Index: gcc/ChangeLog.mm =================================================================== --- gcc/ChangeLog.mm (.../trunk) (revision 0) +++ gcc/ChangeLog.mm (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,356 @@ +2011-11-02 Aldy Hernandez + + * Merge from trunk at revision 180790. + +2011-11-02 Andrew MacLeod + + * builtins.c (fold_builtin_atomic_always_lock_free): Add object param + and check alignment if present. + (expand_builtin_atomic_always_lock_free): Expect 2nd argument. + (fold_builtin_atomic_is_lock_free): Expect 2nd argument. + (expand_builtin_atomic_is_lock_free): Expect 2nd argument. + (fold_builtin_1): Remove LOCK_FREE builtins. + (fold_builtin_2): Add LOCK_FREE builtins. + * sync-builtins.def (BUILT_IN_ATOMIC_{IS,ALWAYS}_LOCK_FREE): Add param. + * builtin-types.def (BT_FN_BOOL_SIZE): Remove. + (BT_FN_BOOL_SIZE_CONST_VPTR): Add. + +2011-11-02 Andrew MacLeod + + * common.opt (finline-atomics): New. Flag to disable atomic inlining. + * builtins.c (expand_builtin_atomic_exchange, + expand_builtin_atomic_compare_exchange, expand_builtin_atomic_load, + expand_builtin_atomic_store, expand_builtin_atomic_fetch_op, + fold_builtin_atomic_is_lock_free, expand_builtin_atomic_is_lock_free): + Don't attempt instruction expansion if inlining atomics is disabled. + +2011-10-31 Richard Henderson + + * optabs.c (expand_atomic_store): Use create_fixed_operand for + atomic_store optab. Don't try to fall back to sync_lock_release. + +2011-10-31 Richard Henderson + + * omp-low.c (expand_omp_atomic_fetch_op): Don't test individual + fetch_op optabs, only test can_compare_and_swap_p. Use __atomic + builtins instead of __sync builtins. + * optabs.h (get_atomic_op_for_code): Remove decl. + (struct atomic_op_functions): Move to... + * optabs.c: ... here. + (get_atomic_op_for_code): Make static. + +2011-10-27 Richard Henderson + + * config/i386/i386.md (UNSPECV_CMPXCHG): Split into ... + (UNSPECV_CMPXCHG_1, UNSPECV_CMPXCHG_2, + UNSPECV_CMPXCHG_3, UNSPECV_CMPXCHG_4): New. + * config/i386/sync.md (mem_thread_fence): Rename from memory_barrier. + Handle the added memory model parameter. + (mfence_nosse): Rename from memory_barrier_nosse. + (sync_compare_and_swap): Split into ... + (atomic_compare_and_swap): this and ... + (atomic_compare_and_swap): this. Handle the new parameters. + (atomic_compare_and_swap_single): Rename from + sync_compare_and_swap; rewrite to use split unspecs. + (atomic_compare_and_swap_double): Rename from + sync_double_compare_and_swap; rewrite to use split unspecs. + (*atomic_compare_and_swap_doubledi_pic): Rename from + sync_double_compare_and_swapdi_pic; rewrite to use split unspecs. + (atomic_fetch_add): Rename from sync_old_add; add memory + model parameter. + (*atomic_fetch_add_cmp): Similarly. + (atomic_add, atomic): Similarly. + (atomic_sub): Similarly. Use x86_maybe_negate_const_int. + (sync_lock_test_and_set): Merge with ... + (atomic_exchange): ... this. + + * optabs.c (get_atomic_op_for_code): Split out from ... + (maybe_emit_op): ... here. + * optabs.h (struct atomic_op_functions): Move from optabs.c and + rename from struct op_functions. + (get_atomic_op_for_code): Declare. + * omp-low.c (expand_omp_atomic_fetch_op): Use get_atomic_op_for_code + and test both atomic and sync optabs. + + * genopinit.c (optabs): Add atomic_add, atomic_sub, atomic_and, + atomic_nand, atomic_xor, atomic_or. + + * optabs.c (expand_val_compare_and_swap_1): Remove. + (expand_val_compare_and_swap, expand_bool_compare_and_swap): Remove. + (expand_atomic_compare_and_swap): Rename from + expand_atomic_compare_exchange. Rewrite to return both success and + oldval return values; expand via both atomic and sync optabs. + (expand_compare_and_swap_loop): Use expand_atomic_compare_and_swap. + (expand_atomic_load): Likewise. + * builtins.c (expand_builtin_compare_and_swap): Likewise. + (expand_builtin_atomic_compare_exchange): Likewise. + * expr.h, optabs.h: Update. + + * optabs.c (can_compare_and_swap_p): New. + (expand_atomic_exchange, expand_atomic_fetch_op): Use it. + * builtins.c (fold_builtin_atomic_always_lock_free): Likewise. + * omp-low.c (expand_omp_atomic_pipeline): Likewise. + * optabs.h: Update. + + * optabs.c (maybe_gen_insn): Handle 8 operands. + + * builtins.c (expand_builtin_mem_thread_fence): Fixup thinko in + mem_thread_fence case. + +2011-10-26 Andrew MacLeod + + * builtins.c (expand_builtin_atomic_fetch_op): External calls for + 'op_fetch' builtins need to instead call 'fetch_op' externals and issue + correction code. + (expand_builtin): Provide proper builtin name for external call and + ignored flag to expand_builtin_atomic_fetch_op. + +2011-10-25 Andrew MacLeod + + * c-typeck.c (build_function_call_vec): Don't reprocess __atomic + parameters. + * doc/extend.texi: Document generic __atomic functions. + * sync-builtin.def (BUILT_IN_ATOMIC_EXCHANGE_N, BUILT_IN_ATOMIC_LOAD_N, + BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N, BUILT_IN_ATOMIC_STORE_N): Add "_n" + to the functions real name. + (BUILT_IN_ATOMIC_EXCHANGE, BUILT_IN_ATOMIC_LOAD, + BUILT_IN_ATOMIC_COMPARE_EXCHANGE, BUILT_IN_ATOMIC_STORE): New. Add + generic atomic builtin functions. + * builtin-types.def (BT_FN_VOID_SIZE_VPTR_PTR_INT, + BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, + BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT): New builtin types. + +2011-10-20 Aldy Hernandez + + * optabs.c (expand_atomic_load): Handle a NULL target. + +2011-10-20 Andrew MacLeod + + * optabs.c (add_op): Fix formatting from rename. + (expand_atomic_fetch_op): Fix formatting from rename. + * builtins.c (get_builtin_sync_mem): Reverse renamed get_builtin_atomic. + (expand_builtin_sync_operation): Fix rename issues. + (expand_builtin_compare_and_swap): Fix rename issues. + (expand_builtin_sync_lock_test_and_set): Fix rename issues. + (expand_builtin_sync_lock_release): Fix rename issues. + (expand_builtin_atomic_exchange): Fix rename issues. + (expand_builtin_atomic_load): Fix rename issues. + (expand_builtin_atomic_store): Fix rename issues. + (expand_builtin_atomic_fetch_op): Fix rename issues. + (expand_builtin): Fix formatting from rename. + +2011-10-20 Andrew MacLeod + + * optabs.h (direct_optab_index): Replace DOI_atomic_compare_exchange + with DOI_atomic_compare_and_swap. + (direct_op): Add DOI_atomic_compare_and_swap. + * genopinit.c: Set atomic_compare_and_swap_optab. + * expr.h (expand_atomic_compare_exchange): Add parameter. + * builtins.c (builtin_atomic_compare_exchange): Add weak parameter + and verify it is a compile time constant. + * optabs.c (expand_atomic_compare_exchange): Use atomic_compare_and_swap + pattern if present, otherwise use __sync_val_compare_and_swap. + * builtin-types.def (BT_FN_BOOL_VPTR_PTR_I{1,2,4,8,16}_BOOL_INT_INT): + Add the bool parameter. + * sync-builtins.def (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_*): Use new + prototype. + +2011-10-17 Andrew MacLeod + + * cppbuiltin.c: Rename __sync_mem to __atomic. + * optabs.c: Rename __sync_mem to __atomic. + * optabs.h: Rename __sync_mem to __atomic. + * genopinit.c: Rename __sync_mem to __atomic. + * builtins.c: Add __atomic as builtin prefix, rename all __sync_mem. + * sync-builtins.def: Rename __sync_mem to __atomic. + * expr.h: Rename __sync_mem to __atomic. + * coretypes.h: Rename __sync_mem to __atomic. + * doc/extend.texi: Rename __sync_mem to __atomic. + * config/i387/sync.md: Rename __sync_mem to __atomic. + +2011-10-13 Andrew MacLeod + + * optabs.h (DOI_sync_mem_always_lock_free): New. + (DOI_sync_mem_is_lock_free): New. + (sync_mem_always_lock_free_optab, sync_mem_is_lock_free_optab): New. + * builtins.c (fold_builtin_sync_mem_always_lock_free): New. + (expand_builtin_sync_mem_always_lock_free): New. + (fold_builtin_sync_mem_is_lock_free): New. + (expand_builtin_sync_mem_is_lock_free): New. + (expand_builtin): Handle BUILT_IN_SYNC_MEM_{is,always}_LOCK_FREE. + (fold_builtin_1): Handle BUILT_IN_SYNC_MEM_{is,always}_LOCK_FREE. + * sync-builtins.def: Add BUILT_IN_SYNC_MEM_{is,always}_LOCK_FREE. + * builtin-types.def: Add BT_FN_BOOL_SIZE type. + * doc/extend.texi: Add documentation. + +2011-10-12 Aldy Hernandez + + * Merge from trunk at revision 179855. + +2011-10-04 Andrew MacLeod + + * optabs.c (expand_sync_mem_load): Don't expand into a default load if + the type is larger than a word. Try a compare_and_swap with 0. + (expand_sync_mem_store): Return const0_rtx if a store is generated. If + type is larger than a word try an exchange, then fail. + * builtins.c (expand_builtin_sync_mem_store): Return a value. + (expand_builtin): If no store generated, leave a function call. + * expr.h (expand_sync_mem_store): Prototype returns value. + +2011-09-16 Andrew MacLeod + + * expr.h: Remove prototypes. + * sync-builtins.def (BUILT_IN_SYNC_MEM_FLAG_TEST_AND_SET, + BUILT_IN_SYNC_MEM_FLAG_CLEAR): Remove. + (BUILT_IN_SYNC_MEM_NAND_FETCH): New builtin. + (BUILT_IN_SYNC_MEM_FETCH_NAND): New builtin. + * optabs.h (enum direct_optab_index): Remove DOI_sync_mem_flag_*. + Add nand patterns as well as _sync_mem patterns with no result. + (direct_op): Add new patterns to table. + * genopinit (optabs[]): Add nand handlers. + * optabs.c (expand_sync_lock_test_and_set): Remove. + (expand_sync_mem_exchange): Incorporate sync_lock_test_and_set here. + (expand_sync_mem_store): If storing const0_rtx, try using + sync_lock_release. + (expand_sync_operation, expand_sync_fetch_operation): Remove. + (struct op_functions): New. Table of different opcode expanders. + (add_op, sub_op, xor_op, and_op, nand_op, or_op): New. Objects + initialized to expander data for each operation. + (maybe_emit_op): New. Try to emit a specific op variation. + (expand_sync_mem_fetch_op): Use maybe_emit_op to try to find a valid + expansion using expanders in the op_function table. + * builtins.c (expand_builtin_sync_lock_test_and_set): Expand into + sync_mem_exchange instead. + (expand_builtin_sync_lock_release): Expand into sync_mem_store of 0. + (expand_builtin_sync_mem_flag_test_and_set): Remove. + (expand_builtin_sync_mem_flag_clear): Remove. + (expand_builtin_sync_operation): Remove ignore param. + (expand_builtin_sync_operation): Always call expand_sync_mem_fetch_op + instead of the old expanders. + (expand_builtin): Remove cases for __SYNC_MEM_FLAG_*. Remove param + 'ignore'. Expand the new NAND builtins. + * doc/extend.texi: Update documentation to match. + +2011-09-08 Andrew MacLeod + + * builtins.c (get_memmodel): If the memory model is not a compile time + constant, default to SEQ_CST mode. + * doc/extend.texi: Document behaviour. + +2011-09-08 Aldy Hernandez + + * Merge from trunk at revision 178608. + +2011-08-23 Andrew MacLeod + + * builtin-types.def (BT_CONST_VOLATILE_PTR): New primitive type. + (BT_FN_I{1,2,4,8,16}_VPTR_INT): Change prototype to be const. + * sync-builtins.def (BUILT_IN_SYNC_MEM_LOAD_*): Change to be const. + +2011-08-13 Andrew MacLeod + + * sync-builtins.def (BUILT_IN_SYNC_MEM_{ADD,SUB,AND,XOR,OR}_FETCH): New. + * optabs.h (enum direct_optab_index): Add defines and access macros + for DOI_sync_mem_{add,sub,and,xor,or}_fetch. + * genopinit.c (optabs): Set handler for + sync_mem_{add,sub,and,xor,or}_fetch. + * expr.h (expand_sync_mem_fetch_op): Add parameter to prototype. + * optabs.c (expand_sync_mem_fetch_op): Add bool parameter to handle + fetch_ops which return the result of the calculation. + * builtins.c (expand_builtin_sync_mem_fetch_op): Add bool parameter + to handle fetch_ops which return the result of the calculation. + (expand_builtin): Add new _SYNC_MEM cases and add bool parameter to + calls to expand_builtin_sync_mem_fetch_op. + * doc/extend.texi: Document __sync_mem_add_fetch, __sync_mem_sub_fetch, + __sync_mem_and_fetch, __sync_mem_xor_fetch, and __sync_mem_or_fetch. + Fix some formatting. + +2011-07-27 Andrew Macleod + + * expr.h (expand_sync_mem_exchange): Change parameter order. + (expand_sync_mem_*): New prototypes. + (expand_builtin_sync_synchronize): Remove prototype. + (expand_builtin_mem_thread_fence): Add prototype. + * optabs.h (DOI_sync_mem_*): Add new optable enums. + (sync_mem_*_optab): Add new #defines for table entries. + * genopinit.c (const optabs[]): Add direct optab handlers. + * optabs.c (expand_sync_mem_exchange): Change parameter order, and use + builtin_mem_thread_fence. + (expand_sync_mem_compare_exchange, expand_sync_mem_load, + expand_sync_mem_store, expand_sync_mem_fetch_op): New. Expand + __sync_mem functions which handle multiple integral types. + * builtins.c (expand_expr_force_mode): New. Factor out common code for + ensuring an integer argument is in the proper mode. + (expand_builtin_sync_operation, expand_builtin_compare_and_swap, + expand_builtin_sync_lock_test_and_set): Use maybe_convert_modes. + (expand_builtin_sync_lock_release): Relocate higher in the file. + (get_memmodel): Don't assume the memmodel is the 3rd argument. + (expand_builtin_sync_mem_exchange): Change error check and use + maybe_convert_modes. + (expand_builtin_sync_mem_compare_exchange): New. + (expand_builtin_sync_mem_load, expand_builtin_sync_mem_store): New. + (expand_builtin_sync_mem_fetch_op): New. + (expand_builtin_sync_mem_flag_test_and_set): New. + (expand_builtin_sync_mem_flag_clear): New. + (expand_builtin_mem_thread_fence): New. + (expand_builtin_sync_mem_thread_fence): New. + (expand_builtin_mem_signal_fence): New. + (expand_builtin_sync_mem_signal_fence): New. + (expand_builtin): Handle BUILT_IN_SYNC_MEM_* types. + * builtin-types.def (BT_FN_I{1,2,4,8,16}_VPTR_INT): New builtin type. + (BT_FN_VOID_VPTR_INT, BT_FN_BOOL_VPTR_INT): New builtin types. + (BT_FN_VOID_VPTR_I{1,2,4,8,16}_INT: New builtin type. + (BT_FN_BOOL_VPTR_PTR_I{1,2,4,8,16}_INT_INT): New builtin type. + * sync-builtins.def (BUILT_IN_SYNC_MEM_*): New sync builtins. + +2011-07-27 Andrew Macleod + + * doc/extend.texi (__sync_mem_*) : Document all the atomic builtin + functions which deal with memory models. + +2011-06-23 Andrew Macleod + + * doc/extend.texi (__sync_mem_load): Document. + * optabs.c (expand_sync_mem_load): New. + * optabs.h (enum direct_optab_index): Add DOI_sync_mem_load. + (sync_mem_load_optab): Define. + * genopinit.c: Add entry for sync_mem_load. + * builtins.c (expand_builtin_sync_mem_load): New. + (expand_builtin): Handle BUILT_IN_SYNC_MEM_LOAD_* + * sync-bultins.def: Add entries for BUILT_IN_SYNC_MEM_LOAD_*. + * builtin-types.def (BT_FN_I{1,2,4,8,16}_VPTR_INT): New. + * expr.h (expand_sync_mem_load): Declare. + * config/i386/sync.md (sync_mem_load): New pattern. + +2011-06-21 Andrew Macleod + Aldy Hernandez + + * doc/extend.texi (__sync_mem_exchange): Document. + * cppbuiltin.c (define__GNUC__): Define __SYNC_MEM*. + * optabs.c (expand_sync_mem_exchange): New. + * optabs.h (enum direct_optab_index): Add DOI_sync_mem_exchange entry. + (sync_mem_exchange_optab): Define. + * genopinit.c: Add entry for sync_mem_exchange. + * builtins.c (get_memmodel): New. + (expand_builtin_sync_mem_exchange): New. + (expand_builtin_sync_synchronize): Remove static. + (expand_builtin): Add cases for BUILT_IN_SYNC_MEM_EXCHANGE_*. + * sync-builtins.def: Add entries for BUILT_IN_SYNC_MEM_EXCHANGE_*. + * builtin-types.def (BT_FN_I{1,2,4,8,16}_VPTR_I{1,2,4,8,16}_INT): New. + * expr.h (expand_sync_mem_exchange): Declare. + (expand_builtin_sync_synchronize): Declare. + * coretypes.h (enum memmodel): New. + * Makefile.in (cppbuiltin.o) Add missing dependency on $(TREE_H) + * config/i386/sync.md (sync_mem_exchange): New pattern. + +2011-03-14 Aldy Hernandez + + * params.h (ALLOW_LOAD_DATA_RACES): New. + (ALLOW_STORE_DATA_RACES): New. + (ALLOW_PACKED_LOAD_DATA_RACES): New. + (ALLOW_PACKED_STORE_DATA_RACES): New. + * params.def (PARAM_ALLOW_LOAD_DATA_RACES): New. + (PARAM_ALLOW_STORE_DATA_RACES): New. + (PARAM_ALLOW_PACKED_LOAD_DATA_RACES): New. + (PARAM_ALLOW_PACKED_STORE_DATA_RACES): New. + * doc/invoke.texi (Optimize Options): Document above parameters. Index: gcc/c-typeck.c =================================================================== --- gcc/c-typeck.c (.../trunk) (revision 180790) +++ gcc/c-typeck.c (.../branches/cxx-mem-model) (revision 180811) @@ -2717,6 +2717,10 @@ build_function_call_vec (location_t loc, name = DECL_NAME (function); fundecl = function; + /* Atomic functions have type checking/casting already done. They are + often rewritten and don't match the original parameter list. */ + if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9)) + origtypes = NULL; } if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) function = function_to_pointer_conversion (loc, function); Index: gcc/coretypes.h =================================================================== --- gcc/coretypes.h (.../trunk) (revision 180790) +++ gcc/coretypes.h (.../branches/cxx-mem-model) (revision 180811) @@ -181,5 +181,18 @@ union _dont_use_tree_here_; #endif +/* Memory model types for the __atomic* builtins. + This must match the order in libstdc++-v3/include/bits/atomic_base.h. */ +enum memmodel +{ + MEMMODEL_RELAXED = 0, + MEMMODEL_CONSUME = 1, + MEMMODEL_ACQUIRE = 2, + MEMMODEL_RELEASE = 3, + MEMMODEL_ACQ_REL = 4, + MEMMODEL_SEQ_CST = 5, + MEMMODEL_LAST = 6 +}; + #endif /* coretypes.h */ Index: gcc/common.opt =================================================================== --- gcc/common.opt (.../trunk) (revision 180790) +++ gcc/common.opt (.../branches/cxx-mem-model) (revision 180811) @@ -1266,6 +1266,10 @@ finline-limit= Common RejectNegative Joined UInteger -finline-limit= Limit the size of inlined functions to +finline-atomics +Common Report Var(flag_inline_atomics) Init(1) Optimization +Inline __atomic operations when a lock free instruction sequence is available. + finstrument-functions Common Report Var(flag_instrument_function_entry_exit) Instrument function entry and exit with profiling calls Index: gcc/Makefile.in =================================================================== --- gcc/Makefile.in (.../trunk) (revision 180790) +++ gcc/Makefile.in (.../branches/cxx-mem-model) (revision 180811) @@ -3976,7 +3976,7 @@ PREPROCESSOR_DEFINES = \ CFLAGS-cppbuiltin.o += $(PREPROCESSOR_DEFINES) -DBASEVER=$(BASEVER_s) cppbuiltin.o: cppbuiltin.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ - cppbuiltin.h Makefile + $(TREE_H) cppbuiltin.h Makefile CFLAGS-cppdefault.o += $(PREPROCESSOR_DEFINES) cppdefault.o: cppdefault.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ Index: gcc/config/sparc/sparc.md =================================================================== --- gcc/config/sparc/sparc.md (.../trunk) (revision 180790) +++ gcc/config/sparc/sparc.md (.../branches/cxx-mem-model) (revision 180811) @@ -2041,8 +2041,8 @@ }) (define_insn "*movsf_insn" - [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,f, *r,*r,*r,*r, f, f,*r, m, m") - (match_operand:SF 1 "input_operand" "G,C,f,*rR, Q, S, f,*r, m, m, f,*rG"))] + [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,f, *r,*r,*r,*r, f,f,*r,m, m") + (match_operand:SF 1 "input_operand" "G,C,f,*rR, Q, S, f,*r,m, m,f,*rG"))] "(register_operand (operands[0], SFmode) || register_or_zero_or_all_ones_operand (operands[1], SFmode))" { @@ -2138,8 +2138,8 @@ }) (define_insn "*movdf_insn_sp32" - [(set (match_operand:DF 0 "nonimmediate_operand" "=b,b,e,e,*r, f, e,T,W,U,T, f, *r, o,o") - (match_operand:DF 1 "input_operand" "G,C,e,e, f,*r,W#F,G,e,T,U,o#F,*roGF,*rG,f"))] + [(set (match_operand:DF 0 "nonimmediate_operand" "=b,b,e,e,*r, f, e,T,W,U,T, f, *r, o,o") + (match_operand:DF 1 "input_operand" "G,C,e,e, f,*r,W#F,G,e,T,U,o#F,*roF,*rG,f"))] "! TARGET_ARCH64 && (register_operand (operands[0], DFmode) || register_or_zero_or_all_ones_operand (operands[1], DFmode))" @@ -2166,7 +2166,7 @@ (define_insn "*movdf_insn_sp64" [(set (match_operand:DF 0 "nonimmediate_operand" "=b,b,e,*r, e, e,W, *r,*r, m,*r") - (match_operand:DF 1 "input_operand" "G,C,e, e,*r,W#F,e,*rG, m,*rG, F"))] + (match_operand:DF 1 "input_operand" "G,C,e, e,*r,W#F,e,*rG, m,*rG, F"))] "TARGET_ARCH64 && (register_operand (operands[0], DFmode) || register_or_zero_or_all_ones_operand (operands[1], DFmode))" @@ -2191,9 +2191,8 @@ (define_split [(set (match_operand:DF 0 "register_operand" "") (match_operand:DF 1 "const_double_operand" ""))] - "TARGET_FPU - && (GET_CODE (operands[0]) == REG - && SPARC_INT_REG_P (REGNO (operands[0]))) + "REG_P (operands[0]) + && SPARC_INT_REG_P (REGNO (operands[0])) && ! const_zero_operand (operands[1], GET_MODE (operands[0])) && reload_completed" [(clobber (const_int 0))] @@ -2378,8 +2377,8 @@ }) (define_insn "*movtf_insn_sp32" - [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,o,U,r") - (match_operand:TF 1 "input_operand" "G,oe,GeUr,o,roG"))] + [(set (match_operand:TF 0 "nonimmediate_operand" "=b, e, o,U, r") + (match_operand:TF 1 "input_operand" " G,oe,GeUr,o,roG"))] "TARGET_FPU && ! TARGET_ARCH64 && (register_operand (operands[0], TFmode) @@ -2392,8 +2391,8 @@ ;; when -mno-fpu. (define_insn "*movtf_insn_sp32_no_fpu" - [(set (match_operand:TF 0 "nonimmediate_operand" "=o,U,o,r,o") - (match_operand:TF 1 "input_operand" "G,o,U,roG,r"))] + [(set (match_operand:TF 0 "nonimmediate_operand" "=o,U,o, r,o") + (match_operand:TF 1 "input_operand" " G,o,U,roG,r"))] "! TARGET_FPU && ! TARGET_ARCH64 && (register_operand (operands[0], TFmode) @@ -2402,8 +2401,8 @@ [(set_attr "length" "4")]) (define_insn "*movtf_insn_sp64" - [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,o,r") - (match_operand:TF 1 "input_operand" "G,oe,Ger,roG"))] + [(set (match_operand:TF 0 "nonimmediate_operand" "=b, e, o, r") + (match_operand:TF 1 "input_operand" "G,oe,Ger,roG"))] "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD @@ -2413,8 +2412,8 @@ [(set_attr "length" "2")]) (define_insn "*movtf_insn_sp64_hq" - [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,e,m,o,r") - (match_operand:TF 1 "input_operand" "G,e,m,e,rG,roG"))] + [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,e,m, o, r") + (match_operand:TF 1 "input_operand" "G,e,m,e,rG,roG"))] "TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD @@ -2431,8 +2430,8 @@ (set_attr "length" "2,*,*,*,2,2")]) (define_insn "*movtf_insn_sp64_no_fpu" - [(set (match_operand:TF 0 "nonimmediate_operand" "=r,o") - (match_operand:TF 1 "input_operand" "orG,rG"))] + [(set (match_operand:TF 0 "nonimmediate_operand" "= r, o") + (match_operand:TF 1 "input_operand" "orG,rG"))] "! TARGET_FPU && TARGET_ARCH64 && (register_operand (operands[0], TFmode) Index: gcc/config/i386/i386.md =================================================================== --- gcc/config/i386/i386.md (.../trunk) (revision 180790) +++ gcc/config/i386/i386.md (.../branches/cxx-mem-model) (revision 180811) @@ -262,7 +262,10 @@ UNSPECV_ALIGN UNSPECV_MONITOR UNSPECV_MWAIT - UNSPECV_CMPXCHG + UNSPECV_CMPXCHG_1 + UNSPECV_CMPXCHG_2 + UNSPECV_CMPXCHG_3 + UNSPECV_CMPXCHG_4 UNSPECV_XCHG UNSPECV_LOCK UNSPECV_PROLOGUE_USE Index: gcc/config/i386/sync.md =================================================================== --- gcc/config/i386/sync.md (.../trunk) (revision 180790) +++ gcc/config/i386/sync.md (.../branches/cxx-mem-model) (revision 180811) @@ -18,31 +18,27 @@ ;; along with GCC; see the file COPYING3. If not see ;; . -(define_mode_iterator CASMODE - [QI HI SI (DI "TARGET_64BIT || TARGET_CMPXCHG8B") - (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) -(define_mode_iterator DCASMODE - [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic") - (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) -(define_mode_attr doublemodesuffix [(DI "8") (TI "16")]) -(define_mode_attr DCASHMODE [(DI "SI") (TI "DI")]) - -(define_expand "memory_barrier" - [(set (match_dup 0) - (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE))] +(define_expand "mem_thread_fence" + [(match_operand:SI 0 "const_int_operand" "")] ;; model "" { - operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); - MEM_VOLATILE_P (operands[0]) = 1; - - if (!(TARGET_64BIT || TARGET_SSE2)) + /* Unless this is a SEQ_CST fence, the i386 memory model is strong + enough not to require barriers of any kind. */ + if (INTVAL (operands[0]) != MEMMODEL_SEQ_CST) + DONE; + + if (TARGET_64BIT || TARGET_SSE2) + emit_insn (gen_sse2_mfence ()); + else { - emit_insn (gen_memory_barrier_nosse (operands[0])); - DONE; + rtx mem = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); + MEM_VOLATILE_P (mem) = 1; + emit_insn (gen_mfence_nosse (mem)); } + DONE; }) -(define_insn "memory_barrier_nosse" +(define_insn "mfence_nosse" [(set (match_operand:BLK 0 "" "") (unspec:BLK [(match_dup 0)] UNSPEC_MFENCE)) (clobber (reg:CC FLAGS_REG))] @@ -50,127 +46,152 @@ "lock{%;} or{l}\t{$0, (%%esp)|DWORD PTR [esp], 0}" [(set_attr "memory" "unknown")]) -;; ??? It would be possible to use cmpxchg8b on pentium for DImode -;; changes. It's complicated because the insn uses ecx:ebx as the -;; new value; note that the registers are reversed from the order -;; that they'd be in with (reg:DI 2 ecx). Similarly for TImode -;; data in 64-bit mode. - -(define_expand "sync_compare_and_swap" - [(parallel - [(set (match_operand:CASMODE 0 "register_operand" "") - (match_operand:CASMODE 1 "memory_operand" "")) - (set (match_dup 1) - (unspec_volatile:CASMODE - [(match_dup 1) - (match_operand:CASMODE 2 "register_operand" "") - (match_operand:CASMODE 3 "register_operand" "")] - UNSPECV_CMPXCHG)) - (set (reg:CCZ FLAGS_REG) - (compare:CCZ - (unspec_volatile:CASMODE - [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG) - (match_dup 2)))])] +(define_expand "atomic_compare_and_swap" + [(match_operand:QI 0 "register_operand" "") ;; bool success output + (match_operand:SWI124 1 "register_operand" "") ;; oldval output + (match_operand:SWI124 2 "memory_operand" "") ;; memory + (match_operand:SWI124 3 "register_operand" "") ;; expected input + (match_operand:SWI124 4 "register_operand" "") ;; newval input + (match_operand:SI 5 "const_int_operand" "") ;; is_weak + (match_operand:SI 6 "const_int_operand" "") ;; success model + (match_operand:SI 7 "const_int_operand" "")] ;; failure model + "TARGET_CMPXCHG" +{ + emit_insn (gen_atomic_compare_and_swap_single + (operands[1], operands[2], operands[3], operands[4])); + ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG), + const0_rtx); + DONE; +}) + +(define_mode_iterator CASMODE + [(DI "TARGET_64BIT || TARGET_CMPXCHG8B") + (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) +(define_mode_iterator DCASMODE + [(DI "!TARGET_64BIT && TARGET_CMPXCHG8B && !flag_pic") + (TI "TARGET_64BIT && TARGET_CMPXCHG16B")]) +(define_mode_attr doublemodesuffix [(DI "8") (TI "16")]) +(define_mode_attr DCASHMODE [(DI "SI") (TI "DI")]) + +(define_expand "atomic_compare_and_swap" + [(match_operand:QI 0 "register_operand" "") ;; bool success output + (match_operand:CASMODE 1 "register_operand" "") ;; oldval output + (match_operand:CASMODE 2 "memory_operand" "") ;; memory + (match_operand:CASMODE 3 "register_operand" "") ;; expected input + (match_operand:CASMODE 4 "register_operand" "") ;; newval input + (match_operand:SI 5 "const_int_operand" "") ;; is_weak + (match_operand:SI 6 "const_int_operand" "") ;; success model + (match_operand:SI 7 "const_int_operand" "")] ;; failure model "TARGET_CMPXCHG" { - if ((mode == DImode && !TARGET_64BIT) || mode == TImode) + if (mode == DImode && TARGET_64BIT) + { + emit_insn (gen_atomic_compare_and_swap_singledi + (operands[1], operands[2], operands[3], operands[4])); + } + else { - enum machine_mode hmode = mode == DImode ? SImode : DImode; - rtx low = simplify_gen_subreg (hmode, operands[3], mode, 0); - rtx high = simplify_gen_subreg (hmode, operands[3], mode, - GET_MODE_SIZE (hmode)); - low = force_reg (hmode, low); - high = force_reg (hmode, high); - if (mode == DImode) - { - if (flag_pic && !cmpxchg8b_pic_memory_operand (operands[1], DImode)) - operands[1] = replace_equiv_address (operands[1], - force_reg (Pmode, - XEXP (operands[1], - 0))); - emit_insn (gen_sync_double_compare_and_swapdi - (operands[0], operands[1], operands[2], low, high)); - } - else if (mode == TImode) - emit_insn (gen_sync_double_compare_and_swapti - (operands[0], operands[1], operands[2], low, high)); - else - gcc_unreachable (); - DONE; + enum machine_mode hmode = mode; + rtx lo_o, lo_e, lo_n, hi_o, hi_e, hi_n, mem; + + lo_o = operands[1]; + mem = operands[2]; + lo_e = operands[3]; + lo_n = operands[4]; + hi_o = gen_highpart (hmode, lo_o); + hi_e = gen_highpart (hmode, lo_e); + hi_n = gen_highpart (hmode, lo_n); + lo_o = gen_lowpart (hmode, lo_o); + lo_e = gen_lowpart (hmode, lo_e); + lo_n = gen_lowpart (hmode, lo_n); + + if (mode == DImode + && !TARGET_64BIT + && flag_pic + && !cmpxchg8b_pic_memory_operand (mem, DImode)) + mem = replace_equiv_address (mem, force_reg (Pmode, XEXP (mem, 0))); + + emit_insn (gen_atomic_compare_and_swap_double + (lo_o, hi_o, mem, lo_e, hi_e, lo_n, hi_n)); } + ix86_expand_setcc (operands[0], EQ, gen_rtx_REG (CCZmode, FLAGS_REG), + const0_rtx); + DONE; }) -(define_insn "*sync_compare_and_swap" +(define_insn "atomic_compare_and_swap_single" [(set (match_operand:SWI 0 "register_operand" "=a") - (match_operand:SWI 1 "memory_operand" "+m")) - (set (match_dup 1) (unspec_volatile:SWI - [(match_dup 1) - (match_operand:SWI 2 "register_operand" "a") + [(match_operand:SWI 1 "memory_operand" "+m") + (match_operand:SWI 2 "register_operand" "0") (match_operand:SWI 3 "register_operand" "")] - UNSPECV_CMPXCHG)) + UNSPECV_CMPXCHG_1)) + (set (match_dup 1) + (unspec_volatile:SWI [(const_int 0)] UNSPECV_CMPXCHG_2)) (set (reg:CCZ FLAGS_REG) - (compare:CCZ - (unspec_volatile:SWI - [(match_dup 1) (match_dup 2) (match_dup 3)] UNSPECV_CMPXCHG) - (match_dup 2)))] + (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG_3))] "TARGET_CMPXCHG" "lock{%;} cmpxchg{}\t{%3, %1|%1, %3}") -(define_insn "sync_double_compare_and_swap" - [(set (match_operand:DCASMODE 0 "register_operand" "=A") - (match_operand:DCASMODE 1 "memory_operand" "+m")) - (set (match_dup 1) - (unspec_volatile:DCASMODE - [(match_dup 1) - (match_operand:DCASMODE 2 "register_operand" "A") - (match_operand: 3 "register_operand" "b") - (match_operand: 4 "register_operand" "c")] - UNSPECV_CMPXCHG)) +;; For double-word compare and swap, we are obliged to play tricks with +;; the input newval (op5:op6) because the Intel register numbering does +;; not match the gcc register numbering, so the pair must be CX:BX. +;; That said, in order to take advantage of possible lower-subreg opts, +;; treat all of the integral operands in the same way. +(define_insn "atomic_compare_and_swap_double" + [(set (match_operand: 0 "register_operand" "=a") + (unspec_volatile: + [(match_operand:DCASMODE 2 "memory_operand" "+m") + (match_operand: 3 "register_operand" "0") + (match_operand: 4 "register_operand" "1") + (match_operand: 5 "register_operand" "b") + (match_operand: 6 "register_operand" "c")] + UNSPECV_CMPXCHG_1)) + (set (match_operand: 1 "register_operand" "=d") + (unspec_volatile: [(const_int 0)] UNSPECV_CMPXCHG_2)) + (set (match_dup 2) + (unspec_volatile:DCASMODE [(const_int 0)] UNSPECV_CMPXCHG_3)) (set (reg:CCZ FLAGS_REG) - (compare:CCZ - (unspec_volatile:DCASMODE - [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] - UNSPECV_CMPXCHG) - (match_dup 2)))] + (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG_4))] "" - "lock{%;} cmpxchgb\t%1") + "lock{%;} cmpxchgb\t%2") -;; Theoretically we'd like to use constraint "r" (any reg) for operand -;; 3, but that includes ecx. If operand 3 and 4 are the same (like when -;; the input is -1LL) GCC might chose to allocate operand 3 to ecx, like -;; operand 4. This breaks, as the xchg will move the PIC register contents -;; to %ecx then --> boom. Operands 3 and 4 really need to be different -;; registers, which in this case means operand 3 must not be ecx. -;; Instead of playing tricks with fake early clobbers or the like we -;; just enumerate all regs possible here, which (as this is !TARGET_64BIT) +;; Theoretically we'd like to use constraint "r" (any reg) for op5, +;; but that includes ecx. If op5 and op6 are the same (like when +;; the input is -1LL) GCC might chose to allocate op5 to ecx, like +;; op6. This breaks, as the xchg will move the PIC register contents +;; to %ecx then --> boom. Operands 5 and 6 really need to be different +;; registers, which in this case means op5 must not be ecx. Instead +;; of playing tricks with fake early clobbers or the like we just +;; enumerate all regs possible here, which (as this is !TARGET_64BIT) ;; are just esi and edi. -(define_insn "*sync_double_compare_and_swapdi_pic" - [(set (match_operand:DI 0 "register_operand" "=A") - (match_operand:DI 1 "cmpxchg8b_pic_memory_operand" "+m")) - (set (match_dup 1) - (unspec_volatile:DI - [(match_dup 1) - (match_operand:DI 2 "register_operand" "A") - (match_operand:SI 3 "register_operand" "SD") - (match_operand:SI 4 "register_operand" "c")] - UNSPECV_CMPXCHG)) +(define_insn "*atomic_compare_and_swap_doubledi_pic" + [(set (match_operand:SI 0 "register_operand" "=a") + (unspec_volatile:SI + [(match_operand:DI 2 "cmpxchg8b_pic_memory_operand" "+m") + (match_operand:SI 3 "register_operand" "0") + (match_operand:SI 4 "register_operand" "1") + (match_operand:SI 5 "register_operand" "SD") + (match_operand:SI 6 "register_operand" "c")] + UNSPECV_CMPXCHG_1)) + (set (match_operand:SI 1 "register_operand" "=d") + (unspec_volatile:SI [(const_int 0)] UNSPECV_CMPXCHG_2)) + (set (match_dup 2) + (unspec_volatile:DI [(const_int 0)] UNSPECV_CMPXCHG_3)) (set (reg:CCZ FLAGS_REG) - (compare:CCZ - (unspec_volatile:DI - [(match_dup 1) (match_dup 2) (match_dup 3) (match_dup 4)] - UNSPECV_CMPXCHG) - (match_dup 2)))] + (unspec_volatile:CCZ [(const_int 0)] UNSPECV_CMPXCHG_4))] "!TARGET_64BIT && TARGET_CMPXCHG8B && flag_pic" - "xchg{l}\t%%ebx, %3\;lock{%;} cmpxchg8b\t%1\;xchg{l}\t%%ebx, %3") + "xchg{l}\t%%ebx, %5\;lock{%;} cmpxchg8b\t%2\;xchg{l}\t%%ebx, %5") ;; For operand 2 nonmemory_operand predicate is used instead of ;; register_operand to allow combiner to better optimize atomic ;; additions of constants. -(define_insn "sync_old_add" +(define_insn "atomic_fetch_add" [(set (match_operand:SWI 0 "register_operand" "=") (unspec_volatile:SWI - [(match_operand:SWI 1 "memory_operand" "+m")] UNSPECV_XCHG)) + [(match_operand:SWI 1 "memory_operand" "+m") + (match_operand:SI 3 "const_int_operand" "")] ;; model + UNSPECV_XCHG)) (set (match_dup 1) (plus:SWI (match_dup 1) (match_operand:SWI 2 "nonmemory_operand" "0"))) @@ -186,7 +207,9 @@ (match_operand:SWI 2 "const_int_operand" "")) (parallel [(set (match_dup 0) (unspec_volatile:SWI - [(match_operand:SWI 1 "memory_operand" "")] UNSPECV_XCHG)) + [(match_operand:SWI 1 "memory_operand" "") + (match_operand:SI 4 "const_int_operand" "")] + UNSPECV_XCHG)) (set (match_dup 1) (plus:SWI (match_dup 1) (match_dup 0))) @@ -199,17 +222,19 @@ == -(unsigned HOST_WIDE_INT) INTVAL (operands[3]) && !reg_overlap_mentioned_p (operands[0], operands[1])" [(parallel [(set (reg:CCZ FLAGS_REG) - (compare:CCZ (unspec_volatile:SWI [(match_dup 1)] - UNSPECV_XCHG) - (match_dup 3))) + (compare:CCZ + (unspec_volatile:SWI [(match_dup 1) (match_dup 4)] + UNSPECV_XCHG) + (match_dup 3))) (set (match_dup 1) (plus:SWI (match_dup 1) (match_dup 2)))])]) -(define_insn "*sync_old_add_cmp" +(define_insn "*atomic_fetch_add_cmp" [(set (reg:CCZ FLAGS_REG) (compare:CCZ (unspec_volatile:SWI - [(match_operand:SWI 0 "memory_operand" "+m")] + [(match_operand:SWI 0 "memory_operand" "+m") + (match_operand:SI 3 "const_int_operand" "")] UNSPECV_XCHG) (match_operand:SWI 2 "const_int_operand" "i"))) (set (match_dup 0) @@ -233,20 +258,24 @@ }) ;; Recall that xchg implicitly sets LOCK#, so adding it again wastes space. -(define_insn "sync_lock_test_and_set" - [(set (match_operand:SWI 0 "register_operand" "=") +;; In addition, it is always a full barrier, so we can ignore the memory model. +(define_insn "atomic_exchange" + [(set (match_operand:SWI 0 "register_operand" "=") ;; output (unspec_volatile:SWI - [(match_operand:SWI 1 "memory_operand" "+m")] UNSPECV_XCHG)) + [(match_operand:SWI 1 "memory_operand" "+m") ;; memory + (match_operand:SI 3 "const_int_operand" "")] ;; model + UNSPECV_XCHG)) (set (match_dup 1) - (match_operand:SWI 2 "register_operand" "0"))] + (match_operand:SWI 2 "register_operand" "0"))] ;; input "" "xchg{}\t{%1, %0|%0, %1}") -(define_insn "sync_add" +(define_insn "atomic_add" [(set (match_operand:SWI 0 "memory_operand" "+m") (unspec_volatile:SWI [(plus:SWI (match_dup 0) - (match_operand:SWI 1 "nonmemory_operand" ""))] + (match_operand:SWI 1 "nonmemory_operand" "")) + (match_operand:SI 2 "const_int_operand" "")] ;; model UNSPECV_LOCK)) (clobber (reg:CC FLAGS_REG))] "" @@ -265,11 +294,12 @@ return "lock{%;} add{}\t{%1, %0|%0, %1}"; }) -(define_insn "sync_sub" +(define_insn "atomic_sub" [(set (match_operand:SWI 0 "memory_operand" "+m") (unspec_volatile:SWI [(minus:SWI (match_dup 0) - (match_operand:SWI 1 "nonmemory_operand" ""))] + (match_operand:SWI 1 "nonmemory_operand" "")) + (match_operand:SI 2 "const_int_operand" "")] ;; model UNSPECV_LOCK)) (clobber (reg:CC FLAGS_REG))] "" @@ -282,14 +312,18 @@ return "lock{%;} inc{}\t%0"; } + if (x86_maybe_negate_const_int (&operands[1], mode)) + return "lock{%;} add{}\t{%1, %0|%0, %1}"; + return "lock{%;} sub{}\t{%1, %0|%0, %1}"; }) -(define_insn "sync_" +(define_insn "atomic_" [(set (match_operand:SWI 0 "memory_operand" "+m") (unspec_volatile:SWI [(any_logic:SWI (match_dup 0) - (match_operand:SWI 1 "nonmemory_operand" ""))] + (match_operand:SWI 1 "nonmemory_operand" "")) + (match_operand:SI 2 "const_int_operand" "")] ;; model UNSPECV_LOCK)) (clobber (reg:CC FLAGS_REG))] "" Index: gcc/params.def =================================================================== --- gcc/params.def (.../trunk) (revision 180790) +++ gcc/params.def (.../branches/cxx-mem-model) (revision 180811) @@ -921,11 +921,26 @@ DEFPARAM (PARAM_CASE_VALUES_THRESHOLD, 0, 0, 0) /* Data race flags for C++0x memory model compliance. */ +DEFPARAM (PARAM_ALLOW_LOAD_DATA_RACES, + "allow-load-data-races", + "Allow new data races on loads to be introduced", + 1, 0, 1) + DEFPARAM (PARAM_ALLOW_STORE_DATA_RACES, "allow-store-data-races", "Allow new data races on stores to be introduced", 1, 0, 1) +DEFPARAM (PARAM_ALLOW_PACKED_LOAD_DATA_RACES, + "allow-packed-load-data-races", + "Allow new data races on packed data loads to be introduced", + 1, 0, 1) + +DEFPARAM (PARAM_ALLOW_PACKED_STORE_DATA_RACES, + "allow-packed-store-data-races", + "Allow new data races on packed data stores to be introduced", + 1, 0, 1) + /* Reassociation width to be used by tree reassoc optimization. */ DEFPARAM (PARAM_TREE_REASSOC_WIDTH, "tree-reassoc-width", Index: gcc/builtin-types.def =================================================================== --- gcc/builtin-types.def (.../trunk) (revision 180790) +++ gcc/builtin-types.def (.../branches/cxx-mem-model) (revision 180811) @@ -95,6 +95,10 @@ DEF_PRIMITIVE_TYPE (BT_VOLATILE_PTR, build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_VOLATILE))) +DEF_PRIMITIVE_TYPE (BT_CONST_VOLATILE_PTR, + build_pointer_type + (build_qualified_type (void_type_node, + TYPE_QUAL_VOLATILE|TYPE_QUAL_CONST))) DEF_PRIMITIVE_TYPE (BT_PTRMODE, (*lang_hooks.types.type_for_mode)(ptr_mode, 0)) DEF_PRIMITIVE_TYPE (BT_INT_PTR, integer_ptr_type_node) DEF_PRIMITIVE_TYPE (BT_FLOAT_PTR, float_ptr_type_node) @@ -315,6 +319,20 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_LONGPTR_ BT_BOOL, BT_PTR_LONG, BT_PTR_LONG) DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_ULONGLONGPTR_ULONGLONGPTR, BT_BOOL, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +DEF_FUNCTION_TYPE_2 (BT_FN_I1_CONST_VPTR_INT, BT_I1, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I2_CONST_VPTR_INT, BT_I2, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I4_CONST_VPTR_INT, BT_I4, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I8_CONST_VPTR_INT, BT_I8, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I16_CONST_VPTR_INT, BT_I16, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT, BT_VOID, BT_VOLATILE_PTR, BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE, + BT_CONST_VOLATILE_PTR) DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR) @@ -383,6 +401,16 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PT BT_PTR, BT_UINT) DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR, BT_CONST_PTR, BT_INT, BT_SIZE) +DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I2_VPTR_I2_INT, BT_I2, BT_VOLATILE_PTR, BT_I2, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_INT, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_INT, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_INT, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I1_INT, BT_VOID, BT_VOLATILE_PTR, BT_I1, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I2_INT, BT_VOID, BT_VOLATILE_PTR, BT_I2, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I4_INT, BT_VOID, BT_VOLATILE_PTR, BT_I4, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I8_INT, BT_VOID, BT_VOLATILE_PTR, BT_I8, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16_INT, BT_VOID, BT_VOLATILE_PTR, BT_I16, BT_INT) DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR) @@ -402,6 +430,10 @@ DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PT BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR, BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR) +DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE, + BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_INT, BT_SIZE, BT_CONST_STRING, @@ -409,6 +441,9 @@ DEF_FUNCTION_TYPE_5 (BT_FN_INT_STRING_IN DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT) + DEF_FUNCTION_TYPE_6 (BT_FN_INT_STRING_SIZE_INT_SIZE_CONST_STRING_VALIST_ARG, BT_INT, BT_STRING, BT_SIZE, BT_INT, BT_SIZE, @@ -422,6 +457,24 @@ DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PT DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I1_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I1, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I2_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I2, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I4_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I4, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I8_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) + DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, Index: gcc/expr.h =================================================================== --- gcc/expr.h (.../trunk) (revision 180790) +++ gcc/expr.h (.../branches/cxx-mem-model) (revision 180811) @@ -212,11 +212,17 @@ int can_conditionally_move_p (enum machi rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx, enum machine_mode, rtx, rtx, enum machine_mode, int); -rtx expand_val_compare_and_swap (rtx, rtx, rtx, rtx); -rtx expand_bool_compare_and_swap (rtx, rtx, rtx, rtx); rtx expand_sync_operation (rtx, rtx, enum rtx_code); rtx expand_sync_fetch_operation (rtx, rtx, enum rtx_code, bool, rtx); -rtx expand_sync_lock_test_and_set (rtx, rtx, rtx); + +rtx expand_atomic_exchange (rtx, rtx, rtx, enum memmodel); +rtx expand_atomic_load (rtx, rtx, enum memmodel); +rtx expand_atomic_store (rtx, rtx, enum memmodel); +rtx expand_atomic_fetch_op (rtx, rtx, rtx, enum rtx_code, enum memmodel, + bool); +void expand_atomic_thread_fence (enum memmodel); +void expand_atomic_signal_fence (enum memmodel); + /* Functions from expmed.c: */ @@ -248,6 +254,7 @@ extern void expand_builtin_setjmp_receiv extern rtx expand_builtin_saveregs (void); extern void expand_builtin_trap (void); extern rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode); +extern void expand_builtin_mem_thread_fence (enum memmodel); /* Functions from expr.c: */ Index: gcc/fortran/ChangeLog.mm =================================================================== --- gcc/fortran/ChangeLog.mm (.../trunk) (revision 0) +++ gcc/fortran/ChangeLog.mm (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,41 @@ +2011-11-02 Andrew MacLeod + + * types.def (BT_FN_BOOL_SIZE): Remove. + (BT_FN_BOOL_SIZE_CONST_VPTR): Add. + +2011-10-25 Andrew MacLeod + + * types.def (BT_FN_VOID_SIZE_VPTR_PTR_INT, + BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, + BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT): New builtin types. + +2011-10-20 Andrew MacLeod + + * types.def (BT_FN_BOOL_VPTR_PTR_I{1,2,4,8,16}_BOOL_INT_INT): Add a + bool parameter for strong/weak. + +2011-10-13 Andrew MacLeod + + * types.def: Add BT_SIZE and BT_FN_BOOL_SIZE. + +2011-08-23 Andrew MacLeod + + * types.def (BUILT_IN_SYNC_MEM_LOAD_*): Change to be const. + +2011-07-27 Andrew Macleod + + * types.def (BT_FN_VOID_INT): New type. + (BT_FN_I{1,2,4,8,16}_VPTR_INT): New builtin type. + (BT_FN_VOID_VPTR_INT, BT_FN_BOOL_VPTR_INT): New builtin types. + (BT_FN_VOID_VPTR_I{1,2,4,8,16}_INT: New builtin type. + (BT_FN_BOOL_VPTR_PTR_I{1,2,4,8,16}_INT_INT): New builtin type. + +2011-06-23 Andrew Macleod + + * types.def (BT_FN_I{1,2,4,8,16}_VPTR_INT): New. + +2011-06-21 Andrew Macleod + Aldy Hernandez + + * types.def (BT_FN_I{1,2,4,8,16}_VPTR_I{1,2,4,8,16}_INT): New. + Index: gcc/fortran/types.def =================================================================== --- gcc/fortran/types.def (.../trunk) (revision 180790) +++ gcc/fortran/types.def (.../branches/cxx-mem-model) (revision 180811) @@ -57,6 +57,7 @@ DEF_PRIMITIVE_TYPE (BT_UINT, unsigned_ty DEF_PRIMITIVE_TYPE (BT_LONG, long_integer_type_node) DEF_PRIMITIVE_TYPE (BT_ULONGLONG, long_long_unsigned_type_node) DEF_PRIMITIVE_TYPE (BT_WORD, (*lang_hooks.types.type_for_mode) (word_mode, 1)) +DEF_PRIMITIVE_TYPE (BT_SIZE, size_type_node) DEF_PRIMITIVE_TYPE (BT_I1, builtin_type_for_size (BITS_PER_UNIT*1, 1)) DEF_PRIMITIVE_TYPE (BT_I2, builtin_type_for_size (BITS_PER_UNIT*2, 1)) @@ -70,7 +71,10 @@ DEF_PRIMITIVE_TYPE (BT_VOLATILE_PTR, build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_VOLATILE))) - +DEF_PRIMITIVE_TYPE (BT_CONST_VOLATILE_PTR, + build_pointer_type + (build_qualified_type (void_type_node, + TYPE_QUAL_VOLATILE|TYPE_QUAL_CONST))) DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG) DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG) DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR) @@ -85,6 +89,8 @@ DEF_FUNCTION_TYPE_1 (BT_FN_VOID_PTRPTR, DEF_FUNCTION_TYPE_1 (BT_FN_VOID_VPTR, BT_VOID, BT_VOLATILE_PTR) DEF_FUNCTION_TYPE_1 (BT_FN_UINT_UINT, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_1 (BT_FN_PTR_PTR, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_1 (BT_FN_VOID_INT, BT_VOID, BT_INT) + DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR, BT_FN_VOID_PTR) @@ -98,6 +104,21 @@ DEF_FUNCTION_TYPE_2 (BT_FN_I4_VPTR_I4, B DEF_FUNCTION_TYPE_2 (BT_FN_I8_VPTR_I8, BT_I8, BT_VOLATILE_PTR, BT_I8) DEF_FUNCTION_TYPE_2 (BT_FN_I16_VPTR_I16, BT_I16, BT_VOLATILE_PTR, BT_I16) DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTR, BT_VOID, BT_PTR, BT_PTR) +DEF_FUNCTION_TYPE_2 (BT_FN_I1_CONST_VPTR_INT, BT_I1, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I2_CONST_VPTR_INT, BT_I2, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I4_CONST_VPTR_INT, BT_I4, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I8_CONST_VPTR_INT, BT_I8, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_I16_CONST_VPTR_INT, BT_I16, BT_CONST_VOLATILE_PTR, + BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_VOID_VPTR_INT, BT_VOID, BT_VOLATILE_PTR, BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_VPTR_INT, BT_BOOL, BT_VOLATILE_PTR, BT_INT) +DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE, + BT_CONST_VOLATILE_PTR) + DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR) @@ -119,15 +140,31 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_ BT_I16, BT_I16) DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT) +DEF_FUNCTION_TYPE_3 (BT_FN_I1_VPTR_I1_INT, BT_I1, BT_VOLATILE_PTR, BT_I1, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I2_VPTR_I2_INT, BT_I2, BT_VOLATILE_PTR, BT_I2, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I4_VPTR_I4_INT, BT_I4, BT_VOLATILE_PTR, BT_I4, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I8_VPTR_I8_INT, BT_I8, BT_VOLATILE_PTR, BT_I8, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_INT, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I1_INT, BT_VOID, BT_VOLATILE_PTR, BT_I1, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I2_INT, BT_VOID, BT_VOLATILE_PTR, BT_I2, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I4_INT, BT_VOID, BT_VOLATILE_PTR, BT_I4, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I8_INT, BT_VOID, BT_VOLATILE_PTR, BT_I8, BT_INT) +DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16_INT, BT_VOID, BT_VOLATILE_PTR, BT_I16, BT_INT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT) DEF_FUNCTION_TYPE_4 (BT_FN_VOID_PTR_WORD_WORD_PTR, BT_VOID, BT_PTR, BT_WORD, BT_WORD, BT_PTR) +DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_VPTR_PTR_INT, BT_VOID, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_INT) +DEF_FUNCTION_TYPE_4 (BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, BT_VOID, BT_SIZE, + BT_CONST_VOLATILE_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_5 (BT_FN_BOOL_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_PTR_LONG, BT_PTR_LONG) +DEF_FUNCTION_TYPE_5 (BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, BT_VOID, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT) DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_LONG_LONG_LONG_LONG_LONGPTR_LONGPTR, BT_BOOL, BT_LONG, BT_LONG, BT_LONG, BT_LONG, @@ -138,6 +175,23 @@ DEF_FUNCTION_TYPE_6 (BT_FN_VOID_OMPFN_PT DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_BOOL_ULL_ULL_ULL_ULLPTR_ULLPTR, BT_BOOL, BT_BOOL, BT_ULONGLONG, BT_ULONGLONG, BT_ULONGLONG, BT_PTR_ULONGLONG, BT_PTR_ULONGLONG) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I1_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I1, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I2_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I2, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I4_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I4, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I8_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I8, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, + BT_BOOL, BT_VOLATILE_PTR, BT_PTR, BT_I16, BT_BOOL, BT_INT, + BT_INT) +DEF_FUNCTION_TYPE_6 (BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, BT_BOOL, BT_SIZE, + BT_VOLATILE_PTR, BT_PTR, BT_PTR, BT_INT, BT_INT) DEF_FUNCTION_TYPE_7 (BT_FN_VOID_OMPFN_PTR_UINT_LONG_LONG_LONG_LONG, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, Index: gcc/doc/extend.texi =================================================================== --- gcc/doc/extend.texi (.../trunk) (revision 180790) +++ gcc/doc/extend.texi (.../branches/cxx-mem-model) (revision 180811) @@ -6813,6 +6813,211 @@ This builtin is not a full barrier, but This means that all previous memory stores are globally visible, and all previous memory loads have been satisfied, but following memory reads are not prevented from being speculated to before the barrier. + +@section Built-in functions for memory model aware atomic operations. + +The following builtins approximately match the requirements for +C++11 memory model. Many are similar to the ``__sync'' prefixed builtins, but +all also have a memory model parameter. These are all identified by being +prefixed with ``__atomic'', and most are overloaded such that they work +with multiple types. + +GCC will allow any integral scalar or pointer type that is 1, 2, 4, or 8 bytes +in length. 16 bytes integral types are also allowed if __int128_t is supported +by the architecture. + +Target architectures are encouraged to provide their own patterns for each of +these builtins. If no target is provided, the original non-memory model +set of ``__sync'' atomic builtins will be utilized, along with any required +synchronization fences surrounding it in order to achieve the proper behaviour. +Execution in this case is subject to the same restrictions as those builtins. + +If there is no pattern or mechanism to provide a lock free instruction sequence, a call is made to an external routine with the same parameters to be resolved at runtime. + +The four non-arithmetic functions (load, store, exchange, and compare_exchange) all have a generic version as well. This generic version will work on any data type. If the data type size maps to one of the integral sizes which may have lock free support, the generic version will utilize the lock free builtin. Otherwise an external call is left to be resolved at runtime. This external call will be the same format with the addition of a size_t parameter inserted as the first parameter indicating the size of the object being pointed to. All objects must be the same size. + +There are 6 different memory models which can be specified. These map to the +same names in the C++11 standard. Refer there or to the GCC wiki on atomics for +more detailed definitions. These memory models integrate both barriers to +code motion as well as synchronization requirements with other threads. These +are listed in approximately ascending order of strength. + +@table @code +@item __ATOMIC_RELAXED +No barriers or synchronization. +@item __ATOMIC_CONSUME +Data dependency only for both barrier and synchronization with another thread. +@item __ATOMIC_ACQUIRE +Barrier to hoisting of code and synchronizes with release (or stronger) +semantic stores from another thread. +@item __ATOMIC_RELEASE +Barrier to sinking of code and synchronizes with acquire (or stronger) semantic +loads from another thread. +@item __ATOMIC_ACQ_REL +Full barrier in both directions and synchronizes with acquire loads and release +stores in another thread. +@item __ATOMIC_SEQ_CST +Full barrier in both directions and synchronizes with acquire loads and release +stores in all threads. +@end table + +When implementing patterns for these builtins, the memory model parameter can +be ignored as long as the pattern implements the most restrictive +__ATOMIC_SEQ_CST model. Any of the other memory models will execute +correctly with this memory model but they may not execute as efficiently as +they could with a more appropriate implemention of the relaxed requirements. + +Note that the C++11 standard allows for the memory model parameter to be +determined at runtime rather than at compile time. These builtins will map any +runtime value to __ATOMIC_SEQ_CST rather than invoke a runtime library +call or inline a switch statement. This is standard compliant, safe, and the +simplest approach for now. + +@item @var{type} __atomic_load_n (@var{type} *ptr, int memmodel) +@findex __atomic_load_n +This builtin implements an atomic load operation. It returns the contents +of @code{*@var{ptr}}. + +The valid memory model variants are +__ATOMIC_RELAXED, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE, and +__ATOMIC_CONSUME. + +@item void __atomic_load (@var{type} *ptr, @var{type} *ret, int memmodel) +@findex __atomic_load +This is the generic version of an atomic load. It will return the contents +of @code{*@var{ptr}} in @code{*@var{ret}}. + + +@item void __atomic_store_n (@var{type} *ptr, @var{type} val, int memmodel) +@findex __atomic_store_n +This builtin implements an atomic store operation. It writes @code{@var{val}} +into @code{*@var{ptr}}. On targets which are limited, 0 may be the only valid +value. This mimics the behaviour of __sync_lock_release on such hardware. + +The valid memory model variants are +__ATOMIC_RELAXED, __ATOMIC_SEQ_CST, and __ATOMIC_RELEASE. + +@item void __atomic_store (@var{type} *ptr, @var{type} *val, int memmodel) +@findex __atomic_store +This is the generic version of an atomic store. It will store the value of +@code{*@var{val}} into @code{*@var{ptr}}. + + +@item @var{type} __atomic_exchange_n (@var{type} *ptr, @var{type} val, int memmodel) +@findex __atomic_exchange_n +This builtin implements an atomic exchange operation. It writes @var{val} +into @code{*@var{ptr}}, and returns the previous contents of @code{*@var{ptr}}. + +On targets which are limited, a value of 1 may be the only valid value written. +This mimics the behaviour of __sync_lock_test_and_set on such hardware. + +The valid memory model variants are +__ATOMIC_RELAXED, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE, +__ATOMIC_RELEASE, and __ATOMIC_ACQ_REL. + +@item void __atomic_exchange (@var{type} *ptr, @var{type} *val, @var{type} *ret, int memmodel) +@findex __atomic_exchange +This is the generic version of an atomic exchange. It will store the contents +of @code{*@var{val}} into @code{*@var{ptr}}. The original value of +@code{*@var{ptr}} will be copied into @code{*@var{ret}}. + + +@item bool __atomic_compare_exchange_n (@var{type} *ptr, @var{type} *expected, @var{type} desired, bool weak, int success_memmodel, int failure_memmodel) +@findex __atomic_compare_exchange_n +This builtin implements an atomic compare_exchange operation. This compares the +contents of @code{*@var{ptr}} with the contents of @code{*@var{expected}} and if +equal, writes @var{desired} into @code{*@var{ptr}}. If they are not equal, the +current contents of @code{*@var{ptr}} is written into @code{*@var{expected}}. + +True is returned if @code{*@var{desired}} is written into @code{*@var{ptr}} and +the execution is considered to conform to the memory model specified by +@var{success_memmodel}. There are no restrictions on what memory model can be +used here. + +False is returned otherwise, and the execution is considered to conform to +@var{failure_memmodel}. This memory model cannot be __ATOMIC_RELEASE nor +__ATOMIC_ACQ_REL. It also cannot be a stronger model than that specified +by @var{success_memmodel}. + +@item bool __atomic_compare_exchange (@var{type} *ptr, @var{type} *expected, @var{type} *desired, bool weak, int success_memmodel, int failure_memmodel) +@findex __atomic_compare_exchange +This builtin implements the generic version of __atomic_compare_exchange. The function is virtually identical to __atomic_compare_exchange_n, except the desired value is also a pointer. + + +@item @var{type} __atomic_add_fetch (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_sub_fetch (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_and_fetch (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_xor_fetch (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_or_fetch (@var{type} *ptr, @var{type} val, int memmodel) +@findex __atomic_add_fetch +@findex __atomic_sub_fetch +@findex __atomic_and_fetch +@findex __atomic_xor_fetch +@findex __atomic_or_fetch +These builtins perform the operation suggested by the name, and return the result +of the operation. That is, + +@smallexample +@{ *ptr @var{op}= val; return *ptr; @} +@end smallexample + +All memory models are valid. + +@item @var{type} __atomic_fetch_add (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_fetch_sub (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_fetch_and (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_fetch_xor (@var{type} *ptr, @var{type} val, int memmodel) +@itemx @var{type} __atomic_fetch_or (@var{type} *ptr, @var{type} val, int memmodel) +@findex __atomic_fetch_add +@findex __atomic_fetch_sub +@findex __atomic_fetch_and +@findex __atomic_fetch_xor +@findex __atomic_fetch_or +These builtins perform the operation suggested by the name, and return the value +that had previously been in *ptr . That is, + +@smallexample +@{ tmp = *ptr; *ptr @var{op}= val; return tmp; @} +@end smallexample + +All memory models are valid. + +@item void __atomic_thread_fence (int memmodel) +@findex __atomic_thread_fence + +This builtin acts as a synchronization fence between threads based on the +specified memory model. + +All memory orders are valid. + +@item void __atomic_signal_fence (int memmodel) +@findex __atomic_signal_fence + +This builtin acts as a synchronization fence between a thread and signal +handlers based in the same thread. + +All memory orders are valid. + +@item bool __atomic_always_lock_free (size_t size) +@findex __atomic_always_lock_free + +This builtin returns true if objects of size bytes will always generate lock +free atomic instructions for the target architecture. Otherwise false is +returned. + +size must resolve to a compile time constant. + +@smallexample +if (_atomic_always_lock_free (sizeof (long long))) +@end smallexample + +@item bool __atomic_is_lock_free (size_t size) +@findex __atomic_is_lock_free + +This builtin returns true if objects of size bytes will always generate lock +free atomic instructions for the target architecture. If it is not known to +be lock free a call is made to a runtime routine named __atomic_is_lock_free. + @end table @node Object Size Checking Index: gcc/doc/invoke.texi =================================================================== --- gcc/doc/invoke.texi (.../trunk) (revision 180790) +++ gcc/doc/invoke.texi (.../branches/cxx-mem-model) (revision 180811) @@ -9149,11 +9149,26 @@ The maximum number of conditional stores if either vectorization (@option{-ftree-vectorize}) or if-conversion (@option{-ftree-loop-if-convert}) is disabled. The default is 2. +@item allow-load-data-races +Allow optimizers to introduce new data races on loads. +Set to 1 to allow, otherwise to 0. This option is enabled by default +unless implicitly set by the @option{-fmemory-model=} option. + @item allow-store-data-races Allow optimizers to introduce new data races on stores. Set to 1 to allow, otherwise to 0. This option is enabled by default unless implicitly set by the @option{-fmemory-model=} option. +@item allow-packed-load-data-races +Allow optimizers to introduce new data races on packed data loads. +Set to 1 to allow, otherwise to 0. This option is enabled by default +unless implicitly set by the @option{-fmemory-model=} option. + +@item allow-packed-store-data-races +Allow optimizers to introduce new data races on packed data stores. +Set to 1 to allow, otherwise to 0. This option is enabled by default +unless implicitly set by the @option{-fmemory-model=} option. + @item case-values-threshold The smallest number of different values for which it is best to use a jump-table instead of a tree of conditional branches. If the value is Index: gcc/cppbuiltin.c =================================================================== --- gcc/cppbuiltin.c (.../trunk) (revision 180790) +++ gcc/cppbuiltin.c (.../branches/cxx-mem-model) (revision 180811) @@ -66,6 +66,12 @@ define__GNUC__ (cpp_reader *pfile) cpp_define_formatted (pfile, "__GNUC_MINOR__=%d", minor); cpp_define_formatted (pfile, "__GNUC_PATCHLEVEL__=%d", patchlevel); cpp_define_formatted (pfile, "__VERSION__=\"%s\"", version_string); + cpp_define_formatted (pfile, "__ATOMIC_RELAXED=%d", MEMMODEL_RELAXED); + cpp_define_formatted (pfile, "__ATOMIC_SEQ_CST=%d", MEMMODEL_SEQ_CST); + cpp_define_formatted (pfile, "__ATOMIC_ACQUIRE=%d", MEMMODEL_ACQUIRE); + cpp_define_formatted (pfile, "__ATOMIC_RELEASE=%d", MEMMODEL_RELEASE); + cpp_define_formatted (pfile, "__ATOMIC_ACQ_REL=%d", MEMMODEL_ACQ_REL); + cpp_define_formatted (pfile, "__ATOMIC_CONSUME=%d", MEMMODEL_CONSUME); } Index: gcc/c-family/c-common.c =================================================================== --- gcc/c-family/c-common.c (.../trunk) (revision 180790) +++ gcc/c-family/c-common.c (.../branches/cxx-mem-model) (revision 180811) @@ -9020,7 +9020,8 @@ sync_resolve_size (tree function, VEC(tr was encountered; true on success. */ static bool -sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params) +sync_resolve_params (tree orig_function, tree function, VEC(tree, gc) *params, + bool orig_format) { function_args_iterator iter; tree ptype; @@ -9052,17 +9053,30 @@ sync_resolve_params (tree orig_function, return false; } - /* ??? Ideally for the first conversion we'd use convert_for_assignment - so that we get warnings for anything that doesn't match the pointer - type. This isn't portable across the C and C++ front ends atm. */ - val = VEC_index (tree, params, parmnum); - val = convert (ptype, val); - val = convert (arg_type, val); - VEC_replace (tree, params, parmnum, val); + /* Only convert parameters if the size is appropriate with new format + sync routines. */ + if (orig_format || + tree_int_cst_equal (TYPE_SIZE (ptype), TYPE_SIZE (arg_type))) + { + /* Ideally for the first conversion we'd use convert_for_assignment + so that we get warnings for anything that doesn't match the pointer + type. This isn't portable across the C and C++ front ends atm. */ + val = VEC_index (tree, params, parmnum); + val = convert (ptype, val); + val = convert (arg_type, val); + VEC_replace (tree, params, parmnum, val); + } function_args_iter_next (&iter); } + /* __atomic routines are not variadic. */ + if (!orig_format && VEC_length (tree, params) != parmnum + 1) + { + error ("too many arguments to function %qE", orig_function); + return false; + } + /* The definition of these primitives is variadic, with the remaining being "an optional list of variables protected by the memory barrier". No clue what that's supposed to mean, precisely, but we consider all @@ -9077,13 +9091,383 @@ sync_resolve_params (tree orig_function, PARAMS. */ static tree -sync_resolve_return (tree first_param, tree result) +sync_resolve_return (tree first_param, tree result, bool orig_format) { tree ptype = TREE_TYPE (TREE_TYPE (first_param)); + tree rtype = TREE_TYPE (result); ptype = TYPE_MAIN_VARIANT (ptype); - return convert (ptype, result); + + /* New format doesn't require casting unless the types are the same size. */ + if (orig_format || tree_int_cst_equal (TYPE_SIZE (ptype), TYPE_SIZE (rtype))) + return convert (ptype, result); + else + return result; } +/* This function verifies the PARAMS to generic atomic FUNCTION. + It returns the size if all the parameters are the same size, otherwise + 0 is returned if the parameters are invalid. */ + +static int +get_atomic_generic_size (tree function, VEC(tree,gc) *params) +{ + unsigned int n_param; + unsigned int n_model; + unsigned int x; + int size_0; + tree type_0; + + /* Determine the parameter makeup. */ + switch (DECL_FUNCTION_CODE (function)) + { + case BUILT_IN_ATOMIC_EXCHANGE: + n_param = 4; + n_model = 1; + break; + case BUILT_IN_ATOMIC_LOAD: + case BUILT_IN_ATOMIC_STORE: + n_param = 3; + n_model = 1; + break; + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE: + n_param = 6; + n_model = 2; + break; + default: + return 0; + } + + if (VEC_length (tree, params) != n_param) + { + error ("Incorrect number of arguments to function %qE", function); + return 0; + } + + /* Get type of first parameter, and determine it's size. */ + type_0 = TREE_TYPE (VEC_index (tree, params, 0)); + if (TREE_CODE (type_0) != POINTER_TYPE) + { + error ("argument 0 of %qE must be a pointer type", function); + return 0; + } + size_0 = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (type_0)), 1); + + /* Check each other parameter is a pointer and the same size. */ + for (x = 0; x < n_param - n_model; x++) + { + int size; + tree type = TREE_TYPE (VEC_index (tree, params, x)); + /* __atomic_compare_exchange has a bool in the 4th postion, skip it. */ + if (n_param == 6 && x == 3) + continue; + if (!POINTER_TYPE_P (type)) + { + error ("argument %d of %qE must be a pointer type", x, function); + return 0; + } + size = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (type)), 1); + if (size != size_0) + { + error ("size mismatch in argument %d of %qE", x, function); + return 0; + } + } + + /* Check memory model parameters for validity. */ + for (x = n_param - n_model ; x < n_param; x++) + { + tree p = VEC_index (tree, params, x); + if (TREE_CODE (p) == INTEGER_CST) + { + int i = tree_low_cst (p, 1); + if (i < 0 || i >= MEMMODEL_LAST) + { + error ("invalid memory model argument %d of %qE", x, function); + return 0; + } + } + else + if (!INTEGRAL_TYPE_P (TREE_TYPE (p))) + { + error ("non-integer memory model argument %d of %qE", x, function); + return 0; + } + } + + return size_0; +} + + +/* This will take an __atomic_ generic FUNCTION call, and add a size parameter N + at the beginning of the parameter list PARAMS representing the size of the + objects. This is to match the library ABI requirement. LOC is the location + of the function call. + The new function is returned if it needed rebuilding, otherwise NULL_TREE is + returned to allow the external call to be constructed. */ + +static tree +add_atomic_size_parameter (unsigned n, location_t loc, tree function, + VEC(tree,gc) *params) +{ + tree size_node; + + /* Insert a SIZE_T parameter as the first param. If there isn't + enough space, allocate a new vector and recursively re-build with that. */ + if (!VEC_space (tree, params, 1)) + { + unsigned int z, len; + VEC(tree,gc) *vec; + tree f; + + len = VEC_length (tree, params); + vec = VEC_alloc (tree, gc, len + 1); + for (z = 0; z < len; z++) + VEC_quick_push (tree, vec, VEC_index (tree, params, z)); + f = build_function_call_vec (loc, function, vec, NULL); + VEC_free (tree, gc, vec); + return f; + } + + /* Add the size parameter and leave as a function call for processing. */ + size_node = build_int_cst (size_type_node, n); + VEC_quick_insert (tree, params, 0, size_node); + return NULL_TREE; +} + + +/* This will process an __atomic_exchange function call, determine whether it + needs to be mapped to the _N variation, or turned into a library call. + LOC is the location of the builtin call. + FUNCTION is the DECL that has been invoked; + PARAMS is the argument list for the call. The return value is non-null + TRUE is returned if it is translated into the proper format for a call to the + external library, and NEW_RETURN is set the tree for that function. + FALSE is returned if processing for the _N variation is required, and + NEW_RETURN is set to the the return value the result is copied into. */ +static bool +resolve_overloaded_atomic_exchange (location_t loc, tree function, + VEC(tree,gc) *params, tree *new_return) +{ + tree p0, p1, p2, p3; + tree I_type, I_type_ptr; + int n = get_atomic_generic_size (function, params); + + /* If not a lock-free size, change to the library generic format. */ + if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16) + { + *new_return = add_atomic_size_parameter (n, loc, function, params); + return true; + } + + /* Otherwise there is a lockfree match, transform the call from: + void fn(T* mem, T* desired, T* return, model) + into + *return = (T) (fn (In* mem, (In) *desired, model)) */ + + p0 = VEC_index (tree, params, 0); + p1 = VEC_index (tree, params, 1); + p2 = VEC_index (tree, params, 2); + p3 = VEC_index (tree, params, 3); + + /* Create pointer to appropriate size. */ + I_type = builtin_type_for_size (BITS_PER_UNIT * n, 1); + I_type_ptr = build_pointer_type (I_type); + + /* Convert object pointer to required type. */ + p0 = build1 (VIEW_CONVERT_EXPR, I_type_ptr, p0); + VEC_replace (tree, params, 0, p0); + + /* Convert new value to required type, and dereference it. */ + p1 = build_indirect_ref (loc, p1, RO_UNARY_STAR); + p1 = build1 (VIEW_CONVERT_EXPR, I_type, p1); + VEC_replace (tree, params, 1, p1); + + /* Move memory model to the 3rd position, and end param list. */ + VEC_replace (tree, params, 2, p3); + VEC_truncate (tree, params, 3); + + /* Convert return pointer and dereference it for later assignment. */ + *new_return = build_indirect_ref (loc, p2, RO_UNARY_STAR); + + return false; +} + + +/* This will process an __atomic_compare_exchange function call, determine + whether it needs to be mapped to the _N variation, or turned into a lib call. + LOC is the location of the builtin call. + FUNCTION is the DECL that has been invoked; + PARAMS is the argument list for the call. The return value is non-null + TRUE is returned if it is translated into the proper format for a call to the + external library, and NEW_RETURN is set the tree for that function. + FALSE is returned if processing for the _N variation is required. */ + +static bool +resolve_overloaded_atomic_compare_exchange (location_t loc, tree function, + VEC(tree,gc) *params, + tree *new_return) +{ + tree p0, p1, p2; + tree I_type, I_type_ptr; + int n = get_atomic_generic_size (function, params); + + /* If not a lock-free size, change to the library generic format. */ + if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16) + { + /* The library generic format does not have the weak parameter, so + remove it from the param list. Since a parameter has been removed, + we can be sure that there is room for the SIZE_T parameter, meaning + there will not be a recursive rebuilding of the parameter list, so + there is no danger this will be done twice. */ + if (n > 0) + { + VEC_replace (tree, params, 3, VEC_index (tree, params, 4)); + VEC_replace (tree, params, 4, VEC_index (tree, params, 5)); + VEC_truncate (tree, params, 5); + } + *new_return = add_atomic_size_parameter (n, loc, function, params); + return true; + } + + /* Otherwise, there is a match, so the call needs to be transformed from: + bool fn(T* mem, T* desired, T* return, weak, success, failure) + into + bool fn ((In *)mem, (In *)expected, (In) *desired, weak, succ, fail) */ + + p0 = VEC_index (tree, params, 0); + p1 = VEC_index (tree, params, 1); + p2 = VEC_index (tree, params, 2); + + /* Create pointer to appropriate size. */ + I_type = builtin_type_for_size (BITS_PER_UNIT * n, 1); + I_type_ptr = build_pointer_type (I_type); + + /* Convert object pointer to required type. */ + p0 = build1 (VIEW_CONVERT_EXPR, I_type_ptr, p0); + VEC_replace (tree, params, 0, p0); + + /* Convert expected pointer to required type. */ + p1 = build1 (VIEW_CONVERT_EXPR, I_type_ptr, p1); + VEC_replace (tree, params, 1, p1); + + /* Convert desired value to required type, and dereference it. */ + p2 = build_indirect_ref (loc, p2, RO_UNARY_STAR); + p2 = build1 (VIEW_CONVERT_EXPR, I_type, p2); + VEC_replace (tree, params, 2, p2); + + /* The rest of the parameters are fine. NULL means no special return value + processing.*/ + *new_return = NULL; + return false; +} + + +/* This will process an __atomic_load function call, determine whether it + needs to be mapped to the _N variation, or turned into a library call. + LOC is the location of the builtin call. + FUNCTION is the DECL that has been invoked; + PARAMS is the argument list for the call. The return value is non-null + TRUE is returned if it is translated into the proper format for a call to the + external library, and NEW_RETURN is set the tree for that function. + FALSE is returned if processing for the _N variation is required, and + NEW_RETURN is set to the the return value the result is copied into. */ + +static bool +resolve_overloaded_atomic_load (location_t loc, tree function, + VEC(tree,gc) *params, tree *new_return) +{ + tree p0, p1, p2; + tree I_type, I_type_ptr; + int n = get_atomic_generic_size (function, params); + + /* If not a lock-free size, change to the library generic format. */ + if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16) + { + *new_return = add_atomic_size_parameter (n, loc, function, params); + return true; + } + + /* Otherwise, there is a match, so the call needs to be transformed from: + void fn(T* mem, T* return, model) + into + *return = (T) (fn ((In *) mem, model)) */ + + p0 = VEC_index (tree, params, 0); + p1 = VEC_index (tree, params, 1); + p2 = VEC_index (tree, params, 2); + + /* Create pointer to appropriate size. */ + I_type = builtin_type_for_size (BITS_PER_UNIT * n, 1); + I_type_ptr = build_pointer_type (I_type); + + /* Convert object pointer to required type. */ + p0 = build1 (VIEW_CONVERT_EXPR, I_type_ptr, p0); + VEC_replace (tree, params, 0, p0); + + /* Move memory model to the 2nd position, and end param list. */ + VEC_replace (tree, params, 1, p2); + VEC_truncate (tree, params, 2); + + /* Convert return pointer and dereference it for later assignment. */ + *new_return = build_indirect_ref (loc, p1, RO_UNARY_STAR); + + return false; +} + + +/* This will process an __atomic_store function call, determine whether it + needs to be mapped to the _N variation, or turned into a library call. + LOC is the location of the builtin call. + FUNCTION is the DECL that has been invoked; + PARAMS is the argument list for the call. The return value is non-null + TRUE is returned if it is translated into the proper format for a call to the + external library, and NEW_RETURN is set the tree for that function. + FALSE is returned if processing for the _N variation is required, and + NEW_RETURN is set to the the return value the result is copied into. */ + +static bool +resolve_overloaded_atomic_store (location_t loc, tree function, + VEC(tree,gc) *params, tree *new_return) +{ + tree p0, p1; + tree I_type, I_type_ptr; + int n = get_atomic_generic_size (function, params); + + /* If not a lock-free size, change to the library generic format. */ + if (n != 1 && n != 2 && n != 4 && n != 8 && n != 16) + { + *new_return = add_atomic_size_parameter (n, loc, function, params); + return true; + } + + /* Otherwise, there is a match, so the call needs to be transformed from: + void fn(T* mem, T* value, model) + into + fn ((In *) mem, (In) *value, model) */ + + p0 = VEC_index (tree, params, 0); + p1 = VEC_index (tree, params, 1); + + /* Create pointer to appropriate size. */ + I_type = builtin_type_for_size (BITS_PER_UNIT * n, 1); + I_type_ptr = build_pointer_type (I_type); + + /* Convert object pointer to required type. */ + p0 = build1 (VIEW_CONVERT_EXPR, I_type_ptr, p0); + VEC_replace (tree, params, 0, p0); + + /* Convert new value to required type, and dereference it. */ + p1 = build_indirect_ref (loc, p1, RO_UNARY_STAR); + p1 = build1 (VIEW_CONVERT_EXPR, I_type, p1); + VEC_replace (tree, params, 1, p1); + + /* The memory model is in the right spot already. Return is void. */ + *new_return = NULL_TREE; + + return false; +} + + /* Some builtin functions are placeholders for other expressions. This function should be called immediately after parsing the call expression before surrounding code has committed to the type of the expression. @@ -9099,6 +9483,9 @@ tree resolve_overloaded_builtin (location_t loc, tree function, VEC(tree,gc) *params) { enum built_in_function orig_code = DECL_FUNCTION_CODE (function); + bool orig_format = true; + tree new_return = NULL_TREE; + switch (DECL_BUILT_IN_CLASS (function)) { case BUILT_IN_NORMAL: @@ -9115,6 +9502,78 @@ resolve_overloaded_builtin (location_t l /* Handle BUILT_IN_NORMAL here. */ switch (orig_code) { + case BUILT_IN_ATOMIC_EXCHANGE: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE: + case BUILT_IN_ATOMIC_LOAD: + case BUILT_IN_ATOMIC_STORE: + { + /* Handle these 4 together so that they can fall through to the next + case if the call is transformed to an _N variant. */ + switch (orig_code) + { + case BUILT_IN_ATOMIC_EXCHANGE: + { + if (resolve_overloaded_atomic_exchange (loc, function, params, + &new_return)) + return new_return; + /* Change to the _N variant. */ + orig_code = BUILT_IN_ATOMIC_EXCHANGE_N; + break; + } + + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE: + { + if (resolve_overloaded_atomic_compare_exchange (loc, function, + params, + &new_return)) + return new_return; + /* Change to the _N variant. */ + orig_code = BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N; + break; + } + case BUILT_IN_ATOMIC_LOAD: + { + if (resolve_overloaded_atomic_load (loc, function, params, + &new_return)) + return new_return; + /* Change to the _N variant. */ + orig_code = BUILT_IN_ATOMIC_LOAD_N; + break; + } + case BUILT_IN_ATOMIC_STORE: + { + if (resolve_overloaded_atomic_store (loc, function, params, + &new_return)) + return new_return; + /* Change to the _N variant. */ + orig_code = BUILT_IN_ATOMIC_STORE_N; + break; + } + default: + gcc_unreachable (); + } + /* Fallthrough to the normal processing. */ + } + case BUILT_IN_ATOMIC_EXCHANGE_N: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N: + case BUILT_IN_ATOMIC_LOAD_N: + case BUILT_IN_ATOMIC_STORE_N: + case BUILT_IN_ATOMIC_ADD_FETCH_N: + case BUILT_IN_ATOMIC_SUB_FETCH_N: + case BUILT_IN_ATOMIC_AND_FETCH_N: + case BUILT_IN_ATOMIC_NAND_FETCH_N: + case BUILT_IN_ATOMIC_XOR_FETCH_N: + case BUILT_IN_ATOMIC_OR_FETCH_N: + case BUILT_IN_ATOMIC_FETCH_ADD_N: + case BUILT_IN_ATOMIC_FETCH_SUB_N: + case BUILT_IN_ATOMIC_FETCH_AND_N: + case BUILT_IN_ATOMIC_FETCH_NAND_N: + case BUILT_IN_ATOMIC_FETCH_XOR_N: + case BUILT_IN_ATOMIC_FETCH_OR_N: + { + orig_format = false; + /* Fallthru for parameter processing. */ + } case BUILT_IN_SYNC_FETCH_AND_ADD_N: case BUILT_IN_SYNC_FETCH_AND_SUB_N: case BUILT_IN_SYNC_FETCH_AND_OR_N: @@ -9141,15 +9600,30 @@ resolve_overloaded_builtin (location_t l fncode = (enum built_in_function)((int)orig_code + exact_log2 (n) + 1); new_function = builtin_decl_explicit (fncode); - if (!sync_resolve_params (function, new_function, params)) + if (!sync_resolve_params (function, new_function, params, orig_format)) return error_mark_node; first_param = VEC_index (tree, params, 0); result = build_function_call_vec (loc, new_function, params, NULL); + if (result == error_mark_node) + return result; if (orig_code != BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_N - && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N) - result = sync_resolve_return (first_param, result); - + && orig_code != BUILT_IN_SYNC_LOCK_RELEASE_N + && orig_code != BUILT_IN_ATOMIC_STORE_N) + result = sync_resolve_return (first_param, result, orig_format); + + /* If new_return is set, assign function to that expr and cast the + result to void since the generic interface returned void. */ + if (new_return) + { + /* Cast function result from I{1,2,4,8,16} to the required type. */ + result = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (new_return), result); + result = build2 (MODIFY_EXPR, TREE_TYPE (new_return), new_return, + result); + TREE_SIDE_EFFECTS (result) = 1; + protected_set_expr_location (result, loc); + result = convert (void_type_node, result); + } return result; } Index: gcc/c-family/ChangeLog.mm =================================================================== --- gcc/c-family/ChangeLog.mm (.../trunk) (revision 0) +++ gcc/c-family/ChangeLog.mm (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,54 @@ +2011-10-27 Richard Henderson + + * c-cppbuiltin.c (c_cpp_builtins): Test both atomic and sync patterns. + +2011-10-25 Andrew MacLeod + + * c-common.c (get_atomic_generic_size): New. Find size of generic + atomic function parameters and do typechecking. + (add_atomic_size_parameter): New. Insert size into parameter list. + (resolve_overloaded_atomic_exchange): Restructure __atomic_exchange to + either __atomic_exchange_n or external library call. + (resolve_overloaded_atomic_compare_exchange): Restructure + __atomic_compare_exchange to either _n variant or external library call. + (resolve_overloaded_atomic_load): Restructure __atomic_load to either + __atomic_load_n or an external library call. + (resolve_overloaded_atomic_store): Restructure __atomic_store to either + __atomic_store_n or an external library call. + (resolve_overloaded_builtin): Handle 4 generic __atomic calls. + +2011-10-20 Andrew MacLeod + + * c-common.c (resolve_overloaded_builtin): Don't try to process a + return value with an error mark. + +2011-10-17 Andrew MacLeod + + * c-common.c: Rename __sync_mem to __atomic. + +2011-09-16 Andrew MacLeod + + * c-common.c (sync_resolve_params, sync_resolve_return): Only tweak + parameters that are the same type size. + (resolve_overloaded_builtin): Use new param for __sync_mem builtins. + Support new NAND builtins. + +2011-08-13 Andrew MacLeod + + * c-common.c (resolve_overloaded_builtin): Handle new __SYNC_MEM + builtins. + +2011-07-27 Andrew Macleod + + * c-common.c (resolve_overloaded_builtin): Handle BUILT_IN_SYNC_MEM_* + types. + +2011-06-23 Andrew Macleod + + * c-common.c (resolve_overloaded_builtin): Add BUILT_IN_SYNC_MEM_LOAD_N. + +2011-06-21 Andrew Macleod + Aldy Hernandez + + * c-common.c (BUILT_IN_SYNC_MEM_EXCHANGE_N): Add case. + Index: gcc/c-family/c-cppbuiltin.c =================================================================== --- gcc/c-family/c-cppbuiltin.c (.../trunk) (revision 180790) +++ gcc/c-family/c-cppbuiltin.c (.../branches/cxx-mem-model) (revision 180811) @@ -758,30 +758,50 @@ c_cpp_builtins (cpp_reader *pfile) /* Tell source code if the compiler makes sync_compare_and_swap builtins available. */ -#ifdef HAVE_sync_compare_and_swapqi - if (HAVE_sync_compare_and_swapqi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); +#ifndef HAVE_sync_compare_and_swapqi +#define HAVE_sync_compare_and_swapqi 0 +#endif +#ifndef HAVE_atomic_compare_and_swapqi +#define HAVE_atomic_compare_and_swapqi 0 #endif + if (HAVE_sync_compare_and_swapqi || HAVE_atomic_compare_and_swapqi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); -#ifdef HAVE_sync_compare_and_swaphi - if (HAVE_sync_compare_and_swaphi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); +#ifndef HAVE_sync_compare_and_swaphi +#define HAVE_sync_compare_and_swaphi 0 #endif +#ifndef HAVE_atomic_compare_and_swaphi +#define HAVE_atomic_compare_and_swaphi 0 +#endif + if (HAVE_sync_compare_and_swaphi || HAVE_atomic_compare_and_swaphi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); -#ifdef HAVE_sync_compare_and_swapsi - if (HAVE_sync_compare_and_swapsi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); +#ifndef HAVE_sync_compare_and_swapsi +#define HAVE_sync_compare_and_swapsi 0 +#endif +#ifndef HAVE_atomic_compare_and_swapsi +#define HAVE_atomic_compare_and_swapsi 0 #endif + if (HAVE_sync_compare_and_swapsi || HAVE_atomic_compare_and_swapsi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); -#ifdef HAVE_sync_compare_and_swapdi - if (HAVE_sync_compare_and_swapdi) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); +#ifndef HAVE_sync_compare_and_swapdi +#define HAVE_sync_compare_and_swapdi 0 #endif +#ifndef HAVE_atomic_compare_and_swapdi +#define HAVE_atomic_compare_and_swapdi 0 +#endif + if (HAVE_sync_compare_and_swapdi || HAVE_atomic_compare_and_swapdi) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); -#ifdef HAVE_sync_compare_and_swapti - if (HAVE_sync_compare_and_swapti) - cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); +#ifndef HAVE_sync_compare_and_swapti +#define HAVE_sync_compare_and_swapti 0 +#endif +#ifndef HAVE_atomic_compare_and_swapti +#define HAVE_atomic_compare_and_swapti 0 #endif + if (HAVE_sync_compare_and_swapti || HAVE_atomic_compare_and_swapti) + cpp_define (pfile, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); #ifdef DWARF2_UNWIND_INFO if (dwarf2out_do_cfi_asm ()) Index: gcc/optabs.c =================================================================== --- gcc/optabs.c (.../trunk) (revision 180790) +++ gcc/optabs.c (.../branches/cxx-mem-model) (revision 180811) @@ -7162,43 +7162,25 @@ expand_vec_cond_expr (tree vec_cond_type } -/* This is an internal subroutine of the other compare_and_swap expanders. - MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap - operation. TARGET is an optional place to store the value result of - the operation. ICODE is the particular instruction to expand. Return - the result of the operation. */ - -static rtx -expand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val, - rtx target, enum insn_code icode) -{ - struct expand_operand ops[4]; - enum machine_mode mode = GET_MODE (mem); +/* Return true if there is a compare_and_swap pattern. */ - create_output_operand (&ops[0], target, mode); - create_fixed_operand (&ops[1], mem); - /* OLD_VAL and NEW_VAL may have been promoted to a wider mode. - Shrink them if so. */ - create_convert_operand_to (&ops[2], old_val, mode, true); - create_convert_operand_to (&ops[3], new_val, mode, true); - if (maybe_expand_insn (icode, 4, ops)) - return ops[0].value; - return NULL_RTX; -} - -/* Expand a compare-and-swap operation and return its value. */ - -rtx -expand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) +bool +can_compare_and_swap_p (enum machine_mode mode) { - enum machine_mode mode = GET_MODE (mem); - enum insn_code icode - = direct_optab_handler (sync_compare_and_swap_optab, mode); + enum insn_code icode; - if (icode == CODE_FOR_nothing) - return NULL_RTX; + /* Check for __sync_compare_and_swap. */ + icode = direct_optab_handler (sync_compare_and_swap_optab, mode); + if (icode != CODE_FOR_nothing) + return true; + + /* Check for __atomic_compare_and_swap. */ + icode = direct_optab_handler (atomic_compare_and_swap_optab, mode); + if (icode != CODE_FOR_nothing) + return true; - return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode); + /* No inline compare and swap. */ + return false; } /* Helper function to find the MODE_CC set in a sync_compare_and_swap @@ -7216,58 +7198,6 @@ find_cc_set (rtx x, const_rtx pat, void } } -/* Expand a compare-and-swap operation and store true into the result if - the operation was successful and false otherwise. Return the result. - Unlike other routines, TARGET is not optional. */ - -rtx -expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target) -{ - enum machine_mode mode = GET_MODE (mem); - enum insn_code icode; - rtx subtarget, seq, cc_reg; - - /* If the target supports a compare-and-swap pattern that simultaneously - sets some flag for success, then use it. Otherwise use the regular - compare-and-swap and follow that immediately with a compare insn. */ - icode = direct_optab_handler (sync_compare_and_swap_optab, mode); - if (icode == CODE_FOR_nothing) - return NULL_RTX; - - do_pending_stack_adjust (); - do - { - start_sequence (); - subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val, - NULL_RTX, icode); - cc_reg = NULL_RTX; - if (subtarget == NULL_RTX) - { - end_sequence (); - return NULL_RTX; - } - - if (have_insn_for (COMPARE, CCmode)) - note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg); - seq = get_insns (); - end_sequence (); - - /* We might be comparing against an old value. Try again. :-( */ - if (!cc_reg && MEM_P (old_val)) - { - seq = NULL_RTX; - old_val = force_reg (mode, old_val); - } - } - while (!seq); - - emit_insn (seq); - if (cc_reg) - return emit_store_flag_force (target, EQ, cc_reg, const0_rtx, VOIDmode, 0, 1); - else - return emit_store_flag_force (target, EQ, subtarget, old_val, VOIDmode, 1, 1); -} - /* This is a helper function for the other atomic operations. This function emits a loop that contains SEQ that iterates until a compare-and-swap operation at the end succeeds. MEM is the memory to be modified. SEQ is @@ -7281,8 +7211,7 @@ static bool expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq) { enum machine_mode mode = GET_MODE (mem); - enum insn_code icode; - rtx label, cmp_reg, subtarget, cc_reg; + rtx label, cmp_reg, success, oldval; /* The loop we want to generate looks like @@ -7290,8 +7219,8 @@ expand_compare_and_swap_loop (rtx mem, r label: old_reg = cmp_reg; seq; - cmp_reg = compare-and-swap(mem, old_reg, new_reg) - if (cmp_reg != old_reg) + (success, cmp_reg) = compare-and-swap(mem, old_reg, new_reg) + if (success) goto label; Note that we only do the plain load from memory once. Subsequent @@ -7306,331 +7235,539 @@ expand_compare_and_swap_loop (rtx mem, r if (seq) emit_insn (seq); - /* If the target supports a compare-and-swap pattern that simultaneously - sets some flag for success, then use it. Otherwise use the regular - compare-and-swap and follow that immediately with a compare insn. */ - icode = direct_optab_handler (sync_compare_and_swap_optab, mode); - if (icode == CODE_FOR_nothing) + success = NULL_RTX; + oldval = cmp_reg; + if (!expand_atomic_compare_and_swap (&success, &oldval, mem, old_reg, + new_reg, false, MEMMODEL_SEQ_CST, + MEMMODEL_RELAXED)) return false; - subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg, - cmp_reg, icode); - if (subtarget == NULL_RTX) - return false; + if (oldval != cmp_reg) + emit_move_insn (cmp_reg, oldval); + + /* ??? Mark this jump predicted not taken? */ + emit_cmp_and_jump_insns (success, const0_rtx, EQ, const0_rtx, + GET_MODE (success), 1, label); + return true; +} + + +/* This function expands the atomic exchange operation: + atomically store VAL in MEM and return the previous value in MEM. + + MEMMODEL is the memory model variant to use. + TARGET is an option place to stick the return value. */ + +rtx +expand_atomic_exchange (rtx target, rtx mem, rtx val, enum memmodel model) +{ + enum machine_mode mode = GET_MODE (mem); + enum insn_code icode; + rtx last_insn; - cc_reg = NULL_RTX; - if (have_insn_for (COMPARE, CCmode)) - note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg); - if (cc_reg) + /* If the target supports the exchange directly, great. */ + icode = direct_optab_handler (atomic_exchange_optab, mode); + if (icode != CODE_FOR_nothing) { - cmp_reg = cc_reg; - old_reg = const0_rtx; + struct expand_operand ops[4]; + + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[2], val, mode, true); + create_integer_operand (&ops[3], model); + if (maybe_expand_insn (icode, 4, ops)) + return ops[0].value; } - else + + /* Legacy sync_lock_test_and_set works the same, but is only defined as an + acquire barrier. If the pattern exists, and the memory model is stronger + than acquire, add a release barrier before the instruction. + The barrier is not needed if sync_lock_test_and_set doesn't exist since + it will expand into a compare-and-swap loop. */ + + icode = direct_optab_handler (sync_lock_test_and_set_optab, mode); + last_insn = get_last_insn (); + if ((icode != CODE_FOR_nothing) && (model == MEMMODEL_SEQ_CST || + model == MEMMODEL_RELEASE || + model == MEMMODEL_ACQ_REL)) + expand_builtin_mem_thread_fence (model); + + if (icode != CODE_FOR_nothing) { - if (subtarget != cmp_reg) - emit_move_insn (cmp_reg, subtarget); + struct expand_operand ops[3]; + + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[2], val, mode, true); + if (maybe_expand_insn (icode, 3, ops)) + return ops[0].value; } - /* ??? Mark this jump predicted not taken? */ - emit_cmp_and_jump_insns (cmp_reg, old_reg, NE, const0_rtx, GET_MODE (cmp_reg), 1, - label); - return true; + /* Remove any fence we may have inserted since a compare and swap loop is a + full memory barrier. */ + if (last_insn != get_last_insn ()) + delete_insns_since (last_insn); + + /* Otherwise, use a compare-and-swap loop for the exchange. */ + if (can_compare_and_swap_p (mode)) + { + if (!target || !register_operand (target, mode)) + target = gen_reg_rtx (mode); + if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) + val = convert_modes (mode, GET_MODE (val), val, 1); + if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX)) + return target; + } + + return NULL_RTX; } -/* This function generates the atomic operation MEM CODE= VAL. In this - case, we do not care about any resulting value. Returns NULL if we - cannot generate the operation. */ +/* This function expands the atomic compare exchange operation: -rtx -expand_sync_operation (rtx mem, rtx val, enum rtx_code code) + *PTARGET_BOOL is an optional place to store the boolean success/failure. + *PTARGET_OVAL is an optional place to store the old value from memory. + Both target parameters may be NULL to indicate that we do not care about + that return value. Both target parameters are updated on success to + the actual location of the corresponding result. + + MEMMODEL is the memory model variant to use. + + The return value of the function is true for success. */ + +bool +expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval, + rtx mem, rtx expected, rtx desired, + bool is_weak, enum memmodel succ_model, + enum memmodel fail_model) { enum machine_mode mode = GET_MODE (mem); + struct expand_operand ops[8]; enum insn_code icode; - rtx insn; + rtx target_bool, target_oval; - /* Look to see if the target supports the operation directly. */ - switch (code) + /* Load expected into a register for the compare and swap. */ + if (MEM_P (expected)) + expected = copy_to_reg (expected); + + /* Make sure we always have some place to put the return oldval. + Further, make sure that place is distinct from the input expected, + just in case we need that path down below. */ + if (ptarget_oval == NULL + || (target_oval = *ptarget_oval) == NULL + || reg_overlap_mentioned_p (expected, target_oval)) + target_oval = gen_reg_rtx (mode); + + icode = direct_optab_handler (atomic_compare_and_swap_optab, mode); + if (icode != CODE_FOR_nothing) { - case PLUS: - icode = direct_optab_handler (sync_add_optab, mode); - break; - case IOR: - icode = direct_optab_handler (sync_ior_optab, mode); - break; - case XOR: - icode = direct_optab_handler (sync_xor_optab, mode); - break; - case AND: - icode = direct_optab_handler (sync_and_optab, mode); - break; - case NOT: - icode = direct_optab_handler (sync_nand_optab, mode); - break; + enum machine_mode bool_mode = insn_data[icode].operand[0].mode; - case MINUS: - icode = direct_optab_handler (sync_sub_optab, mode); - if (icode == CODE_FOR_nothing || CONST_INT_P (val)) - { - icode = direct_optab_handler (sync_add_optab, mode); - if (icode != CODE_FOR_nothing) - { - val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); - code = PLUS; - } - } - break; + /* Make sure we always have a place for the bool operand. */ + if (ptarget_bool == NULL + || (target_bool = *ptarget_bool) == NULL + || GET_MODE (target_bool) != bool_mode) + target_bool = gen_reg_rtx (bool_mode); + + /* Emit the compare_and_swap. */ + create_output_operand (&ops[0], target_bool, bool_mode); + create_output_operand (&ops[1], target_oval, mode); + create_fixed_operand (&ops[2], mem); + create_convert_operand_to (&ops[3], expected, mode, true); + create_convert_operand_to (&ops[4], desired, mode, true); + create_integer_operand (&ops[5], is_weak); + create_integer_operand (&ops[6], succ_model); + create_integer_operand (&ops[7], fail_model); + expand_insn (icode, 8, ops); + + /* Return success/failure. */ + target_bool = ops[0].value; + target_oval = ops[1].value; + goto success; + } - default: - gcc_unreachable (); + /* Otherwise fall back to the original __sync_val_compare_and_swap + which is always seq-cst. */ + icode = direct_optab_handler (sync_compare_and_swap_optab, mode); + if (icode != CODE_FOR_nothing) + { + rtx cc_reg; + + create_output_operand (&ops[0], target_oval, mode); + create_fixed_operand (&ops[1], mem); + create_convert_operand_to (&ops[2], expected, mode, true); + create_convert_operand_to (&ops[3], desired, mode, true); + if (!maybe_expand_insn (icode, 4, ops)) + return false; + + target_oval = ops[0].value; + target_bool = NULL_RTX; + + /* If the caller isn't interested in the boolean return value, + skip the computation of it. */ + if (ptarget_bool == NULL) + goto success; + + /* Otherwise, work out if the compare-and-swap succeeded. */ + cc_reg = NULL_RTX; + if (have_insn_for (COMPARE, CCmode)) + note_stores (PATTERN (get_last_insn ()), find_cc_set, &cc_reg); + + target_bool + = (cc_reg + ? emit_store_flag_force (target_bool, EQ, cc_reg, + const0_rtx, VOIDmode, 0, 1) + : emit_store_flag_force (target_bool, EQ, target_oval, + expected, VOIDmode, 1, 1)); + goto success; } + return false; + + success: + /* Make sure that the oval output winds up where the caller asked. */ + if (ptarget_oval) + *ptarget_oval = target_oval; + if (ptarget_bool) + *ptarget_bool = target_bool; + return true; +} + +/* This function expands the atomic load operation: + return the atomically loaded value in MEM. + + MEMMODEL is the memory model variant to use. + TARGET is an option place to stick the return value. */ + +rtx +expand_atomic_load (rtx target, rtx mem, enum memmodel model) +{ + enum machine_mode mode = GET_MODE (mem); + enum insn_code icode; - /* Generate the direct operation, if present. */ + /* If the target supports the load directly, great. */ + icode = direct_optab_handler (atomic_load_optab, mode); if (icode != CODE_FOR_nothing) { - struct expand_operand ops[2]; + struct expand_operand ops[3]; - create_fixed_operand (&ops[0], mem); - /* VAL may have been promoted to a wider mode. Shrink it if so. */ - create_convert_operand_to (&ops[1], val, mode, true); - if (maybe_expand_insn (icode, 2, ops)) - return const0_rtx; + create_output_operand (&ops[0], target, mode); + create_fixed_operand (&ops[1], mem); + create_integer_operand (&ops[2], model); + if (maybe_expand_insn (icode, 3, ops)) + return ops[0].value; } - /* Failing that, generate a compare-and-swap loop in which we perform the - operation with normal arithmetic instructions. */ - if (direct_optab_handler (sync_compare_and_swap_optab, mode) - != CODE_FOR_nothing) + /* If there is no load pattern, default to a move with barriers. If the size + of the object is greater than word size on this target, a default load + will not be atomic. */ + if (GET_MODE_PRECISION (mode) > BITS_PER_WORD) { - rtx t0 = gen_reg_rtx (mode), t1; + /* Issue val = compare_and_swap (mem, 0, 0). + This may cause the occasional harmless store of 0 when the value is + already 0, but do it anyway until its determined to be invalid. */ + expand_atomic_compare_and_swap (NULL, &target, mem, const0_rtx, + const0_rtx, false, model, model); + return target; + } - start_sequence (); + if (!target || target == const0_rtx) + target = gen_reg_rtx (mode); - t1 = t0; - if (code == NOT) - { - t1 = expand_simple_binop (mode, AND, t1, val, NULL_RTX, - true, OPTAB_LIB_WIDEN); - t1 = expand_simple_unop (mode, code, t1, NULL_RTX, true); - } - else - t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, - true, OPTAB_LIB_WIDEN); - insn = get_insns (); - end_sequence (); + /* Emit the appropriate barrier before the load. */ + expand_builtin_mem_thread_fence (model); - if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) - return const0_rtx; - } + emit_move_insn (target, mem); - return NULL_RTX; + /* For SEQ_CST, also emit a barrier after the load. */ + if (model == MEMMODEL_SEQ_CST) + expand_builtin_mem_thread_fence (model); + + return target; } -/* This function generates the atomic operation MEM CODE= VAL. In this - case, we do care about the resulting value: if AFTER is true then - return the value MEM holds after the operation, if AFTER is false - then return the value MEM holds before the operation. TARGET is an - optional place for the result value to be stored. */ +/* This function expands the atomic store operation: + Atomically store VAL in MEM. + MEMMODEL is the memory model variant to use. + function returns const0_rtx if a pattern was emitted. */ rtx -expand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code, - bool after, rtx target) +expand_atomic_store (rtx mem, rtx val, enum memmodel model) { enum machine_mode mode = GET_MODE (mem); - enum insn_code old_code, new_code, icode; - bool compensate; - rtx insn; + enum insn_code icode; + struct expand_operand ops[3]; + + /* If the target supports the store directly, great. */ + icode = direct_optab_handler (atomic_store_optab, mode); + if (icode != CODE_FOR_nothing) + { + create_fixed_operand (&ops[0], mem); + create_input_operand (&ops[1], val, mode); + create_integer_operand (&ops[2], model); + if (maybe_expand_insn (icode, 3, ops)) + return const0_rtx; + } + + /* If the size of the object is greater than word size on this target, + a default store will not be atomic, Try a mem_exchange and throw away + the result. If that doesn't work, don't do anything. */ + if (GET_MODE_PRECISION(mode) > BITS_PER_WORD) + { + rtx target = expand_atomic_exchange (NULL_RTX, mem, val, model); + if (target) + return const0_rtx; + else + return NULL_RTX; + } + + /* If there is no mem_store, default to a move with barriers */ + if (model == MEMMODEL_SEQ_CST || model == MEMMODEL_RELEASE) + expand_builtin_mem_thread_fence (model); + + emit_move_insn (mem, val); + + /* For SEQ_CST, also emit a barrier after the load. */ + if (model == MEMMODEL_SEQ_CST) + expand_builtin_mem_thread_fence (model); + + return const0_rtx; +} + + +/* Structure containing the pointers and values required to process the + various forms of the atomic_fetch_op and atomic_op_fetch builtins. */ + +struct atomic_op_functions +{ + struct direct_optab_d *mem_fetch_before; + struct direct_optab_d *mem_fetch_after; + struct direct_optab_d *mem_no_result; + struct direct_optab_d *fetch_before; + struct direct_optab_d *fetch_after; + struct direct_optab_d *no_result; + enum rtx_code reverse_code; +}; + +static const struct atomic_op_functions * +get_atomic_op_for_code (enum rtx_code code) +{ + static const struct atomic_op_functions add_op = { + atomic_fetch_add_optab, atomic_add_fetch_optab, atomic_add_optab, + sync_old_add_optab, sync_new_add_optab, sync_add_optab, MINUS + }, sub_op = { + atomic_fetch_sub_optab, atomic_sub_fetch_optab, atomic_sub_optab, + sync_old_sub_optab, sync_new_sub_optab, sync_sub_optab, PLUS + }, xor_op = { + atomic_fetch_xor_optab, atomic_xor_fetch_optab, atomic_xor_optab, + sync_old_xor_optab, sync_new_xor_optab, sync_xor_optab, XOR + }, and_op = { + atomic_fetch_and_optab, atomic_and_fetch_optab, atomic_and_optab, + sync_old_and_optab, sync_new_and_optab, sync_and_optab, UNKNOWN + }, nand_op = { + atomic_fetch_nand_optab, atomic_nand_fetch_optab, atomic_nand_optab, + sync_old_nand_optab, sync_new_nand_optab, sync_nand_optab, UNKNOWN + }, ior_op = { + atomic_fetch_or_optab, atomic_or_fetch_optab, atomic_or_optab, + sync_old_ior_optab, sync_new_ior_optab, sync_ior_optab, UNKNOWN + }; - /* Look to see if the target supports the operation directly. */ switch (code) { case PLUS: - old_code = direct_optab_handler (sync_old_add_optab, mode); - new_code = direct_optab_handler (sync_new_add_optab, mode); - break; - case IOR: - old_code = direct_optab_handler (sync_old_ior_optab, mode); - new_code = direct_optab_handler (sync_new_ior_optab, mode); - break; + return &add_op; + case MINUS: + return &sub_op; case XOR: - old_code = direct_optab_handler (sync_old_xor_optab, mode); - new_code = direct_optab_handler (sync_new_xor_optab, mode); - break; + return &xor_op; case AND: - old_code = direct_optab_handler (sync_old_and_optab, mode); - new_code = direct_optab_handler (sync_new_and_optab, mode); - break; + return &and_op; + case IOR: + return &ior_op; case NOT: - old_code = direct_optab_handler (sync_old_nand_optab, mode); - new_code = direct_optab_handler (sync_new_nand_optab, mode); - break; - - case MINUS: - old_code = direct_optab_handler (sync_old_sub_optab, mode); - new_code = direct_optab_handler (sync_new_sub_optab, mode); - if ((old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing) - || CONST_INT_P (val)) - { - old_code = direct_optab_handler (sync_old_add_optab, mode); - new_code = direct_optab_handler (sync_new_add_optab, mode); - if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing) - { - val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1); - code = PLUS; - } - } - break; - + return &nand_op; default: gcc_unreachable (); } +} - /* If the target does supports the proper new/old operation, great. But - if we only support the opposite old/new operation, check to see if we - can compensate. In the case in which the old value is supported, then - we can always perform the operation again with normal arithmetic. In - the case in which the new value is supported, then we can only handle - this in the case the operation is reversible. */ - compensate = false; - if (after) +/* Try to emit an instruction for a specific operation varaition. + OPTAB contains the OP functions. + TARGET is an optional place to return the result. const0_rtx means unused. + MEM is the memory location to operate on. + VAL is the value to use in the operation. + USE_MEMMODEL is TRUE if the variation with a memory model should be tried. + MODEL is the memory model, if used. + AFTER is true if the returned result is the value after the operation. */ + +static rtx +maybe_emit_op (const struct atomic_op_functions *optab, rtx target, rtx mem, + rtx val, bool use_memmodel, enum memmodel model, bool after) +{ + enum machine_mode mode = GET_MODE (mem); + struct direct_optab_d *this_optab; + struct expand_operand ops[4]; + enum insn_code icode; + int op_counter = 0; + int num_ops; + + /* Check to see if there is a result returned. */ + if (target == const0_rtx) { - icode = new_code; - if (icode == CODE_FOR_nothing) - { - icode = old_code; - if (icode != CODE_FOR_nothing) - compensate = true; + if (use_memmodel) + { + this_optab = optab->mem_no_result; + create_integer_operand (&ops[2], model); + num_ops = 3; + } + else + { + this_optab = optab->no_result; + num_ops = 2; } } + /* Otherwise, we need to generate a result. */ else { - icode = old_code; - if (icode == CODE_FOR_nothing - && (code == PLUS || code == MINUS || code == XOR)) + if (use_memmodel) + { + this_optab = after ? optab->mem_fetch_after : optab->mem_fetch_before; + create_integer_operand (&ops[3], model); + num_ops= 4; + } + else { - icode = new_code; - if (icode != CODE_FOR_nothing) - compensate = true; + this_optab = after ? optab->fetch_after : optab->fetch_before; + num_ops = 3; } + create_output_operand (&ops[op_counter++], target, mode); } - /* If we found something supported, great. */ - if (icode != CODE_FOR_nothing) - { - struct expand_operand ops[3]; + icode = direct_optab_handler (this_optab, mode); + if (icode == CODE_FOR_nothing) + return NULL_RTX; + + create_fixed_operand (&ops[op_counter++], mem); + /* VAL may have been promoted to a wider mode. Shrink it if so. */ + create_convert_operand_to (&ops[op_counter++], val, mode, true); + + if (maybe_expand_insn (icode, num_ops, ops)) + return ((target == const0_rtx) ? const0_rtx : ops[0].value); + + return NULL_RTX; +} - create_output_operand (&ops[0], target, mode); - create_fixed_operand (&ops[1], mem); - /* VAL may have been promoted to a wider mode. Shrink it if so. */ - create_convert_operand_to (&ops[2], val, mode, true); - if (maybe_expand_insn (icode, 3, ops)) - { - target = ops[0].value; - val = ops[2].value; - /* If we need to compensate for using an operation with the - wrong return value, do so now. */ - if (compensate) - { - if (!after) - { - if (code == PLUS) - code = MINUS; - else if (code == MINUS) - code = PLUS; - } - - if (code == NOT) - { - target = expand_simple_binop (mode, AND, target, val, - NULL_RTX, true, - OPTAB_LIB_WIDEN); - target = expand_simple_unop (mode, code, target, - NULL_RTX, true); - } - else - target = expand_simple_binop (mode, code, target, val, - NULL_RTX, true, - OPTAB_LIB_WIDEN); - } - return target; +/* This function expands an atomic fetch_OP or OP_fetch operation: + TARGET is an option place to stick the return value. const0_rtx indicates + the result is unused. + atomically fetch MEM, perform the operation with VAL and return it to MEM. + CODE is the operation being performed (OP) + MEMMODEL is the memory model variant to use. + AFTER is true to return the result of the operation (OP_fetch). + AFTER is false to return the value before the operation (fetch_OP). */ +rtx +expand_atomic_fetch_op (rtx target, rtx mem, rtx val, enum rtx_code code, + enum memmodel model, bool after) +{ + enum machine_mode mode = GET_MODE (mem); + const struct atomic_op_functions *optab; + rtx result; + bool unused_result = (target == const0_rtx); + + optab = get_atomic_op_for_code (code); + + /* Check for the case where the result isn't used and try those patterns. */ + if (unused_result) + { + /* Try the memory model variant first. */ + result = maybe_emit_op (optab, target, mem, val, true, model, true); + if (result) + return result; + + /* Next try the old style withuot a memory model. */ + result = maybe_emit_op (optab, target, mem, val, false, model, true); + if (result) + return result; + + /* There is no no-result pattern, so try patterns with a result. */ + target = NULL_RTX; + } + + /* Try the __atomic version. */ + result = maybe_emit_op (optab, target, mem, val, true, model, after); + if (result) + return result; + + /* Try the older __sync version. */ + result = maybe_emit_op (optab, target, mem, val, false, model, after); + if (result) + return result; + + /* If the fetch value can be calculated from the other variation of fetch, + try that operation. */ + if (after || optab->reverse_code != UNKNOWN || target == const0_rtx) + { + /* Try the __atomic version, then the older __sync version. */ + result = maybe_emit_op (optab, target, mem, val, true, model, !after); + if (!result) + result = maybe_emit_op (optab, target, mem, val, false, model, !after); + + if (result) + { + /* If the result isn't used, no need to do compensation code. */ + if (unused_result) + return target; + + /* Issue compensation code. Fetch_after == fetch_before OP val. + Fetch_before == after REVERSE_OP val. */ + if (!after) + code = optab->reverse_code; + result = expand_simple_binop (mode, code, result, val, NULL_RTX, true, + OPTAB_LIB_WIDEN); + return result; } } - /* Failing that, generate a compare-and-swap loop in which we perform the - operation with normal arithmetic instructions. */ - if (direct_optab_handler (sync_compare_and_swap_optab, mode) - != CODE_FOR_nothing) + /* If nothing else has succeeded, default to a compare and swap loop. */ + if (can_compare_and_swap_p (mode)) { + rtx insn; rtx t0 = gen_reg_rtx (mode), t1; - if (!target || !register_operand (target, mode)) - target = gen_reg_rtx (mode); - start_sequence (); - if (!after) - emit_move_insn (target, t0); + /* If the result is used, get a register for it. */ + if (!unused_result) + { + if (!target || !register_operand (target, mode)) + target = gen_reg_rtx (mode); + /* If fetch_before, copy the value now. */ + if (!after) + emit_move_insn (target, t0); + } + else + target = const0_rtx; + t1 = t0; if (code == NOT) - { + { t1 = expand_simple_binop (mode, AND, t1, val, NULL_RTX, true, OPTAB_LIB_WIDEN); t1 = expand_simple_unop (mode, code, t1, NULL_RTX, true); } else - t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, - true, OPTAB_LIB_WIDEN); - if (after) - emit_move_insn (target, t1); + t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX, true, + OPTAB_LIB_WIDEN); + /* For after, copy the value now. */ + if (!unused_result && after) + emit_move_insn (target, t1); insn = get_insns (); end_sequence (); if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn)) - return target; - } - - return NULL_RTX; -} - -/* This function expands a test-and-set operation. Ideally we atomically - store VAL in MEM and return the previous value in MEM. Some targets - may not support this operation and only support VAL with the constant 1; - in this case while the return value will be 0/1, but the exact value - stored in MEM is target defined. TARGET is an option place to stick - the return value. */ - -rtx -expand_sync_lock_test_and_set (rtx mem, rtx val, rtx target) -{ - enum machine_mode mode = GET_MODE (mem); - enum insn_code icode; - - /* If the target supports the test-and-set directly, great. */ - icode = direct_optab_handler (sync_lock_test_and_set_optab, mode); - if (icode != CODE_FOR_nothing) - { - struct expand_operand ops[3]; - - create_output_operand (&ops[0], target, mode); - create_fixed_operand (&ops[1], mem); - /* VAL may have been promoted to a wider mode. Shrink it if so. */ - create_convert_operand_to (&ops[2], val, mode, true); - if (maybe_expand_insn (icode, 3, ops)) - return ops[0].value; - } - - /* Otherwise, use a compare-and-swap loop for the exchange. */ - if (direct_optab_handler (sync_compare_and_swap_optab, mode) - != CODE_FOR_nothing) - { - if (!target || !register_operand (target, mode)) - target = gen_reg_rtx (mode); - if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode) - val = convert_modes (mode, GET_MODE (val), val, 1); - if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX)) - return target; + return target; } return NULL_RTX; @@ -7838,6 +7975,14 @@ maybe_gen_insn (enum insn_code icode, un case 6: return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, ops[3].value, ops[4].value, ops[5].value); + case 7: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, + ops[3].value, ops[4].value, ops[5].value, + ops[6].value); + case 8: + return GEN_FCN (icode) (ops[0].value, ops[1].value, ops[2].value, + ops[3].value, ops[4].value, ops[5].value, + ops[6].value, ops[7].value); } gcc_unreachable (); } Index: gcc/optabs.h =================================================================== --- gcc/optabs.h (.../trunk) (revision 180790) +++ gcc/optabs.h (.../branches/cxx-mem-model) (revision 180811) @@ -695,6 +695,34 @@ enum direct_optab_index /* Atomic clear with release semantics. */ DOI_sync_lock_release, + /* Atomic operations with memory model parameters. */ + DOI_atomic_exchange, + DOI_atomic_compare_and_swap, + DOI_atomic_load, + DOI_atomic_store, + DOI_atomic_add_fetch, + DOI_atomic_sub_fetch, + DOI_atomic_and_fetch, + DOI_atomic_nand_fetch, + DOI_atomic_xor_fetch, + DOI_atomic_or_fetch, + DOI_atomic_fetch_add, + DOI_atomic_fetch_sub, + DOI_atomic_fetch_and, + DOI_atomic_fetch_nand, + DOI_atomic_fetch_xor, + DOI_atomic_fetch_or, + DOI_atomic_add, + DOI_atomic_sub, + DOI_atomic_and, + DOI_atomic_nand, + DOI_atomic_xor, + DOI_atomic_or, + DOI_atomic_always_lock_free, + DOI_atomic_is_lock_free, + DOI_atomic_thread_fence, + DOI_atomic_signal_fence, + /* Vector permutation. */ DOI_vec_perm, DOI_vec_perm_const, @@ -744,6 +772,60 @@ typedef struct direct_optab_d *direct_op (&direct_optab_table[(int) DOI_sync_lock_test_and_set]) #define sync_lock_release_optab \ (&direct_optab_table[(int) DOI_sync_lock_release]) + +#define atomic_exchange_optab \ + (&direct_optab_table[(int) DOI_atomic_exchange]) +#define atomic_compare_and_swap_optab \ + (&direct_optab_table[(int) DOI_atomic_compare_and_swap]) +#define atomic_load_optab \ + (&direct_optab_table[(int) DOI_atomic_load]) +#define atomic_store_optab \ + (&direct_optab_table[(int) DOI_atomic_store]) +#define atomic_add_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_add_fetch]) +#define atomic_sub_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_sub_fetch]) +#define atomic_and_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_and_fetch]) +#define atomic_nand_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_nand_fetch]) +#define atomic_xor_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_xor_fetch]) +#define atomic_or_fetch_optab \ + (&direct_optab_table[(int) DOI_atomic_or_fetch]) +#define atomic_fetch_add_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_add]) +#define atomic_fetch_sub_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_sub]) +#define atomic_fetch_and_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_and]) +#define atomic_fetch_nand_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_nand]) +#define atomic_fetch_xor_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_xor]) +#define atomic_fetch_or_optab \ + (&direct_optab_table[(int) DOI_atomic_fetch_or]) +#define atomic_add_optab \ + (&direct_optab_table[(int) DOI_atomic_add]) +#define atomic_sub_optab \ + (&direct_optab_table[(int) DOI_atomic_sub]) +#define atomic_and_optab \ + (&direct_optab_table[(int) DOI_atomic_and]) +#define atomic_nand_optab \ + (&direct_optab_table[(int) DOI_atomic_nand]) +#define atomic_xor_optab \ + (&direct_optab_table[(int) DOI_atomic_xor]) +#define atomic_or_optab \ + (&direct_optab_table[(int) DOI_atomic_or]) +#define atomic_always_lock_free_optab \ + (&direct_optab_table[(int) DOI_atomic_always_lock_free]) +#define atomic_is_lock_free_optab \ + (&direct_optab_table[(int) DOI_atomic_is_lock_free]) +#define atomic_thread_fence_optab \ + (&direct_optab_table[(int) DOI_atomic_thread_fence]) +#define atomic_signal_fence_optab \ + (&direct_optab_table[(int) DOI_atomic_signal_fence]) + #define vec_perm_optab (&direct_optab_table[DOI_vec_perm]) #define vec_perm_const_optab (&direct_optab_table[(int) DOI_vec_perm_const]) @@ -883,6 +965,13 @@ extern void expand_float (rtx, rtx, int) /* Return the insn_code for a FLOAT_EXPR. */ enum insn_code can_float_p (enum machine_mode, enum machine_mode, int); +/* Return true if there is an inline compare and swap pattern. */ +extern bool can_compare_and_swap_p (enum machine_mode); + +/* Generate code for a compare and swap. */ +extern bool expand_atomic_compare_and_swap (rtx *, rtx *, rtx, rtx, rtx, bool, + enum memmodel, enum memmodel); + /* Check whether an operation represented by the code CODE is a convert operation that is supported by the target platform in vector form */ Index: gcc/genopinit.c =================================================================== --- gcc/genopinit.c (.../trunk) (revision 180790) +++ gcc/genopinit.c (.../branches/cxx-mem-model) (revision 180811) @@ -243,6 +243,28 @@ static const char * const optabs[] = "set_direct_optab_handler (sync_compare_and_swap_optab, $A, CODE_FOR_$(sync_compare_and_swap$I$a$))", "set_direct_optab_handler (sync_lock_test_and_set_optab, $A, CODE_FOR_$(sync_lock_test_and_set$I$a$))", "set_direct_optab_handler (sync_lock_release_optab, $A, CODE_FOR_$(sync_lock_release$I$a$))", + "set_direct_optab_handler (atomic_exchange_optab, $A, CODE_FOR_$(atomic_exchange$I$a$))", + "set_direct_optab_handler (atomic_compare_and_swap_optab, $A, CODE_FOR_$(atomic_compare_and_swap$I$a$))", + "set_direct_optab_handler (atomic_load_optab, $A, CODE_FOR_$(atomic_load$I$a$))", + "set_direct_optab_handler (atomic_store_optab, $A, CODE_FOR_$(atomic_store$I$a$))", + "set_direct_optab_handler (atomic_add_fetch_optab, $A, CODE_FOR_$(atomic_add_fetch$I$a$))", + "set_direct_optab_handler (atomic_sub_fetch_optab, $A, CODE_FOR_$(atomic_sub_fetch$I$a$))", + "set_direct_optab_handler (atomic_and_fetch_optab, $A, CODE_FOR_$(atomic_and_fetch$I$a$))", + "set_direct_optab_handler (atomic_nand_fetch_optab, $A, CODE_FOR_$(atomic_nand_fetch$I$a$))", + "set_direct_optab_handler (atomic_xor_fetch_optab, $A, CODE_FOR_$(atomic_xor_fetch$I$a$))", + "set_direct_optab_handler (atomic_or_fetch_optab, $A, CODE_FOR_$(atomic_or_fetch$I$a$))", + "set_direct_optab_handler (atomic_fetch_add_optab, $A, CODE_FOR_$(atomic_fetch_add$I$a$))", + "set_direct_optab_handler (atomic_fetch_sub_optab, $A, CODE_FOR_$(atomic_fetch_sub$I$a$))", + "set_direct_optab_handler (atomic_fetch_and_optab, $A, CODE_FOR_$(atomic_fetch_and$I$a$))", + "set_direct_optab_handler (atomic_fetch_nand_optab, $A, CODE_FOR_$(atomic_fetch_nand$I$a$))", + "set_direct_optab_handler (atomic_fetch_xor_optab, $A, CODE_FOR_$(atomic_fetch_xor$I$a$))", + "set_direct_optab_handler (atomic_fetch_or_optab, $A, CODE_FOR_$(atomic_fetch_or$I$a$))", + "set_direct_optab_handler (atomic_add_optab, $A, CODE_FOR_$(atomic_add$I$a$))", + "set_direct_optab_handler (atomic_sub_optab, $A, CODE_FOR_$(atomic_sub$I$a$))", + "set_direct_optab_handler (atomic_and_optab, $A, CODE_FOR_$(atomic_and$I$a$))", + "set_direct_optab_handler (atomic_nand_optab, $A, CODE_FOR_$(atomic_nand$I$a$))", + "set_direct_optab_handler (atomic_xor_optab, $A, CODE_FOR_$(atomic_xor$I$a$))", + "set_direct_optab_handler (atomic_or_optab, $A, CODE_FOR_$(atomic_or$I$a$))", "set_optab_handler (vec_set_optab, $A, CODE_FOR_$(vec_set$a$))", "set_optab_handler (vec_extract_optab, $A, CODE_FOR_$(vec_extract$a$))", "set_optab_handler (vec_extract_even_optab, $A, CODE_FOR_$(vec_extract_even$a$))", Index: gcc/builtins.c =================================================================== --- gcc/builtins.c (.../trunk) (revision 180790) +++ gcc/builtins.c (.../branches/cxx-mem-model) (revision 180811) @@ -223,6 +223,7 @@ static tree do_mpfr_bessel_n (tree, tree const REAL_VALUE_TYPE *, bool); static tree do_mpfr_remquo (tree, tree, tree); static tree do_mpfr_lgamma_r (tree, tree, tree); +static void expand_builtin_sync_synchronize (void); /* Return true if NAME starts with __builtin_ or __sync_. */ @@ -233,6 +234,8 @@ is_builtin_name (const char *name) return true; if (strncmp (name, "__sync_", 7) == 0) return true; + if (strncmp (name, "__atomic_", 9) == 0) + return true; return false; } @@ -5090,21 +5093,41 @@ get_builtin_sync_mem (tree loc, enum mac return mem; } +/* Make sure an argument is in the right mode. + EXP is the tree argument. + MODE is the mode it should be in. */ + +static rtx +expand_expr_force_mode (tree exp, enum machine_mode mode) +{ + rtx val; + enum machine_mode old_mode; + + val = expand_expr (exp, NULL_RTX, mode, EXPAND_NORMAL); + /* If VAL is promoted to a wider mode, convert it back to MODE. Take care + of CONST_INTs, where we know the old_mode only from the call argument. */ + + old_mode = GET_MODE (val); + if (old_mode == VOIDmode) + old_mode = TYPE_MODE (TREE_TYPE (exp)); + val = convert_modes (mode, old_mode, val, 1); + return val; +} + + /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics. EXP is the CALL_EXPR. CODE is the rtx code that corresponds to the arithmetic or logical operation from the name; an exception here is that NOT actually means NAND. TARGET is an optional place for us to store the results; AFTER is true if this is the - fetch_and_xxx form. IGNORE is true if we don't actually care about - the result of the operation at all. */ + fetch_and_xxx form. */ static rtx expand_builtin_sync_operation (enum machine_mode mode, tree exp, enum rtx_code code, bool after, - rtx target, bool ignore) + rtx target) { rtx val, mem; - enum machine_mode old_mode; location_t loc = EXPR_LOCATION (exp); if (code == NOT && warn_sync_nand) @@ -5151,19 +5174,10 @@ expand_builtin_sync_operation (enum mach /* Expand the operands. */ mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); - val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))); - val = convert_modes (mode, old_mode, val, 1); - - if (ignore) - return expand_sync_operation (mem, val, code); - else - return expand_sync_fetch_operation (mem, val, code, after, target); + return expand_atomic_fetch_op (target, mem, val, code, MEMMODEL_SEQ_CST, + after); } /* Expand the __sync_val_compare_and_swap and __sync_bool_compare_and_swap @@ -5176,34 +5190,19 @@ expand_builtin_compare_and_swap (enum ma bool is_bool, rtx target) { rtx old_val, new_val, mem; - enum machine_mode old_mode; /* Expand the operands. */ mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + old_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); + new_val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode); + if (!expand_atomic_compare_and_swap ((is_bool ? &target : NULL), + (is_bool ? NULL : &target), + mem, old_val, new_val, false, + MEMMODEL_SEQ_CST, MEMMODEL_SEQ_CST)) + return NULL_RTX; - old_val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, - mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (old_val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))); - old_val = convert_modes (mode, old_mode, old_val, 1); - - new_val = expand_expr (CALL_EXPR_ARG (exp, 2), NULL_RTX, - mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (new_val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 2))); - new_val = convert_modes (mode, old_mode, new_val, 1); - - if (is_bool) - return expand_bool_compare_and_swap (mem, old_val, new_val, target); - else - return expand_val_compare_and_swap (mem, old_val, new_val, target); + return target; } /* Expand the __sync_lock_test_and_set intrinsic. Note that the most @@ -5214,22 +5213,436 @@ expand_builtin_compare_and_swap (enum ma static rtx expand_builtin_sync_lock_test_and_set (enum machine_mode mode, tree exp, - rtx target) + rtx target) { rtx val, mem; - enum machine_mode old_mode; /* Expand the operands. */ mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); - val = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, mode, EXPAND_NORMAL); - /* If VAL is promoted to a wider mode, convert it back to MODE. Take care - of CONST_INTs, where we know the old_mode only from the call argument. */ - old_mode = GET_MODE (val); - if (old_mode == VOIDmode) - old_mode = TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))); - val = convert_modes (mode, old_mode, val, 1); + val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); + + return expand_atomic_exchange (target, mem, val, MEMMODEL_ACQUIRE); +} + +/* Expand the __sync_lock_release intrinsic. EXP is the CALL_EXPR. */ + +static void +expand_builtin_sync_lock_release (enum machine_mode mode, tree exp) +{ + rtx mem; + + /* Expand the operands. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + + expand_atomic_store (mem, const0_rtx, MEMMODEL_RELEASE); +} + +/* Given an integer representing an ``enum memmodel'', verify its + correctness and return the memory model enum. */ + +static enum memmodel +get_memmodel (tree exp) +{ + rtx op; + + /* If the parameter is not a constant, it's a run time value so we'll just + convert it to MEMMODEL_SEQ_CST to avoid annoying runtime checking. */ + if (TREE_CODE (exp) != INTEGER_CST) + return MEMMODEL_SEQ_CST; + + op = expand_normal (exp); + if (INTVAL (op) < 0 || INTVAL (op) >= MEMMODEL_LAST) + { + error ("invalid memory model argument to builtin"); + return MEMMODEL_SEQ_CST; + } + return (enum memmodel) INTVAL (op); +} + +/* Expand the __atomic_exchange intrinsic: + TYPE __atomic_exchange (TYPE *object, TYPE desired, enum memmodel) + EXP is the CALL_EXPR. + TARGET is an optional place for us to store the results. */ + +static rtx +expand_builtin_atomic_exchange (enum machine_mode mode, tree exp, rtx target) +{ + rtx val, mem; + enum memmodel model; + + model = get_memmodel (CALL_EXPR_ARG (exp, 2)); + if (model == MEMMODEL_CONSUME) + { + error ("invalid memory model for %<__atomic_exchange%>"); + return NULL_RTX; + } + + if (!flag_inline_atomics) + return NULL_RTX; + + /* Expand the operands. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); + + return expand_atomic_exchange (target, mem, val, model); +} + +/* Expand the __atomic_compare_exchange intrinsic: + bool __atomic_compare_exchange (TYPE *object, TYPE *expect, + TYPE desired, BOOL weak, + enum memmodel success, + enum memmodel failure) + EXP is the CALL_EXPR. + TARGET is an optional place for us to store the results. */ + +static rtx +expand_builtin_atomic_compare_exchange (enum machine_mode mode, tree exp, + rtx target) +{ + rtx expect, desired, mem, oldval; + enum memmodel success, failure; + tree weak; + bool is_weak; + + success = get_memmodel (CALL_EXPR_ARG (exp, 4)); + failure = get_memmodel (CALL_EXPR_ARG (exp, 5)); + + if (failure == MEMMODEL_RELEASE || failure == MEMMODEL_ACQ_REL) + { + error ("invalid failure memory model for %<__atomic_compare_exchange%>"); + return NULL_RTX; + } + + if (failure > success) + { + error ("failure memory model cannot be stronger than success " + "memory model for %<__atomic_compare_exchange%>"); + return NULL_RTX; + } + + if (!flag_inline_atomics) + return NULL_RTX; + + /* Expand the operands. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + + expect = expand_normal (CALL_EXPR_ARG (exp, 1)); + expect = convert_memory_address (Pmode, expect); + desired = expand_expr_force_mode (CALL_EXPR_ARG (exp, 2), mode); + + weak = CALL_EXPR_ARG (exp, 3); + is_weak = false; + if (host_integerp (weak, 0) && tree_low_cst (weak, 0) != 0) + is_weak = true; + + oldval = copy_to_reg (gen_rtx_MEM (mode, expect)); + + if (!expand_atomic_compare_and_swap (&target, &oldval, mem, oldval, + desired, is_weak, success, failure)) + return NULL_RTX; + + emit_move_insn (gen_rtx_MEM (mode, expect), oldval); + return target; +} + +/* Expand the __atomic_load intrinsic: + TYPE __atomic_load (TYPE *object, enum memmodel) + EXP is the CALL_EXPR. + TARGET is an optional place for us to store the results. */ + +static rtx +expand_builtin_atomic_load (enum machine_mode mode, tree exp, rtx target) +{ + rtx mem; + enum memmodel model; + + model = get_memmodel (CALL_EXPR_ARG (exp, 1)); + if (model == MEMMODEL_RELEASE + || model == MEMMODEL_ACQ_REL) + { + error ("invalid memory model for %<__atomic_load%>"); + return NULL_RTX; + } + + if (!flag_inline_atomics) + return NULL_RTX; + + /* Expand the operand. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + + return expand_atomic_load (target, mem, model); +} + + +/* Expand the __atomic_store intrinsic: + void __atomic_store (TYPE *object, TYPE desired, enum memmodel) + EXP is the CALL_EXPR. + TARGET is an optional place for us to store the results. */ + +static rtx +expand_builtin_atomic_store (enum machine_mode mode, tree exp) +{ + rtx mem, val; + enum memmodel model; + + model = get_memmodel (CALL_EXPR_ARG (exp, 2)); + if (model != MEMMODEL_RELAXED + && model != MEMMODEL_SEQ_CST + && model != MEMMODEL_RELEASE) + { + error ("invalid memory model for %<__atomic_store%>"); + return NULL_RTX; + } + + if (!flag_inline_atomics) + return NULL_RTX; + + /* Expand the operands. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); + + return expand_atomic_store (mem, val, model); +} + +/* Expand the __atomic_fetch_XXX intrinsic: + TYPE __atomic_fetch_XXX (TYPE *object, TYPE val, enum memmodel) + EXP is the CALL_EXPR. + TARGET is an optional place for us to store the results. + CODE is the operation, PLUS, MINUS, ADD, XOR, or IOR. + FETCH_AFTER is true if returning the result of the operation. + FETCH_AFTER is false if returning the value before the operation. + IGNORE is true if the result is not used. + EXT_CALL is the correct builtin for an external call if this cannot be + resolved to an instruction sequence. */ + +static rtx +expand_builtin_atomic_fetch_op (enum machine_mode mode, tree exp, rtx target, + enum rtx_code code, bool fetch_after, + bool ignore, enum built_in_function ext_call) +{ + rtx val, mem, ret; + enum memmodel model; + tree fndecl; + tree addr; + + model = get_memmodel (CALL_EXPR_ARG (exp, 2)); + + /* Expand the operands. */ + mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); + val = expand_expr_force_mode (CALL_EXPR_ARG (exp, 1), mode); + + /* Only try generating instructions if inlining is turned on. */ + if (flag_inline_atomics) + { + ret = expand_atomic_fetch_op (target, mem, val, code, model, fetch_after); + if (ret) + return ret; + } + + /* Return if a different routine isn't needed for the library call. */ + if (ext_call == BUILT_IN_NONE) + return NULL_RTX; + + /* Change the call to the specified function. */ + fndecl = get_callee_fndecl (exp); + addr = CALL_EXPR_FN (exp); + STRIP_NOPS (addr); + + gcc_assert (TREE_OPERAND (addr, 0) == fndecl); + TREE_OPERAND (addr, 0) = builtin_decl_explicit(ext_call); + + /* Expand the call here so we can emit trailing code. */ + ret = expand_call (exp, target, ignore); + + /* Replace the original function just in case it matters. */ + TREE_OPERAND (addr, 0) = fndecl; + + /* Then issue the arithmetic correction to return the right result. */ + if (!ignore) + ret = expand_simple_binop (mode, code, ret, val, NULL_RTX, true, + OPTAB_LIB_WIDEN); + return ret; +} + +/* Return true if (optional) argument ARG1 of size ARG0 is always lock free on + this architecture. If ARG1 is NULL, use typical alignment for size ARG0. */ + +static tree +fold_builtin_atomic_always_lock_free (tree arg0, tree arg1) +{ + int size; + enum machine_mode mode; + unsigned int mode_align, type_align; + + if (TREE_CODE (arg0) != INTEGER_CST) + return NULL_TREE; + + size = INTVAL (expand_normal (arg0)) * BITS_PER_UNIT; + mode = mode_for_size (size, MODE_INT, 0); + mode_align = GET_MODE_ALIGNMENT (mode); - return expand_sync_lock_test_and_set (mem, val, target); + if (TREE_CODE (arg1) == INTEGER_CST && INTVAL (expand_normal (arg1)) == 0) + type_align = mode_align; + else + { + tree ttype = TREE_TYPE (arg1); + + /* This function is usually invoked and folded immediately by the front + end before anything else has a chance to look at it. The pointer + parameter at this point is usually cast to a void *, so check for that + and look past the cast. */ + if (TREE_CODE (arg1) == NOP_EXPR && POINTER_TYPE_P (ttype) + && VOID_TYPE_P (TREE_TYPE (ttype))) + arg1 = TREE_OPERAND (arg1, 0); + + ttype = TREE_TYPE (arg1); + gcc_assert (POINTER_TYPE_P (ttype)); + + /* Get the underlying type of the object. */ + ttype = TREE_TYPE (ttype); + type_align = TYPE_ALIGN (ttype); + } + + /* If the object has smaller alignment, the the lock free routines cannot + be used. */ + if (type_align < mode_align) + return integer_zero_node; + + /* Check if a compare_and_swap pattern exists for the mode which represents + the required size. The pattern is not allowed to fail, so the existence + of the pattern indicates support is present. */ + if (can_compare_and_swap_p (mode)) + return integer_one_node; + else + return integer_zero_node; +} + +/* Return true if the parameters to call EXP represent an object which will + always generate lock free instructions. The first argument represents the + size of the object, and the second parameter is a pointer to the object + itself. If NULL is passed for the object, then the result is based on + typical alignment for an object of the specified size. Otherwise return + false. */ + +static rtx +expand_builtin_atomic_always_lock_free (tree exp) +{ + tree size; + tree arg0 = CALL_EXPR_ARG (exp, 0); + tree arg1 = CALL_EXPR_ARG (exp, 1); + + if (TREE_CODE (arg0) != INTEGER_CST) + { + error ("non-constant argument 1 to __atomic_always_lock_free"); + return const0_rtx; + } + + size = fold_builtin_atomic_always_lock_free (arg0, arg1); + if (size == integer_one_node) + return const1_rtx; + return const0_rtx; +} + +/* Return a one or zero if it can be determined that object ARG1 of size ARG + is lock free on this architecture. */ + +static tree +fold_builtin_atomic_is_lock_free (tree arg0, tree arg1) +{ + if (!flag_inline_atomics) + return NULL_TREE; + + /* If it isn't always lock free, don't generate a result. */ + if (fold_builtin_atomic_always_lock_free (arg0, arg1) == integer_one_node) + return integer_one_node; + + return NULL_TREE; +} + +/* Return true if the parameters to call EXP represent an object which will + always generate lock free instructions. The first argument represents the + size of the object, and the second parameter is a pointer to the object + itself. If NULL is passed for the object, then the result is based on + typical alignment for an object of the specified size. Otherwise return + NULL*/ + +static rtx +expand_builtin_atomic_is_lock_free (tree exp) +{ + tree size; + tree arg0 = CALL_EXPR_ARG (exp, 0); + tree arg1 = CALL_EXPR_ARG (exp, 1); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))) + { + error ("non-integer argument 1 to __atomic_is_lock_free"); + return NULL_RTX; + } + + if (!flag_inline_atomics) + return NULL_RTX; + + /* If the value is known at compile time, return the RTX for it. */ + size = fold_builtin_atomic_is_lock_free (arg0, arg1); + if (size == integer_one_node) + return const1_rtx; + + return NULL_RTX; +} + +/* This routine will either emit the mem_thread_fence pattern or issue a + sync_synchronize to generate a fence for memory model MEMMODEL. */ + +void +expand_builtin_mem_thread_fence (enum memmodel model) +{ + if (model == MEMMODEL_RELAXED) + return; +#ifdef HAVE_mem_thread_fence + emit_insn (gen_mem_thread_fence (GEN_INT (model))); +#else + expand_builtin_sync_synchronize (); +#endif +} + +/* Expand the __atomic_thread_fence intrinsic: + void __atomic_thread_fence (enum memmodel) + EXP is the CALL_EXPR. */ + +static void +expand_builtin_atomic_thread_fence (tree exp) +{ + enum memmodel model; + + model = get_memmodel (CALL_EXPR_ARG (exp, 0)); + expand_builtin_mem_thread_fence (model); +} + +/* This routine will either emit the mem_signal_fence pattern or issue a + sync_synchronize to generate a fence for memory model MEMMODEL. */ + +static void +expand_builtin_mem_signal_fence (enum memmodel model) +{ +#ifdef HAVE_mem_signal_fence + emit_insn (gen_mem_signal_fence (memmodel)); +#else + if (model != MEMMODEL_RELAXED) + expand_builtin_sync_synchronize (); +#endif +} + +/* Expand the __atomic_signal_fence intrinsic: + void __atomic_signal_fence (enum memmodel) + EXP is the CALL_EXPR. */ + +static void +expand_builtin_atomic_signal_fence (tree exp) +{ + enum memmodel model; + + model = get_memmodel (CALL_EXPR_ARG (exp, 0)); + expand_builtin_mem_signal_fence (model); } /* Expand the __sync_synchronize intrinsic. */ @@ -5264,33 +5677,6 @@ expand_builtin_sync_synchronize (void) expand_asm_stmt (x); } -/* Expand the __sync_lock_release intrinsic. EXP is the CALL_EXPR. */ - -static void -expand_builtin_sync_lock_release (enum machine_mode mode, tree exp) -{ - struct expand_operand ops[2]; - enum insn_code icode; - rtx mem; - - /* Expand the operands. */ - mem = get_builtin_sync_mem (CALL_EXPR_ARG (exp, 0), mode); - - /* If there is an explicit operation in the md file, use it. */ - icode = direct_optab_handler (sync_lock_release_optab, mode); - if (icode != CODE_FOR_nothing) - { - create_fixed_operand (&ops[0], mem); - create_input_operand (&ops[1], const0_rtx, mode); - if (maybe_expand_insn (icode, 2, ops)) - return; - } - - /* Otherwise we can implement this operation by emitting a barrier - followed by a store of zero. */ - expand_builtin_sync_synchronize (); - emit_move_insn (mem, const0_rtx); -} /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient @@ -5891,8 +6277,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_ADD_8: case BUILT_IN_SYNC_FETCH_AND_ADD_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_ADD_1); - target = expand_builtin_sync_operation (mode, exp, PLUS, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, PLUS, false, target); if (target) return target; break; @@ -5903,8 +6288,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_SUB_8: case BUILT_IN_SYNC_FETCH_AND_SUB_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_SUB_1); - target = expand_builtin_sync_operation (mode, exp, MINUS, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, MINUS, false, target); if (target) return target; break; @@ -5915,8 +6299,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_OR_8: case BUILT_IN_SYNC_FETCH_AND_OR_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_OR_1); - target = expand_builtin_sync_operation (mode, exp, IOR, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, IOR, false, target); if (target) return target; break; @@ -5927,8 +6310,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_AND_8: case BUILT_IN_SYNC_FETCH_AND_AND_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_AND_1); - target = expand_builtin_sync_operation (mode, exp, AND, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, AND, false, target); if (target) return target; break; @@ -5939,8 +6321,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_XOR_8: case BUILT_IN_SYNC_FETCH_AND_XOR_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_XOR_1); - target = expand_builtin_sync_operation (mode, exp, XOR, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, XOR, false, target); if (target) return target; break; @@ -5951,8 +6332,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_FETCH_AND_NAND_8: case BUILT_IN_SYNC_FETCH_AND_NAND_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_FETCH_AND_NAND_1); - target = expand_builtin_sync_operation (mode, exp, NOT, - false, target, ignore); + target = expand_builtin_sync_operation (mode, exp, NOT, false, target); if (target) return target; break; @@ -5963,8 +6343,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_ADD_AND_FETCH_8: case BUILT_IN_SYNC_ADD_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_ADD_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, PLUS, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, PLUS, true, target); if (target) return target; break; @@ -5975,8 +6354,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_SUB_AND_FETCH_8: case BUILT_IN_SYNC_SUB_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_SUB_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, MINUS, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, MINUS, true, target); if (target) return target; break; @@ -5987,8 +6365,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_OR_AND_FETCH_8: case BUILT_IN_SYNC_OR_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_OR_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, IOR, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, IOR, true, target); if (target) return target; break; @@ -5999,8 +6376,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_AND_AND_FETCH_8: case BUILT_IN_SYNC_AND_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_AND_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, AND, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, AND, true, target); if (target) return target; break; @@ -6011,8 +6387,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_XOR_AND_FETCH_8: case BUILT_IN_SYNC_XOR_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_XOR_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, XOR, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, XOR, true, target); if (target) return target; break; @@ -6023,8 +6398,7 @@ expand_builtin (tree exp, rtx target, rt case BUILT_IN_SYNC_NAND_AND_FETCH_8: case BUILT_IN_SYNC_NAND_AND_FETCH_16: mode = get_builtin_sync_mode (fcode - BUILT_IN_SYNC_NAND_AND_FETCH_1); - target = expand_builtin_sync_operation (mode, exp, NOT, - true, target, ignore); + target = expand_builtin_sync_operation (mode, exp, NOT, true, target); if (target) return target; break; @@ -6082,6 +6456,236 @@ expand_builtin (tree exp, rtx target, rt expand_builtin_sync_synchronize (); return const0_rtx; + case BUILT_IN_ATOMIC_EXCHANGE_1: + case BUILT_IN_ATOMIC_EXCHANGE_2: + case BUILT_IN_ATOMIC_EXCHANGE_4: + case BUILT_IN_ATOMIC_EXCHANGE_8: + case BUILT_IN_ATOMIC_EXCHANGE_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_EXCHANGE_1); + target = expand_builtin_atomic_exchange (mode, exp, target); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8: + case BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16: + mode = + get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1); + target = expand_builtin_atomic_compare_exchange (mode, exp, target); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_LOAD_1: + case BUILT_IN_ATOMIC_LOAD_2: + case BUILT_IN_ATOMIC_LOAD_4: + case BUILT_IN_ATOMIC_LOAD_8: + case BUILT_IN_ATOMIC_LOAD_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_LOAD_1); + target = expand_builtin_atomic_load (mode, exp, target); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_STORE_1: + case BUILT_IN_ATOMIC_STORE_2: + case BUILT_IN_ATOMIC_STORE_4: + case BUILT_IN_ATOMIC_STORE_8: + case BUILT_IN_ATOMIC_STORE_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_STORE_1); + target = expand_builtin_atomic_store (mode, exp); + if (target) + return const0_rtx; + break; + + case BUILT_IN_ATOMIC_ADD_FETCH_1: + case BUILT_IN_ATOMIC_ADD_FETCH_2: + case BUILT_IN_ATOMIC_ADD_FETCH_4: + case BUILT_IN_ATOMIC_ADD_FETCH_8: + case BUILT_IN_ATOMIC_ADD_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_ADD_1 + + (fcode - BUILT_IN_ATOMIC_ADD_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_SUB_FETCH_1: + case BUILT_IN_ATOMIC_SUB_FETCH_2: + case BUILT_IN_ATOMIC_SUB_FETCH_4: + case BUILT_IN_ATOMIC_SUB_FETCH_8: + case BUILT_IN_ATOMIC_SUB_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_SUB_1 + + (fcode - BUILT_IN_ATOMIC_SUB_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_AND_FETCH_1: + case BUILT_IN_ATOMIC_AND_FETCH_2: + case BUILT_IN_ATOMIC_AND_FETCH_4: + case BUILT_IN_ATOMIC_AND_FETCH_8: + case BUILT_IN_ATOMIC_AND_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_AND_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_AND_1 + + (fcode - BUILT_IN_ATOMIC_AND_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_NAND_FETCH_1: + case BUILT_IN_ATOMIC_NAND_FETCH_2: + case BUILT_IN_ATOMIC_NAND_FETCH_4: + case BUILT_IN_ATOMIC_NAND_FETCH_8: + case BUILT_IN_ATOMIC_NAND_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_NAND_1 + + (fcode - BUILT_IN_ATOMIC_NAND_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_XOR_FETCH_1: + case BUILT_IN_ATOMIC_XOR_FETCH_2: + case BUILT_IN_ATOMIC_XOR_FETCH_4: + case BUILT_IN_ATOMIC_XOR_FETCH_8: + case BUILT_IN_ATOMIC_XOR_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_XOR_1 + + (fcode - BUILT_IN_ATOMIC_XOR_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_OR_FETCH_1: + case BUILT_IN_ATOMIC_OR_FETCH_2: + case BUILT_IN_ATOMIC_OR_FETCH_4: + case BUILT_IN_ATOMIC_OR_FETCH_8: + case BUILT_IN_ATOMIC_OR_FETCH_16: + { + enum built_in_function lib; + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_OR_FETCH_1); + lib = (enum built_in_function)((int)BUILT_IN_ATOMIC_FETCH_OR_1 + + (fcode - BUILT_IN_ATOMIC_OR_FETCH_1)); + target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, true, + ignore, lib); + if (target) + return target; + break; + } + case BUILT_IN_ATOMIC_FETCH_ADD_1: + case BUILT_IN_ATOMIC_FETCH_ADD_2: + case BUILT_IN_ATOMIC_FETCH_ADD_4: + case BUILT_IN_ATOMIC_FETCH_ADD_8: + case BUILT_IN_ATOMIC_FETCH_ADD_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_ADD_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, PLUS, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_FETCH_SUB_1: + case BUILT_IN_ATOMIC_FETCH_SUB_2: + case BUILT_IN_ATOMIC_FETCH_SUB_4: + case BUILT_IN_ATOMIC_FETCH_SUB_8: + case BUILT_IN_ATOMIC_FETCH_SUB_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_SUB_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, MINUS, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_FETCH_AND_1: + case BUILT_IN_ATOMIC_FETCH_AND_2: + case BUILT_IN_ATOMIC_FETCH_AND_4: + case BUILT_IN_ATOMIC_FETCH_AND_8: + case BUILT_IN_ATOMIC_FETCH_AND_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_AND_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, AND, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_FETCH_NAND_1: + case BUILT_IN_ATOMIC_FETCH_NAND_2: + case BUILT_IN_ATOMIC_FETCH_NAND_4: + case BUILT_IN_ATOMIC_FETCH_NAND_8: + case BUILT_IN_ATOMIC_FETCH_NAND_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_NAND_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, NOT, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_FETCH_XOR_1: + case BUILT_IN_ATOMIC_FETCH_XOR_2: + case BUILT_IN_ATOMIC_FETCH_XOR_4: + case BUILT_IN_ATOMIC_FETCH_XOR_8: + case BUILT_IN_ATOMIC_FETCH_XOR_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_XOR_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, XOR, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_FETCH_OR_1: + case BUILT_IN_ATOMIC_FETCH_OR_2: + case BUILT_IN_ATOMIC_FETCH_OR_4: + case BUILT_IN_ATOMIC_FETCH_OR_8: + case BUILT_IN_ATOMIC_FETCH_OR_16: + mode = get_builtin_sync_mode (fcode - BUILT_IN_ATOMIC_FETCH_OR_1); + target = expand_builtin_atomic_fetch_op (mode, exp, target, IOR, false, + ignore, BUILT_IN_NONE); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE: + return expand_builtin_atomic_always_lock_free (exp); + + case BUILT_IN_ATOMIC_IS_LOCK_FREE: + target = expand_builtin_atomic_is_lock_free (exp); + if (target) + return target; + break; + + case BUILT_IN_ATOMIC_THREAD_FENCE: + expand_builtin_atomic_thread_fence (exp); + return const0_rtx; + + case BUILT_IN_ATOMIC_SIGNAL_FENCE: + expand_builtin_atomic_signal_fence (exp); + return const0_rtx; + case BUILT_IN_OBJECT_SIZE: return expand_builtin_object_size (exp); @@ -10121,6 +10725,12 @@ fold_builtin_2 (location_t loc, tree fnd return fold_builtin_fprintf (loc, fndecl, arg0, arg1, NULL_TREE, ignore, fcode); + case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE: + return fold_builtin_atomic_always_lock_free (arg0, arg1); + + case BUILT_IN_ATOMIC_IS_LOCK_FREE: + return fold_builtin_atomic_is_lock_free (arg0, arg1); + default: break; } Index: gcc/sync-builtins.def =================================================================== --- gcc/sync-builtins.def (.../trunk) (revision 180790) +++ gcc/sync-builtins.def (.../branches/cxx-mem-model) (revision 180811) @@ -256,3 +256,341 @@ DEF_SYNC_BUILTIN (BUILT_IN_SYNC_LOCK_REL DEF_SYNC_BUILTIN (BUILT_IN_SYNC_SYNCHRONIZE, "__sync_synchronize", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) + +/* __sync* builtins for the C++ memory model. */ + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE, + "__atomic_exchange", + BT_FN_VOID_SIZE_VPTR_PTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_N, + "__atomic_exchange_n", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_1, + "__atomic_exchange_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_2, + "__atomic_exchange_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_4, + "__atomic_exchange_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_8, + "__atomic_exchange_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_EXCHANGE_16, + "__atomic_exchange_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD, + "__atomic_load", + BT_FN_VOID_SIZE_CONST_VPTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_N, + "__atomic_load_n", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_1, + "__atomic_load_1", + BT_FN_I1_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_2, + "__atomic_load_2", + BT_FN_I2_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_4, + "__atomic_load_4", + BT_FN_I4_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_8, + "__atomic_load_8", + BT_FN_I8_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_LOAD_16, + "__atomic_load_16", + BT_FN_I16_CONST_VPTR_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE, + "__atomic_compare_exchange", + BT_FN_BOOL_SIZE_VPTR_PTR_PTR_INT_INT, + ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N, + "__atomic_compare_exchange_n", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_1, + "__atomic_compare_exchange_1", + BT_FN_BOOL_VPTR_PTR_I1_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_2, + "__atomic_compare_exchange_2", + BT_FN_BOOL_VPTR_PTR_I2_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4, + "__atomic_compare_exchange_4", + BT_FN_BOOL_VPTR_PTR_I4_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8, + "__atomic_compare_exchange_8", + BT_FN_BOOL_VPTR_PTR_I8_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_COMPARE_EXCHANGE_16, + "__atomic_compare_exchange_16", + BT_FN_BOOL_VPTR_PTR_I16_BOOL_INT_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE, + "__atomic_store", + BT_FN_VOID_SIZE_VPTR_PTR_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_N, + "__atomic_store_n", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_1, + "__atomic_store_1", + BT_FN_VOID_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_2, + "__atomic_store_2", + BT_FN_VOID_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_4, + "__atomic_store_4", + BT_FN_VOID_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_8, + "__atomic_store_8", + BT_FN_VOID_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_STORE_16, + "__atomic_store_16", + BT_FN_VOID_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_N, + "__atomic_add_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_1, + "__atomic_add_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_2, + "__atomic_add_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_4, + "__atomic_add_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_8, + "__atomic_add_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ADD_FETCH_16, + "__atomic_add_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_N, + "__atomic_sub_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_1, + "__atomic_sub_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_2, + "__atomic_sub_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_4, + "__atomic_sub_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_8, + "__atomic_sub_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SUB_FETCH_16, + "__atomic_sub_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_N, + "__atomic_and_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_1, + "__atomic_and_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_2, + "__atomic_and_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_4, + "__atomic_and_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_8, + "__atomic_and_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_AND_FETCH_16, + "__atomic_and_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_N, + "__atomic_nand_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_1, + "__atomic_nand_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_2, + "__atomic_nand_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_4, + "__atomic_nand_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_8, + "__atomic_nand_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_NAND_FETCH_16, + "__atomic_nand_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_N, + "__atomic_xor_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_1, + "__atomic_xor_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_2, + "__atomic_xor_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_4, + "__atomic_xor_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_8, + "__atomic_xor_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_XOR_FETCH_16, + "__atomic_xor_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_N, + "__atomic_or_fetch", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_1, + "__atomic_or_fetch_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_2, + "__atomic_or_fetch_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_4, + "__atomic_or_fetch_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_8, + "__atomic_or_fetch_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_OR_FETCH_16, + "__atomic_or_fetch_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_N, + "__atomic_fetch_add", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_1, + "__atomic_fetch_add_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_2, + "__atomic_fetch_add_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_4, + "__atomic_fetch_add_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_8, + "__atomic_fetch_add_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_ADD_16, + "__atomic_fetch_add_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_N, + "__atomic_fetch_sub", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_1, + "__atomic_fetch_sub_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_2, + "__atomic_fetch_sub_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_4, + "__atomic_fetch_sub_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_8, + "__atomic_fetch_sub_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_SUB_16, + "__atomic_fetch_sub_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_N, + "__atomic_fetch_and", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_1, + "__atomic_fetch_and_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_2, + "__atomic_fetch_and_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_4, + "__atomic_fetch_and_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_8, + "__atomic_fetch_and_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_AND_16, + "__atomic_fetch_and_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_N, + "__atomic_fetch_nand", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_1, + "__atomic_fetch_nand_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_2, + "__atomic_fetch_nand_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_4, + "__atomic_fetch_nand_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_8, + "__atomic_fetch_nand_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_NAND_16, + "__atomic_fetch_nand_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_N, + "__atomic_fetch_xor", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_1, + "__atomic_fetch_xor_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_2, + "__atomic_fetch_xor_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_4, + "__atomic_fetch_xor_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_8, + "__atomic_fetch_xor_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_XOR_16, + "__atomic_fetch_xor_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_N, + "__atomic_fetch_or", + BT_FN_VOID_VAR, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_1, + "__atomic_fetch_or_1", + BT_FN_I1_VPTR_I1_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_2, + "__atomic_fetch_or_2", + BT_FN_I2_VPTR_I2_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_4, + "__atomic_fetch_or_4", + BT_FN_I4_VPTR_I4_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_8, + "__atomic_fetch_or_8", + BT_FN_I8_VPTR_I8_INT, ATTR_NOTHROW_LEAF_LIST) +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FETCH_OR_16, + "__atomic_fetch_or_16", + BT_FN_I16_VPTR_I16_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE, + "__atomic_always_lock_free", + BT_FN_BOOL_SIZE_CONST_VPTR, ATTR_CONST_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_IS_LOCK_FREE, + "__atomic_is_lock_free", + BT_FN_BOOL_SIZE_CONST_VPTR, ATTR_CONST_NOTHROW_LEAF_LIST) + + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_THREAD_FENCE, + "__atomic_thread_fence", + BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST) + +DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SIGNAL_FENCE, + "__atomic_signal_fence", + BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST) + Index: gcc/params.h =================================================================== --- gcc/params.h (.../trunk) (revision 180790) +++ gcc/params.h (.../branches/cxx-mem-model) (revision 180811) @@ -211,6 +211,13 @@ extern void init_param_values (int *para PARAM_VALUE (PARAM_MIN_NONDEBUG_INSN_UID) #define MAX_STORES_TO_SINK \ PARAM_VALUE (PARAM_MAX_STORES_TO_SINK) +#define ALLOW_LOAD_DATA_RACES \ + PARAM_VALUE (PARAM_ALLOW_LOAD_DATA_RACES) #define ALLOW_STORE_DATA_RACES \ PARAM_VALUE (PARAM_ALLOW_STORE_DATA_RACES) +#define ALLOW_PACKED_LOAD_DATA_RACES \ + PARAM_VALUE (PARAM_ALLOW_PACKED_LOAD_DATA_RACES) +#define ALLOW_PACKED_STORE_DATA_RACES \ + PARAM_VALUE (PARAM_ALLOW_PACKED_STORE_DATA_RACES) + #endif /* ! GCC_PARAMS_H */ Index: gcc/omp-low.c =================================================================== --- gcc/omp-low.c (.../trunk) (revision 180790) +++ gcc/omp-low.c (.../branches/cxx-mem-model) (revision 180811) @@ -4998,7 +4998,7 @@ expand_omp_atomic_store (basic_block loa } /* A subroutine of expand_omp_atomic. Attempt to implement the atomic - operation as a __sync_fetch_and_op builtin. INDEX is log2 of the + operation as a __atomic_fetch_op builtin. INDEX is log2 of the size of the data type, and thus usable to find the index of the builtin decl. Returns false if the expression is not of the proper form. */ @@ -5009,13 +5009,14 @@ expand_omp_atomic_fetch_op (basic_block { enum built_in_function oldbase, newbase, tmpbase; tree decl, itype, call; - direct_optab optab, oldoptab, newoptab; tree lhs, rhs; basic_block store_bb = single_succ (load_bb); gimple_stmt_iterator gsi; gimple stmt; location_t loc; + enum tree_code code; bool need_old, need_new; + enum machine_mode imode; /* We expect to find the following sequences: @@ -5047,47 +5048,34 @@ expand_omp_atomic_fetch_op (basic_block return false; /* Check for one of the supported fetch-op operations. */ - switch (gimple_assign_rhs_code (stmt)) + code = gimple_assign_rhs_code (stmt); + switch (code) { case PLUS_EXPR: case POINTER_PLUS_EXPR: - oldbase = BUILT_IN_SYNC_FETCH_AND_ADD_N; - newbase = BUILT_IN_SYNC_ADD_AND_FETCH_N; - optab = sync_add_optab; - oldoptab = sync_old_add_optab; - newoptab = sync_new_add_optab; + oldbase = BUILT_IN_ATOMIC_FETCH_ADD_N; + newbase = BUILT_IN_ATOMIC_ADD_FETCH_N; break; case MINUS_EXPR: - oldbase = BUILT_IN_SYNC_FETCH_AND_SUB_N; - newbase = BUILT_IN_SYNC_SUB_AND_FETCH_N; - optab = sync_add_optab; - oldoptab = sync_old_add_optab; - newoptab = sync_new_add_optab; + oldbase = BUILT_IN_ATOMIC_FETCH_SUB_N; + newbase = BUILT_IN_ATOMIC_SUB_FETCH_N; break; case BIT_AND_EXPR: - oldbase = BUILT_IN_SYNC_FETCH_AND_AND_N; - newbase = BUILT_IN_SYNC_AND_AND_FETCH_N; - optab = sync_and_optab; - oldoptab = sync_old_and_optab; - newoptab = sync_new_and_optab; + oldbase = BUILT_IN_ATOMIC_FETCH_AND_N; + newbase = BUILT_IN_ATOMIC_AND_FETCH_N; break; case BIT_IOR_EXPR: - oldbase = BUILT_IN_SYNC_FETCH_AND_OR_N; - newbase = BUILT_IN_SYNC_OR_AND_FETCH_N; - optab = sync_ior_optab; - oldoptab = sync_old_ior_optab; - newoptab = sync_new_ior_optab; + oldbase = BUILT_IN_ATOMIC_FETCH_OR_N; + newbase = BUILT_IN_ATOMIC_OR_FETCH_N; break; case BIT_XOR_EXPR: - oldbase = BUILT_IN_SYNC_FETCH_AND_XOR_N; - newbase = BUILT_IN_SYNC_XOR_AND_FETCH_N; - optab = sync_xor_optab; - oldoptab = sync_old_xor_optab; - newoptab = sync_new_xor_optab; + oldbase = BUILT_IN_ATOMIC_FETCH_XOR_N; + newbase = BUILT_IN_ATOMIC_XOR_FETCH_N; break; default: return false; } + /* Make sure the expression is of the proper form. */ if (operand_equal_p (gimple_assign_rhs1 (stmt), loaded_val, 0)) rhs = gimple_assign_rhs2 (stmt); @@ -5103,37 +5091,25 @@ expand_omp_atomic_fetch_op (basic_block if (decl == NULL_TREE) return false; itype = TREE_TYPE (TREE_TYPE (decl)); + imode = TYPE_MODE (itype); - if (need_new) - { - /* expand_sync_fetch_operation can always compensate when interested - in the new value. */ - if (direct_optab_handler (newoptab, TYPE_MODE (itype)) - == CODE_FOR_nothing - && direct_optab_handler (oldoptab, TYPE_MODE (itype)) - == CODE_FOR_nothing) - return false; - } - else if (need_old) - { - /* When interested in the old value, expand_sync_fetch_operation - can compensate only if the operation is reversible. AND and OR - are not reversible. */ - if (direct_optab_handler (oldoptab, TYPE_MODE (itype)) - == CODE_FOR_nothing - && (oldbase == BUILT_IN_SYNC_FETCH_AND_AND_N - || oldbase == BUILT_IN_SYNC_FETCH_AND_OR_N - || direct_optab_handler (newoptab, TYPE_MODE (itype)) - == CODE_FOR_nothing)) - return false; - } - else if (direct_optab_handler (optab, TYPE_MODE (itype)) == CODE_FOR_nothing) + /* We could test all of the various optabs involved, but the fact of the + matter is that (with the exception of i486 vs i586 and xadd) all targets + that support any atomic operaton optab also implements compare-and-swap. + Let optabs.c take care of expanding any compare-and-swap loop. */ + if (!can_compare_and_swap_p (imode)) return false; gsi = gsi_last_bb (load_bb); gcc_assert (gimple_code (gsi_stmt (gsi)) == GIMPLE_OMP_ATOMIC_LOAD); - call = build_call_expr_loc (loc, decl, 2, addr, - fold_convert_loc (loc, itype, rhs)); + + /* OpenMP does not imply any barrier-like semantics on its atomic ops. + It only requires that the operation happen atomically. Thus we can + use the RELAXED memory model. */ + call = build_call_expr_loc (loc, decl, 3, addr, + fold_convert_loc (loc, itype, rhs), + build_int_cst (NULL, MEMMODEL_RELAXED)); + if (need_old || need_new) { lhs = need_old ? loaded_val : stored_val; @@ -5182,6 +5158,8 @@ expand_omp_atomic_pipeline (basic_block edge e; enum built_in_function fncode; + /* ??? We need a non-pointer interface to __atomic_compare_exchange in + order to use the RELAXED memory model effectively. */ fncode = (enum built_in_function)((int)BUILT_IN_SYNC_VAL_COMPARE_AND_SWAP_N + index + 1); cmpxchg = builtin_decl_explicit (fncode); @@ -5190,8 +5168,7 @@ expand_omp_atomic_pipeline (basic_block type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr))); itype = TREE_TYPE (TREE_TYPE (cmpxchg)); - if (direct_optab_handler (sync_compare_and_swap_optab, TYPE_MODE (itype)) - == CODE_FOR_nothing) + if (!can_compare_and_swap_p (TYPE_MODE (itype))) return false; /* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */ Index: gcc/testsuite/gcc.target/sparc/20111102-1.c =================================================================== --- gcc/testsuite/gcc.target/sparc/20111102-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.target/sparc/20111102-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,17 @@ +/* PR target/50945 */ +/* { dg-do compile } */ +/* { dg-options "-O -msoft-float" } */ + +double +__powidf2 (double x, int m) +{ + unsigned int n = m < 0 ? -m : m; + double y = n % 2 ? x : 1; + while (n >>= 1) + { + x = x * x; + if (n % 2) + y = y * x; + } + return m < 0 ? 1/y : y; +} Index: gcc/testsuite/ChangeLog.mm =================================================================== --- gcc/testsuite/ChangeLog.mm (.../trunk) (revision 0) +++ gcc/testsuite/ChangeLog.mm (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,244 @@ +2011-11-02 Andrew MacLeod + + * gcc.dg/atomic-lockfree.c: Add extra lock-free parameter. + * gcc.dg/atomic-lockfree-aux.c: Add extra lock-free parameter. + * gcc.dg/atomic-noinline.c: Add extra lock-free parameter. + * gcc.dg/atomic-noinline-aux.c: Add extra lock-free parameter. + * gcc.dg/atomic-invalid.c: Add extra lock-free parameter. + +2011-11-02 Andrew MacLeod + + * gcc.dg/atomic-noinline.c: New. Make a variety of atomics calls. + * gcc.dg/atomic-noinline-aux.c: New. Provide some entry points. + +2011-10-31 Richard Henderson + + * lib/target-supports.exp (check_effective_target_cas_char): New. + (check_effective_target_cas_int): New. + * c-c++-common/gomp/atomic-10.c: Use cas_int; match __atomic builtin. + * c-c++-common/gomp/atomic-3.c: Likewise. + * c-c++-common/gomp/atomic-9.c: Likewise. + + * gcc.dg/gomp/atomic-1.c, gcc.dg/gomp/atomic-2.c, + gcc.dg/gomp/atomic-3.c, gcc.dg/gomp/atomic-4.c, gcc.dg/gomp/atomic-7.c, + gcc.dg/gomp/atomic-8.c, gcc.dg/gomp/atomic-9.c, + gcc.dg/gomp/atomic-10.c, gcc.dg/gomp/atomic-12.c, + gcc.dg/gomp/atomic-13.c, gcc.dg/gomp/atomic-14.c, + gcc.dg/gomp/atomic-15.c: Move to c-c++-common/gomp/. + * g++.dg/gomp/atomic-1.C, g++.dg/gomp/atomic-2.C, + g++.dg/gomp/atomic-3.C, g++.dg/gomp/atomic-4.C, g++.dg/gomp/atomic-7.C, + g++.dg/gomp/atomic-8.C, g++.dg/gomp/atomic-9.C, + g++.dg/gomp/atomic-10.C, g++.dg/gomp/atomic-11.C, + g++.dg/gomp/atomic-12.C, g++.dg/gomp/atomic-13.C, + g++.dg/gomp/atomic-15.C: Remove. + * gcc.dg/gomp/gomp.exp, g++.dg/gomp/gomp.exp: Run c-c++-common tests. + +2011-10-25 Andrew MacLeod + + * gcc.dg/atomic-generic-aux.c: New. Provide 4 functional external + entrypoints for new generic library functions. + * gcc.dg/atomic-generic.c: New. Test that generic functions produce + the expected library calls. + * gcc.dg/atomic-compare-exchange*.c: Replace __atomic_compare_exchange + with __atomic_compare_exchange_n. Add generic variations. + * gcc.dg/atomic-exchange*.c: Replace __atomic_exchange with + __atomic_exchange_n. Add generic variations. + * gcc.dg/atomic-invalid.c: Add _n to renamed functions. + gcc.dg/atomic-load*.c: Replace __atomic_load with __atomic_load_n. Add + generic variations. + * gcc.dg/atomic-param.c: Add _n to renamed functions. + * gcc.dg/atomic-store*.c: Replace __atomic_store with __atomic_store_n. + Add generic variations. + * gcc.dg/simulate-thread/atomic*.c: Add _n to renamed functions. + +2011-10-24 Aldy Hernandez + + * lib/target-supports.exp (check_effective_target_sync_int_128): + Handle both 32-bit and 64-bit triplets on x86. + (check_effective_target_sync_long_long): Same. + * gcc.dg/simulate-thread/atomic-load-int128.c: Handle i?86-*-*. + * gcc.dg/simulate-thread/atomic-other-int128.c: Same. + +2011-10-20 Andrew MacLeod + + * gcc.dg/atomic-invalid.c: Add compare_exchange failures. + * gcc.dg/atomic-compare-exchange-{1-5}.c: New functional tests. + +2011-10-17 Andrew MacLeod + + * sync-mem*.c: Rename all files to atomic-*, rename __sync_mem. + * simulate-thread/sync*.c: Rename all files to atomic-*, rename + __sync_mem to __atomic.. + +2011-10-13 Andrew MacLeod + + * testsuite/gcc.dg/sync-mem-invalid.c: Test for invalid param. + * testsuite/gcc.dg/sync-mem-lockfree[-aux].c: New tests. + +2011-10-10 Aldy Hernandez + + Merge from mainline: + + 2011-10-10 Aldy Hernandez + + * lib/gcc-simulate-thread.exp: New. + * gcc.dg/simulate-thread/guality.h: New. + * gcc.dg/simulate-thread/simulate-thread.h: New. + * gcc.dg/simulate-thread/simulate-thread.exp: New. + * gcc.dg/simulate-thread/simulate-thread.gdb: New. + * gcc.dg/simulate-thread/README: New. + * g++.dg/simulate-thread/guality.h: New. + * g++.dg/simulate-thread/simulate-thread.h: New. + * g++.dg/simulate-thread/simulate-thread.exp: New. + * g++.dg/simulate-thread/simulate-thread.gdb: New. + * c-c++-common/cxxbitfields-2.c: Remove. + * c-c++-common/cxxbitfields.c: Remove. + * c-c++-common/cxxbitfields-4.c: Remove. + * c-c++-common/cxxbitfields-5.c: Remove. + * c-c++-common/simulate-thread/bitfields-1.c: New. + * c-c++-common/simulate-thread/bitfields-2.c: New. + * c-c++-common/simulate-thread/bitfields-3.c: New. + * c-c++-common/simulate-thread/bitfields-4.c: New. + +2011-10-04 Andrew MacLeod + + * gcc.dg/memmodel/memmodel.h (__gdb_memmodel_fini): Rename from + memmodel_fini. + (HOSTILE_THREAD_THRESHOLD, HOSTILE_THREAD_PAUSE): New. + (__gdb_hostile_pause): New. Indicates a pause was triggered. + (__gdb_wrapper_other_threads): New. Wrapper for memmodel_other_threads. + Avoid infinite loops. + (__gdb_wrapper_final_verify): New. Wrapper for memmodel_final_verify. + * gcc.dg/memmodel/memmodel.gdb: Use renamed __gdb_ routines instead. + * gcc.dg/memmodel/speculative-store.c (memmodel_other_threads): Correct + return type. + * gcc.dg/memmodel/sync-load-int128.c: Don't xfail any more. + * gcc.dg/memmodel/sync-other-int128.c: Don't xfail any more. + +2011-09-16 Andrew MacLeod + + * gcc.dg/sync-mem-invalid.c: Remove __sync_mem_flag_clear + tests. + * gcc.dg/sync-mem-flag.c: Remove. + * gcc.dg/sync-mem-param.c: New testcase to check correct number of + parameters on a sample __sync_mem builtin. + * gcc.dg/sync-mem-op-[1-5].c: Add NAND tests and a set of tests which + test the op builtins when the result isnt used. Add a few constants + as parameters for better coverage. + +2011-09-07 Aldy Hernandez + + * gcc.dg/memmodel/memmodel.exp: Call torture-finish. + * g++.dg/memmodel/memmodel.exp: Likewise. + +2011-09-07 Aldy Hernandez + + * gcc.dg/dg.exp: Exclude memmodel tests. + +2011-08-18 Aldy Hernandez + + * gcc.dg/memmodel/memmodel.exp: Torture with more options. + * g++.dg/memmodel/memmodel.exp: Same. + * gcc.dg/memmodel/*.c: Remove optimization flags. + * g++.dg/memmodel/*.c: Remove optimization flags. + +2011-08-18 Andrew MacLeod + + * gcc.dg/memmodel/memmodel.gdb: Short-circuit tests once a failure + happens. + * gcc.dg/memmodel/sync-other-{short,int,longlong,int128}.c: New. Test + for proper atomic operation of all __sync_mem routines except load. + * gcc.dg/memmodel/sync-load-{short,int,longlong,int128}.c: New. Test + for proper atomic operation of __sync_mem_load. + +2011-08-17 Aldy Hernandez + + * lib/gcc-memmodel-gdb-test.exp (memmmodel-gdb-test): Handle xfails. + +2011-08-17 Andrew MacLeod + + * gcc.dg/memmodel/memmodel.gdb: Avoid pagination. + * gcc.dg/sync-mem-invalid.c: Remove __sync_mem_compare_exchange test. + +2011-08-13 Andrew MacLeod + + * gcc.dg/sync-mem-op-[1-5].c: Combine all sync_mem_fetch_{op} + tests in one test file, and add new sync_mem_{op}_fetch tests. + * gcc/dg/sync-mem-fetch-add-[1-5].c: Delete. + * gcc/dg/sync-mem-fetch-sub-[1-5].c: Delete. + * gcc/dg/sync-mem-fetch-and-[1-5].c: Delete. + * gcc/dg/sync-mem-fetch-xor-[1-5].c: Delete. + * gcc/dg/sync-mem-fetch-or-[1-5].c: Delete. + +2011-07-27 Andrew MacLeod + + * gcc.dg/sync-mem-{1-5}.c: Remove. + * gcc.dg/sync-mem.h: Remove. + * gcc.dg/sync-mem-exchange-{1-5}.c: New functional tests. + * gcc.dg/sync-mem-fence.c: New functional tests. + * gcc.dg/sync-mem-fetch-*-{1-5}.c: New functional tests. + * gcc.dg/sync-mem-flag.c: New functional tests. + * gcc.dg/sync-mem-invalid.c: Add new invalid combinations. + * gcc.dg/sync-mem-load-{1-5}.c: New functional tests. + * gcc.dg/sync-mem-store-{1-5}.c: New functional tests. + +2011-06-23 Andrew MacLeod + + * gcc.dg/sync-mem-invalid.c: Add invalid load tests. + * gcc.dg/sync-mem.h: Add load executable tests. + +2011-06-23 Andrew MacLeod + + * lib/target-support.exp (check_effective_target_sync_int_128, + check_effective_target_sync_long_long): Check whether the target + supports 64 and 128 bit __sync builtins. + * gcc.dg/sync-mem.h: New. Common code to check memory model __syncs. + * gcc.dg/sync-mem-1.c: New. Check char size. + * gcc.dg/sync-mem-2.c: New. Check short size. + * gcc.dg/sync-mem-3.c: New. Check int size. + * gcc.dg/sync-mem-4.c: New. Check long long. + * gcc.dg/sync-mem-5.c: New. Check 128 bit. + * gcc.dg/sync-mem-invalid.c: New. Check invalid memory modes. + +2011-03-29 Aldy Hernandez + + * gcc.dg/memmodel/subfields.c (set_a): Set noinline attribute. + * g++.dg/memmodel/bitfields.C (set_a): Same. + * g++.dg/memmodel/bitfields-2.C: New. + +2011-03-29 Aldy Hernandez + + * gcc.dg/memmodel/d2.c: Remove. + * gcc.dg/memmodel/d3.c: Remove. + * gcc.dg/memmodel/global-hoist.c: Remove. + +2011-03-11 Aldy Hernandez + + * lib/gcc-memmodel-gdb-test.exp: Return if no executable. + * gcc.dg/memmodel/memmodel.h (memmodel_done): Add noinline + attribute. + * g++.dg/memmodel/bitfields.C: New. + +2011-03-10 Aldy Hernandez + + * lib/gcc-memmodel-gdb-test.exp: New. + * gcc.dg/memmodel/speculative-store.c: New + * gcc.dg/memmodel/subfields: New + * gcc.dg/memmodel/guality.h: New + * gcc.dg/memmodel/memmodel.h: New + * gcc.dg/memmodel/global-hoist.c: New + * gcc.dg/memmodel/d2.c: New + * gcc.dg/memmodel/d3.c: New + * gcc.dg/memmodel/memmodel.gdb: New. + * gcc.dg/memmodel/memmodel.exp: New. + * gcc.dg/memmodel/README: New. + * g++.dg/memmodel/guality.h: New. + * g++.dg/memmodel/memmodel.h: New. + * g++.dg/memmodel/memmodel.gdb: New. + * g++.dg/memmodel/memmodel.exp: New. + * g++.dg/memmodel/atomics-1.C: New. + +Local Variables: +mode: change-log +change-log-default-name: "ChangeLog.mm" +End: Index: gcc/testsuite/lib/target-supports.exp =================================================================== --- gcc/testsuite/lib/target-supports.exp (.../trunk) (revision 180790) +++ gcc/testsuite/lib/target-supports.exp (.../branches/cxx-mem-model) (revision 180811) @@ -655,6 +655,28 @@ proc check_effective_target_tls_runtime } [add_options_for_tls ""]] } +# Return 1 if atomic compare-and-swap is supported on 'int' + +proc check_effective_target_cas_char {} { + return [check_no_compiler_messages cas_char assembly { + #ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 + #error unsupported + #endif + } ""] +} + +proc check_effective_target_cas_int {} { + return [check_no_compiler_messages cas_int assembly { + #if __INT_MAX__ == 0x7fff && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 + /* ok */ + #elif __INT_MAX__ == 0x7fffffff && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + /* ok */ + #else + #error unsupported + #endif + } ""] +} + # Return 1 if -ffunction-sections is supported, 0 otherwise. proc check_effective_target_function_sections {} { @@ -3499,6 +3521,44 @@ proc check_effective_target_section_anch return $et_section_anchors_saved } +# Return 1 if the target supports atomic operations on "int_128" values. + +proc check_effective_target_sync_int_128 { } { + global et_sync_int_128_saved + + if [info exists et_sync_int_128_saved] { + verbose "check_effective_target_sync_int_128: using cached result" 2 + } else { + set et_sync_int_128_saved 0 + if { ([istarget x86_64-*-*] || [istarget i?86-*-*]) + && ![is-effective-target ia32] } { + set et_sync_int_128_saved 1 + } + } + + verbose "check_effective_target_sync_int_128: returning $et_sync_int_128_saved" 2 + return $et_sync_int_128_saved +} + +# Return 1 if the target supports atomic operations on "long long". + +proc check_effective_target_sync_long_long { } { + global et_sync_long_long_saved + + if [info exists et_sync_long_long_saved] { + verbose "check_effective_target_sync_long_long: using cached result" 2 + } else { + set et_sync_long_long_saved 0 + if { ([istarget x86_64-*-*] || [istarget i?86-*-*]) + && ![is-effective-target ia32] } { + set et_sync_long_long_saved 1 + } + } + + verbose "check_effective_target_sync_long_long: returning $et_sync_long_long_saved" 2 + return $et_sync_long_long_saved +} + # Return 1 if the target supports atomic operations on "int" and "long". proc check_effective_target_sync_int_long { } { Index: gcc/testsuite/gcc.dg/atomic-op-1.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-op-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-op-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,554 @@ +/* Test __atomic routines for existence and proper execution on 1 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_*OP builtin routines for a char. */ + +extern void abort(void); + +char v, count, res; +const char init = ~0; + +/* The fetch_op routines return the original value before the operation. */ + +void +test_fetch_add () +{ + v = 0; + count = 1; + + if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) + abort (); +} + + +void +test_fetch_sub() +{ + v = res = 20; + count = 0; + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) != res--) + abort (); +} + +void +test_fetch_and () +{ + v = init; + + if (__atomic_fetch_and (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_and (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_fetch_and (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_fetch_nand () +{ + v = init; + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_ACQUIRE) != 0 ) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL) != 0) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_xor () +{ + v = init; + count = 0; + + if (__atomic_fetch_xor (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_or () +{ + v = 0; + count = 1; + + if (__atomic_fetch_or (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 2, __ATOMIC_CONSUME) != 1) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 8, __ATOMIC_RELEASE) != 7) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQ_REL) != 15) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST) != 31) + abort (); +} + +/* The OP_fetch routines return the new value after the operation. */ + +void +test_add_fetch () +{ + v = 0; + count = 1; + + if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) + abort (); +} + + +void +test_sub_fetch () +{ + v = res = 20; + count = 0; + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) != --res) + abort (); +} + +void +test_and_fetch () +{ + v = init; + + if (__atomic_and_fetch (&v, 0, __ATOMIC_RELAXED) != 0) + abort (); + + v = init; + if (__atomic_and_fetch (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_nand_fetch () +{ + v = init; + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + + + +void +test_xor_fetch () +{ + v = init; + count = 0; + + if (__atomic_xor_fetch (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_or_fetch () +{ + v = 0; + count = 1; + + if (__atomic_or_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 2, __ATOMIC_CONSUME) != 3) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQUIRE) != 7) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 8, __ATOMIC_RELEASE) != 15) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL) != 31) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_SEQ_CST) != 63) + abort (); +} + + +/* Test the OP routines with a result which isn't used. Use both variations + within each function. */ + +void +test_add () +{ + v = 0; + count = 1; + + __atomic_add_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_CONSUME); + if (v != 2) + abort (); + + __atomic_add_fetch (&v, 1 , __ATOMIC_ACQUIRE); + if (v != 3) + abort (); + + __atomic_fetch_add (&v, 1, __ATOMIC_RELEASE); + if (v != 4) + abort (); + + __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 5) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST); + if (v != 6) + abort (); +} + + +void +test_sub() +{ + v = res = 20; + count = 0; + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != --res) + abort (); +} + +void +test_and () +{ + v = init; + + __atomic_and_fetch (&v, 0, __ATOMIC_RELAXED); + if (v != 0) + abort (); + + v = init; + __atomic_fetch_and (&v, init, __ATOMIC_CONSUME); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, init, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_nand () +{ + v = init; + + __atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, init, __ATOMIC_RELEASE); + if (v != 0) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST); + if (v != init) + abort (); +} + + + +void +test_xor () +{ + v = init; + count = 0; + + __atomic_xor_fetch (&v, count, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_or () +{ + v = 0; + count = 1; + + __atomic_or_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_CONSUME); + if (v != 3) + abort (); + + count *= 2; + __atomic_or_fetch (&v, 4, __ATOMIC_ACQUIRE); + if (v != 7) + abort (); + + count *= 2; + __atomic_fetch_or (&v, 8, __ATOMIC_RELEASE); + if (v != 15) + abort (); + + count *= 2; + __atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 31) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST); + if (v != 63) + abort (); +} + +main () +{ + test_fetch_add (); + test_fetch_sub (); + test_fetch_and (); + test_fetch_nand (); + test_fetch_xor (); + test_fetch_or (); + + test_add_fetch (); + test_sub_fetch (); + test_and_fetch (); + test_nand_fetch (); + test_xor_fetch (); + test_or_fetch (); + + test_add (); + test_sub (); + test_and (); + test_nand (); + test_xor (); + test_or (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-exchange-5.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-exchange-5.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-exchange-5.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,63 @@ +/* Test __atomic routines for existence and proper execution on 16 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* } } } */ + +/* Test the execution of the __atomic_X builtin for a 16 byte value. */ + +extern void abort(void); + +__int128_t v, count, ret; + +main () +{ + v = 0; + count = 0; + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) + abort (); + + /* Now test the generic version. */ + + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); + if (ret != count - 1 || v != count) + abort (); + count++; + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-op-5.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-op-5.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-op-5.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,555 @@ +/* Test __atomic routines for existence and proper execution on 16 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* } } } */ + +/* Test the execution of the __atomic_*OP builtin routines for an int_128. */ + +extern void abort(void); + +__int128_t v, count, res; +const __int128_t init = ~0; + +/* The fetch_op routines return the original value before the operation. */ + +void +test_fetch_add () +{ + v = 0; + count = 1; + + if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) + abort (); +} + + +void +test_fetch_sub() +{ + v = res = 20; + count = 0; + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) != res--) + abort (); +} + +void +test_fetch_and () +{ + v = init; + + if (__atomic_fetch_and (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_and (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_fetch_and (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_fetch_nand () +{ + v = init; + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_ACQUIRE) != 0 ) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL) != 0) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_xor () +{ + v = init; + count = 0; + + if (__atomic_fetch_xor (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_or () +{ + v = 0; + count = 1; + + if (__atomic_fetch_or (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 2, __ATOMIC_CONSUME) != 1) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 8, __ATOMIC_RELEASE) != 7) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQ_REL) != 15) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST) != 31) + abort (); +} + +/* The OP_fetch routines return the new value after the operation. */ + +void +test_add_fetch () +{ + v = 0; + count = 1; + + if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) + abort (); +} + + +void +test_sub_fetch () +{ + v = res = 20; + count = 0; + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) != --res) + abort (); +} + +void +test_and_fetch () +{ + v = init; + + if (__atomic_and_fetch (&v, 0, __ATOMIC_RELAXED) != 0) + abort (); + + v = init; + if (__atomic_and_fetch (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_nand_fetch () +{ + v = init; + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + + + +void +test_xor_fetch () +{ + v = init; + count = 0; + + if (__atomic_xor_fetch (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_or_fetch () +{ + v = 0; + count = 1; + + if (__atomic_or_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 2, __ATOMIC_CONSUME) != 3) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQUIRE) != 7) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 8, __ATOMIC_RELEASE) != 15) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL) != 31) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_SEQ_CST) != 63) + abort (); +} + + +/* Test the OP routines with a result which isn't used. Use both variations + within each function. */ + +void +test_add () +{ + v = 0; + count = 1; + + __atomic_add_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_CONSUME); + if (v != 2) + abort (); + + __atomic_add_fetch (&v, 1 , __ATOMIC_ACQUIRE); + if (v != 3) + abort (); + + __atomic_fetch_add (&v, 1, __ATOMIC_RELEASE); + if (v != 4) + abort (); + + __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 5) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST); + if (v != 6) + abort (); +} + + +void +test_sub() +{ + v = res = 20; + count = 0; + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != --res) + abort (); +} + +void +test_and () +{ + v = init; + + __atomic_and_fetch (&v, 0, __ATOMIC_RELAXED); + if (v != 0) + abort (); + + v = init; + __atomic_fetch_and (&v, init, __ATOMIC_CONSUME); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, init, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_nand () +{ + v = init; + + __atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, init, __ATOMIC_RELEASE); + if (v != 0) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST); + if (v != init) + abort (); +} + + + +void +test_xor () +{ + v = init; + count = 0; + + __atomic_xor_fetch (&v, count, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_or () +{ + v = 0; + count = 1; + + __atomic_or_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_CONSUME); + if (v != 3) + abort (); + + count *= 2; + __atomic_or_fetch (&v, 4, __ATOMIC_ACQUIRE); + if (v != 7) + abort (); + + count *= 2; + __atomic_fetch_or (&v, 8, __ATOMIC_RELEASE); + if (v != 15) + abort (); + + count *= 2; + __atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 31) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST); + if (v != 63) + abort (); +} + +main () +{ + test_fetch_add (); + test_fetch_sub (); + test_fetch_and (); + test_fetch_nand (); + test_fetch_xor (); + test_fetch_or (); + + test_add_fetch (); + test_sub_fetch (); + test_and_fetch (); + test_nand_fetch (); + test_xor_fetch (); + test_or_fetch (); + + test_add (); + test_sub (); + test_and (); + test_nand (); + test_xor (); + test_or (); + + return 0; +} Index: gcc/testsuite/gcc.dg/gomp/atomic-14.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-14.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-14.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,43 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp" } */ - -#ifdef __cplusplus -bool *baz (); -#else -_Bool *baz (); -#endif -int *bar (); - -int -foo (void) -{ - #pragma omp barrier - #pragma omp atomic - (*bar ())++; - #pragma omp barrier - #pragma omp atomic - ++(*bar ()); - #pragma omp barrier - #pragma omp atomic - (*bar ())--; - #pragma omp barrier - #pragma omp atomic - --(*bar ()); - #pragma omp barrier - #pragma omp atomic - (*baz ())++; - #pragma omp barrier - #pragma omp atomic - ++(*baz ()); -#ifndef __cplusplus - #pragma omp barrier - #pragma omp atomic - (*baz ())--; - #pragma omp barrier - #pragma omp atomic - --(*baz ()); - #pragma omp barrier -#endif - return 0; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-4.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-4.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,24 +0,0 @@ -/* { dg-do compile } */ - -int a[4]; -int *p; -struct S { int x; int y[4]; } s; -int *bar(void); - -void f1(void) -{ - #pragma omp atomic - a[4] += 1; - #pragma omp atomic - *p += 1; - #pragma omp atomic - s.x += 1; - #pragma omp atomic - s.y[*p] += 1; - #pragma omp atomic - s.y[*p] *= 42; - #pragma omp atomic - *bar() += 1; - #pragma omp atomic - *bar() *= 42; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-8.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-8.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-8.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,21 +0,0 @@ -/* { dg-do compile } */ - -long double z; - -void f3(void) -{ - #pragma omp atomic - z++; - #pragma omp atomic - z--; - #pragma omp atomic - ++z; - #pragma omp atomic - --z; - #pragma omp atomic - z += 1; - #pragma omp atomic - z *= 3; - #pragma omp atomic - z /= 3; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-11.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-11.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-11.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,17 +0,0 @@ -/* PR middle-end/36877 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp" } */ -/* { dg-options "-fopenmp -march=i386" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */ - -int i; -float f; - -void foo (void) -{ -#pragma omp atomic - i++; -#pragma omp atomic - f += 1.0; -} - -/* { dg-final { scan-assembler-not "__sync_(fetch|add|bool|val)" { target i?86-*-* x86_64-*-* powerpc*-*-* ia64-*-* s390*-*-* sparc*-*-* } } } */ Index: gcc/testsuite/gcc.dg/gomp/atomic-15.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-15.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-15.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,46 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fopenmp" } */ - -int x = 6; - -int -main () -{ - int v; - #pragma omp atomic - x = x * 7 + 6; /* { dg-error "expected" } */ - #pragma omp atomic - x = x * 7 ^ 6; /* { dg-error "expected" } */ - #pragma omp atomic update - x = x - 8 + 6; /* { dg-error "expected" } */ - #pragma omp atomic - x = x ^ 7 | 2; /* { dg-error "expected" } */ - #pragma omp atomic - x = x / 7 * 2; /* { dg-error "expected" } */ - #pragma omp atomic - x = x / 7 / 2; /* { dg-error "expected" } */ - #pragma omp atomic capture - v = x = x | 6; /* { dg-error "invalid operator" } */ - #pragma omp atomic capture - { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */ - #pragma omp atomic capture - { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */ - (void) v; - return 0; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-1.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-1.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,99 +0,0 @@ -/* { dg-do compile } */ - -int x; -volatile int y; -volatile unsigned char z; - -void f1(void) -{ - #pragma omp atomic - x++; - #pragma omp atomic - x--; - #pragma omp atomic - ++x; - #pragma omp atomic - --x; - #pragma omp atomic - x += 1; - #pragma omp atomic - x -= y; - #pragma omp atomic - x |= 1; - #pragma omp atomic - x &= 1; - #pragma omp atomic - x ^= 1; - #pragma omp atomic - x *= 3; - #pragma omp atomic - x /= 3; - #pragma omp atomic - x /= 3; - #pragma omp atomic - x <<= 3; - #pragma omp atomic - x >>= 3; -} - -void f2(void) -{ - #pragma omp atomic - y++; - #pragma omp atomic - y--; - #pragma omp atomic - ++y; - #pragma omp atomic - --y; - #pragma omp atomic - y += 1; - #pragma omp atomic - y -= x; - #pragma omp atomic - y |= 1; - #pragma omp atomic - y &= 1; - #pragma omp atomic - y ^= 1; - #pragma omp atomic - y *= 3; - #pragma omp atomic - y /= 3; - #pragma omp atomic - y /= 3; - #pragma omp atomic - y <<= 3; - #pragma omp atomic - y >>= 3; -} - -void f3(void) -{ - #pragma omp atomic - z++; - #pragma omp atomic - z--; - #pragma omp atomic - ++z; - #pragma omp atomic - --z; - #pragma omp atomic - z += 1; - #pragma omp atomic - z |= 1; - #pragma omp atomic - z &= 1; - #pragma omp atomic - z ^= 1; - #pragma omp atomic - z *= 3; - #pragma omp atomic - z /= 3; - #pragma omp atomic - z /= 3; - #pragma omp atomic - z <<= 3; - #pragma omp atomic - z >>= 3; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-9.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-9.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-9.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,13 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ - -volatile int *bar(void); - -void f1(void) -{ - #pragma omp atomic - *bar() += 1; -} - -/* { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 1 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ -/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/gcc.dg/gomp/atomic-12.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-12.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-12.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,306 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-gimple -g0" } */ -/* atomicvar should never be referenced in between the barrier and - following #pragma omp atomic_load. */ -/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ -/* { dg-final { cleanup-tree-dump "gimple" } } */ - -#ifdef __cplusplus -bool atomicvar, c; -#else -_Bool atomicvar, c; -#endif -int i, atomicvar2, c2; - -int -foo (void) -{ - #pragma omp barrier - #pragma omp atomic - atomicvar |= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar |= c; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= c; - #pragma omp barrier - #pragma omp atomic - atomicvar &= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar &= c; - #pragma omp barrier - #pragma omp atomic - atomicvar += -1; - #pragma omp barrier - #pragma omp atomic - atomicvar += 0; - #pragma omp barrier - #pragma omp atomic - atomicvar += 1; - #pragma omp barrier - #pragma omp atomic - atomicvar += 2; - #pragma omp barrier - #pragma omp atomic - atomicvar += c; - #pragma omp barrier - #pragma omp atomic - atomicvar -= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar -= c; - #pragma omp barrier - #pragma omp atomic - atomicvar *= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar *= c; - #pragma omp barrier - #pragma omp atomic - atomicvar /= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar /= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar /= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar /= c; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= i; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= i; - #pragma omp barrier - #pragma omp atomic - atomicvar++; - #pragma omp barrier - #pragma omp atomic - ++atomicvar; - #pragma omp barrier -#ifndef __cplusplus - #pragma omp atomic - atomicvar--; - #pragma omp barrier - #pragma omp atomic - --atomicvar; - #pragma omp barrier -#endif - return 0; -} - -int -bar (void) -{ - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= i; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= i; - #pragma omp barrier - #pragma omp atomic - atomicvar2++; - #pragma omp barrier - #pragma omp atomic - ++atomicvar2; - #pragma omp barrier - #pragma omp atomic - atomicvar2--; - #pragma omp barrier - #pragma omp atomic - --atomicvar2; - #pragma omp barrier - return 0; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-2.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-2.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,23 +0,0 @@ -/* { dg-do compile } */ - -float x, y; - -void f1(void) -{ - #pragma omp atomic - x++; - #pragma omp atomic - x--; - #pragma omp atomic - ++x; - #pragma omp atomic - --x; - #pragma omp atomic - x += 1; - #pragma omp atomic - x -= y; - #pragma omp atomic - x *= 3; - #pragma omp atomic - x /= 3; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-13.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-13.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-13.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,9 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-gimple -g0 -O2" } */ -/* atomicvar should never be referenced in between the barrier and - following #pragma omp atomic_load. */ -/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ -/* { dg-final { cleanup-tree-dump "gimple" } } */ - -#include "atomic-12.c" Index: gcc/testsuite/gcc.dg/gomp/atomic-3.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-3.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,13 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ - -int *xyzzy; - -void f1(void) -{ - #pragma omp atomic - xyzzy++; -} - -/* { dg-final { scan-tree-dump-times "xyzzy, 4" 1 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ -/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/gcc.dg/gomp/atomic-7.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-7.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-7.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,23 +0,0 @@ -/* { dg-do compile } */ - -double x, y; - -void f2(void) -{ - #pragma omp atomic - y++; - #pragma omp atomic - y--; - #pragma omp atomic - ++y; - #pragma omp atomic - --y; - #pragma omp atomic - y += 1; - #pragma omp atomic - y -= x; - #pragma omp atomic - y *= 3; - #pragma omp atomic - y /= 3; -} Index: gcc/testsuite/gcc.dg/gomp/atomic-10.c =================================================================== --- gcc/testsuite/gcc.dg/gomp/atomic-10.c (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/atomic-10.c (.../branches/cxx-mem-model) (revision 180811) @@ -1,24 +0,0 @@ -/* PR middle-end/28046 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ - -int a[3], b; -struct C { int x; int y; } c; - -int bar (void), *baz (void); - -void -foo (void) -{ -#pragma omp atomic - a[2] += bar (); -#pragma omp atomic - b += bar (); -#pragma omp atomic - c.y += bar (); -#pragma omp atomic - *baz () += bar (); -} - -/* { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 4 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ -/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/gcc.dg/gomp/gomp.exp =================================================================== --- gcc/testsuite/gcc.dg/gomp/gomp.exp (.../trunk) (revision 180790) +++ gcc/testsuite/gcc.dg/gomp/gomp.exp (.../branches/cxx-mem-model) (revision 180811) @@ -29,8 +29,7 @@ if ![check_effective_target_fopenmp] { dg-init # Main loop. -dg-runtest [lsort [find $srcdir/$subdir *.c]] \ - "" "-fopenmp" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/gomp/*.c]] "" "-fopenmp" # All done. dg-finish Index: gcc/testsuite/gcc.dg/atomic-store-2.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-store-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-store-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,46 @@ +/* Test __atomic routines for existence and proper execution on 2 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_store_n builtin for a short. */ + +extern void abort(void); + +short v, count; + +main () +{ + v = 0; + count = 0; + + __atomic_store_n (&v, count + 1, __ATOMIC_RELAXED); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_RELEASE); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != ++count) + abort (); + + /* Now test the generic variant. */ + count++; + + __atomic_store (&v, &count, __ATOMIC_RELAXED); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_RELEASE); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_SEQ_CST); + if (v != count) + abort (); + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-compare-exchange-3.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-compare-exchange-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-compare-exchange-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,85 @@ +/* Test __atomic routines for existence and proper execution on 4 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_long } */ + +/* Test the execution of the __atomic_compare_exchange_n builtin for an int. */ + +extern void abort(void); + +int v = 0; +int expected = 0; +int max = ~0; +int desired = ~0; +int zero = 0; + +#define STRONG 0 +#define WEAK 1 + +main () +{ + + if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + /* Now test the generic version. */ + + v = 0; + + if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-lockfree-aux.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-lockfree-aux.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-lockfree-aux.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,17 @@ +/* Test supply a __atomic_is_lock_free routine for lock-free tests. */ +/* Just compile it on its own. */ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +/* Test that __atomic_{is,always}_lock_free builtins execute. */ + +#include + +/* Supply a builtin external function which returns a non-standard value so + it can be detected that it was called. */ +int +__atomic_is_lock_free (size_t s, void *p) +{ + return 2; +} + Index: gcc/testsuite/gcc.dg/atomic-load-3.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-load-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-load-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,65 @@ +/* Test __atomic routines for existence and proper execution on 4 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_long } */ + +extern void abort(void); + +int v, count; + + +main () +{ + v = 0; + count = 0; + + if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++) + abort(); + else + v++; + + /* Now test the generic variants. */ + + __atomic_load (&v, &count, __ATOMIC_RELAXED); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_ACQUIRE); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_CONSUME); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_SEQ_CST); + if (count != v) + abort(); + else + v++; + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-exchange-2.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-exchange-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-exchange-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,62 @@ +/* Test __atomic routines for existence and proper execution on 2 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_X builtin for a short. */ + +extern void abort(void); + +short v, count, ret; + +main () +{ + v = 0; + count = 0; + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) + abort (); + + /* Now test the generic version. */ + + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); + if (ret != count - 1 || v != count) + abort (); + count++; + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-op-2.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-op-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-op-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,555 @@ +/* Test __atomic routines for existence and proper execution on 2 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + + +/* Test the execution of the __atomic_*OP builtin routines for a short. */ + +extern void abort(void); + +short v, count, res; +const short init = ~0; + +/* The fetch_op routines return the original value before the operation. */ + +void +test_fetch_add () +{ + v = 0; + count = 1; + + if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) + abort (); +} + + +void +test_fetch_sub() +{ + v = res = 20; + count = 0; + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) != res--) + abort (); +} + +void +test_fetch_and () +{ + v = init; + + if (__atomic_fetch_and (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_and (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_fetch_and (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_fetch_nand () +{ + v = init; + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_ACQUIRE) != 0 ) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL) != 0) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_xor () +{ + v = init; + count = 0; + + if (__atomic_fetch_xor (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_or () +{ + v = 0; + count = 1; + + if (__atomic_fetch_or (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 2, __ATOMIC_CONSUME) != 1) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 8, __ATOMIC_RELEASE) != 7) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQ_REL) != 15) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST) != 31) + abort (); +} + +/* The OP_fetch routines return the new value after the operation. */ + +void +test_add_fetch () +{ + v = 0; + count = 1; + + if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) + abort (); +} + + +void +test_sub_fetch () +{ + v = res = 20; + count = 0; + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) != --res) + abort (); +} + +void +test_and_fetch () +{ + v = init; + + if (__atomic_and_fetch (&v, 0, __ATOMIC_RELAXED) != 0) + abort (); + + v = init; + if (__atomic_and_fetch (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_nand_fetch () +{ + v = init; + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + + + +void +test_xor_fetch () +{ + v = init; + count = 0; + + if (__atomic_xor_fetch (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_or_fetch () +{ + v = 0; + count = 1; + + if (__atomic_or_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 2, __ATOMIC_CONSUME) != 3) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQUIRE) != 7) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 8, __ATOMIC_RELEASE) != 15) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL) != 31) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_SEQ_CST) != 63) + abort (); +} + + +/* Test the OP routines with a result which isn't used. Use both variations + within each function. */ + +void +test_add () +{ + v = 0; + count = 1; + + __atomic_add_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_CONSUME); + if (v != 2) + abort (); + + __atomic_add_fetch (&v, 1 , __ATOMIC_ACQUIRE); + if (v != 3) + abort (); + + __atomic_fetch_add (&v, 1, __ATOMIC_RELEASE); + if (v != 4) + abort (); + + __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 5) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST); + if (v != 6) + abort (); +} + + +void +test_sub() +{ + v = res = 20; + count = 0; + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != --res) + abort (); +} + +void +test_and () +{ + v = init; + + __atomic_and_fetch (&v, 0, __ATOMIC_RELAXED); + if (v != 0) + abort (); + + v = init; + __atomic_fetch_and (&v, init, __ATOMIC_CONSUME); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, init, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_nand () +{ + v = init; + + __atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, init, __ATOMIC_RELEASE); + if (v != 0) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST); + if (v != init) + abort (); +} + + + +void +test_xor () +{ + v = init; + count = 0; + + __atomic_xor_fetch (&v, count, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_or () +{ + v = 0; + count = 1; + + __atomic_or_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_CONSUME); + if (v != 3) + abort (); + + count *= 2; + __atomic_or_fetch (&v, 4, __ATOMIC_ACQUIRE); + if (v != 7) + abort (); + + count *= 2; + __atomic_fetch_or (&v, 8, __ATOMIC_RELEASE); + if (v != 15) + abort (); + + count *= 2; + __atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 31) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST); + if (v != 63) + abort (); +} + +main () +{ + test_fetch_add (); + test_fetch_sub (); + test_fetch_and (); + test_fetch_nand (); + test_fetch_xor (); + test_fetch_or (); + + test_add_fetch (); + test_sub_fetch (); + test_and_fetch (); + test_nand_fetch (); + test_xor_fetch (); + test_or_fetch (); + + test_add (); + test_sub (); + test_and (); + test_nand (); + test_xor (); + test_or (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-generic-aux.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-generic-aux.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-generic-aux.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,45 @@ +/* Supply a set of generic atomic functions to test the compiler make the + calls properly. */ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +/* Test that the generic builtins make calls as expected. */ + +#include +#include +#include + +void +__atomic_exchange (size_t size, void *obj, void *val, void *ret, int model) +{ + /* Copy old value into *ret. */ + memcpy (ret, obj, size); + /* Copy val into object. */ + memcpy (obj, val, size); +} + + +bool +__atomic_compare_exchange (size_t size, void *obj, void *expected, + void *desired, int model1, int model2) +{ + if (!memcmp (obj, expected, size)) + { + memcpy (obj, desired, size); + return true; + } + memcpy (expected, obj, size); + return false; +} + + +void __atomic_load (size_t size, void *obj, void *ret, int model) +{ + memcpy (ret, obj, size); +} + + +void __atomic_store (size_t size, void *obj, void *val, int model) +{ + memcpy (obj, val, size); +} Index: gcc/testsuite/gcc.dg/atomic-fence.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-fence.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-fence.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,27 @@ +/* Test __atomic routines for existence and execution with each valid + memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + + +/* Test that __atomic_{thread,signal}_fence builtins execute. */ + +main () +{ + __atomic_thread_fence (__ATOMIC_RELAXED); + __atomic_thread_fence (__ATOMIC_CONSUME); + __atomic_thread_fence (__ATOMIC_ACQUIRE); + __atomic_thread_fence (__ATOMIC_RELEASE); + __atomic_thread_fence (__ATOMIC_ACQ_REL); + __atomic_thread_fence (__ATOMIC_SEQ_CST); + + __atomic_signal_fence (__ATOMIC_RELAXED); + __atomic_signal_fence (__ATOMIC_CONSUME); + __atomic_signal_fence (__ATOMIC_ACQUIRE); + __atomic_signal_fence (__ATOMIC_RELEASE); + __atomic_signal_fence (__ATOMIC_ACQ_REL); + __atomic_signal_fence (__ATOMIC_SEQ_CST); + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-generic.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-generic.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-generic.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,56 @@ +/* Test generic __atomic routines for proper function calling. + memory model. */ +/* { dg-options "-w" } */ +/* { dg-do run } */ +/* { dg-additional-sources "atomic-generic-aux.c" } */ + +/* Test that the generioc atomic builtins execute as expected.. + sync-mem-generic-aux.c supplies a functional external entry point for + the 4 generic functions. */ + +#include +#include + +extern void abort(); + +typedef struct test { + int array[10]; +} test_struct; + +test_struct zero = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +test_struct ones = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +test_struct a,b; + +int size = sizeof (test_struct); +/* Test for consistency on sizes 1, 2, 4, 8, 16 and 32. */ +main () +{ + test_struct c; + + __atomic_store (&a, &zero, __ATOMIC_RELAXED); + if (memcmp (&a, &zero, size)) + abort (); + + __atomic_exchange (&a, &ones, &c, __ATOMIC_SEQ_CST); + if (memcmp (&c, &zero, size)) + abort (); + if (memcmp (&a, &ones, size)) + abort (); + + __atomic_load (&a, &b, __ATOMIC_RELAXED); + if (memcmp (&b, &ones, size)) + abort (); + + if (!__atomic_compare_exchange (&a, &b, &zero, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort(); + if (memcmp (&a, &zero, size)) + abort (); + + if (__atomic_compare_exchange (&a, &b, &ones, false, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort(); + if (memcmp (&b, &zero, size)) + abort (); + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-store-3.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-store-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-store-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,47 @@ +/* Test __atomic routines for existence and proper execution on 4 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_long } */ + +/* Test the execution of the __atomic_store_n builtin for an int. */ + +extern void abort(void); + +int v, count; + +main () +{ + v = 0; + count = 0; + + __atomic_store_n (&v, count + 1, __ATOMIC_RELAXED); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_RELEASE); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != ++count) + abort (); + + /* Now test the generic variant. */ + count++; + + __atomic_store (&v, &count, __ATOMIC_RELAXED); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_RELEASE); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_SEQ_CST); + if (v != count) + abort (); + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-compare-exchange-4.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-compare-exchange-4.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-compare-exchange-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,86 @@ +/* Test __atomic routines for existence and proper execution on 8 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ + +/* Test the execution of __atomic_compare_exchange_n builtin for a long_long. */ + +extern void abort(void); + +long long v = 0; +long long expected = 0; +long long max = ~0; +long long desired = ~0; +long long zero = 0; + +#define STRONG 0 +#define WEAK 1 + +main () +{ + + if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + /* Now test the generic version. */ + + v = 0; + + if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-load-4.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-load-4.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-load-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,65 @@ +/* Test __atomic routines for existence and proper execution on 8 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ + +extern void abort(void); + +long long v, count; + +main () +{ + v = 0; + count = 0; + + if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++) + abort(); + else + v++; + + /* Now test the generic variants. */ + + __atomic_load (&v, &count, __ATOMIC_RELAXED); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_ACQUIRE); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_CONSUME); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_SEQ_CST); + if (count != v) + abort(); + else + v++; + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-exchange-3.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-exchange-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-exchange-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,62 @@ +/* Test __atomic routines for existence and proper execution on 4 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_long } */ + +/* Test the execution of the __atomic_X builtin for an int. */ + +extern void abort(void); + +int v, count, ret; + +main () +{ + v = 0; + count = 0; + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) + abort (); + + /* Now test the generic version. */ + + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); + if (ret != count - 1 || v != count) + abort (); + count++; + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-invalid.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-invalid.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-invalid.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,27 @@ +/* Test __atomic routines for invalid memory model errors. This only needs + to be tested on a single size. */ +/* { dg-do compile } */ +/* { dg-require-effective-target sync_int_long } */ + +#include + +int i, e, b; +size_t s; + +main () +{ + __atomic_compare_exchange_n (&i, &e, 1, 0, __ATOMIC_RELAXED, __ATOMIC_SEQ_CST); /* { dg-error "failure memory model cannot be stronger" } */ + __atomic_compare_exchange_n (&i, &e, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_RELEASE); /* { dg-error "invalid failure memory" } */ + __atomic_compare_exchange_n (&i, &e, 1, 1, __ATOMIC_SEQ_CST, __ATOMIC_ACQ_REL); /* { dg-error "invalid failure memory" } */ + + __atomic_exchange_n (&i, 1, __ATOMIC_CONSUME); /* { dg-error "invalid memory model" } */ + + __atomic_load_n (&i, __ATOMIC_RELEASE); /* { dg-error "invalid memory model" } */ + __atomic_load_n (&i, __ATOMIC_ACQ_REL); /* { dg-error "invalid memory model" } */ + + __atomic_store_n (&i, 1, __ATOMIC_ACQUIRE); /* { dg-error "invalid memory model" } */ + __atomic_store_n (&i, 1, __ATOMIC_CONSUME); /* { dg-error "invalid memory model" } */ + __atomic_store_n (&i, 1, __ATOMIC_ACQ_REL); /* { dg-error "invalid memory model" } */ + + i = __atomic_always_lock_free (s, NULL); /* { dg-error "non-constant argument" } */ +} Index: gcc/testsuite/gcc.dg/atomic-noinline.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-noinline.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-noinline.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,56 @@ +/* Test generic __atomic routines for proper function calling. + memory model. */ +/* { dg-options "-w -fno-inline-atomics" } */ +/* { dg-do run } */ +/* { dg-additional-sources "atomic-noinline-aux.c" } */ + +/* Test that -fno-inline-atomics works as expected. + atomic-generic-aux provide the expected routines which simply set the + value of the first parameter to */ + +#include +#include + +extern void abort(); + +short as,bs,cs; +char ac,bc,cc; + +main () +{ + + ac = __atomic_exchange_n (&bc, cc, __ATOMIC_RELAXED); + if (bc != 1) + abort (); + + as = __atomic_load_n (&bs, __ATOMIC_SEQ_CST); + if (bs != 1) + abort (); + + __atomic_store_n (&ac, bc, __ATOMIC_RELAXED); + if (ac != 1) + abort (); + + __atomic_compare_exchange_n (&as, &bs, cs, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + if (as != 1) + abort (); + + ac = __atomic_fetch_add (&cc, 15, __ATOMIC_SEQ_CST); + if (cc != 1) + abort (); + + /* This should be translated to __atomic_fetch_add for the library */ + as = __atomic_add_fetch (&cs, 10, __ATOMIC_RELAXED); + + if (cs != 1) + abort (); + + /* The fake external function should return 10. */ + if (__atomic_is_lock_free (4, 0) != 10) + abort (); + + return 0; +} + + + Index: gcc/testsuite/gcc.dg/atomic-op-3.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-op-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-op-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,554 @@ +/* Test __atomic routines for existence and proper execution on 4 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_long } */ + +/* Test the execution of the __atomic_*OP builtin routines for an int. */ + +extern void abort(void); + +int v, count, res; +const int init = ~0; + +/* The fetch_op routines return the original value before the operation. */ + +void +test_fetch_add () +{ + v = 0; + count = 1; + + if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) + abort (); +} + + +void +test_fetch_sub() +{ + v = res = 20; + count = 0; + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) != res--) + abort (); +} + +void +test_fetch_and () +{ + v = init; + + if (__atomic_fetch_and (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_and (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_fetch_and (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_fetch_nand () +{ + v = init; + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_ACQUIRE) != 0 ) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL) != 0) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_xor () +{ + v = init; + count = 0; + + if (__atomic_fetch_xor (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_or () +{ + v = 0; + count = 1; + + if (__atomic_fetch_or (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 2, __ATOMIC_CONSUME) != 1) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 8, __ATOMIC_RELEASE) != 7) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQ_REL) != 15) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST) != 31) + abort (); +} + +/* The OP_fetch routines return the new value after the operation. */ + +void +test_add_fetch () +{ + v = 0; + count = 1; + + if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) + abort (); +} + + +void +test_sub_fetch () +{ + v = res = 20; + count = 0; + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) != --res) + abort (); +} + +void +test_and_fetch () +{ + v = init; + + if (__atomic_and_fetch (&v, 0, __ATOMIC_RELAXED) != 0) + abort (); + + v = init; + if (__atomic_and_fetch (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_nand_fetch () +{ + v = init; + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + + + +void +test_xor_fetch () +{ + v = init; + count = 0; + + if (__atomic_xor_fetch (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_or_fetch () +{ + v = 0; + count = 1; + + if (__atomic_or_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 2, __ATOMIC_CONSUME) != 3) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQUIRE) != 7) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 8, __ATOMIC_RELEASE) != 15) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL) != 31) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_SEQ_CST) != 63) + abort (); +} + + +/* Test the OP routines with a result which isn't used. Use both variations + within each function. */ + +void +test_add () +{ + v = 0; + count = 1; + + __atomic_add_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_CONSUME); + if (v != 2) + abort (); + + __atomic_add_fetch (&v, 1 , __ATOMIC_ACQUIRE); + if (v != 3) + abort (); + + __atomic_fetch_add (&v, 1, __ATOMIC_RELEASE); + if (v != 4) + abort (); + + __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 5) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST); + if (v != 6) + abort (); +} + + +void +test_sub() +{ + v = res = 20; + count = 0; + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != --res) + abort (); +} + +void +test_and () +{ + v = init; + + __atomic_and_fetch (&v, 0, __ATOMIC_RELAXED); + if (v != 0) + abort (); + + v = init; + __atomic_fetch_and (&v, init, __ATOMIC_CONSUME); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, init, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_nand () +{ + v = init; + + __atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, init, __ATOMIC_RELEASE); + if (v != 0) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST); + if (v != init) + abort (); +} + + + +void +test_xor () +{ + v = init; + count = 0; + + __atomic_xor_fetch (&v, count, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_or () +{ + v = 0; + count = 1; + + __atomic_or_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_CONSUME); + if (v != 3) + abort (); + + count *= 2; + __atomic_or_fetch (&v, 4, __ATOMIC_ACQUIRE); + if (v != 7) + abort (); + + count *= 2; + __atomic_fetch_or (&v, 8, __ATOMIC_RELEASE); + if (v != 15) + abort (); + + count *= 2; + __atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 31) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST); + if (v != 63) + abort (); +} + +main () +{ + test_fetch_add (); + test_fetch_sub (); + test_fetch_and (); + test_fetch_nand (); + test_fetch_xor (); + test_fetch_or (); + + test_add_fetch (); + test_sub_fetch (); + test_and_fetch (); + test_nand_fetch (); + test_xor_fetch (); + test_or_fetch (); + + test_add (); + test_sub (); + test_and (); + test_nand (); + test_xor (); + test_or (); + + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int128.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,116 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* i?86-*-*] } } } */ +/* { dg-final { simulate-thread } } */ + +#include +#include "simulate-thread.h" + +/* Test all the __sync routines for proper atomicity on 16 byte values. */ + +__int128_t zero = 0; +__int128_t max = ~0; +__int128_t changing_value = 0; +__int128_t value = 0; +__int128_t ret; + +void test_abort() +{ + static int reported = 0; + if (!reported) + { + printf ("FAIL: improper execution of __sync builtin.\n"); + reported = 1; + } +} + +void simulate_thread_other_threads () +{ +} + +int simulate_thread_step_verify () +{ + if (value != zero && value != max) + { + printf ("FAIL: invalid intermediate result for value.\n"); + return 1; + } + return 0; +} + +int simulate_thread_final_verify () +{ + if (value != 0) + { + printf ("FAIL: invalid final result for value.\n"); + return 1; + } + return 0; +} + +/* All values written to 'value' alternate between 'zero' and 'max'. Any other + value detected by simulate_thread_step_verify() between instructions would indicate + that the value was only partially written, and would thus fail this + atomicity test. + + This function tests each different __atomic routine once, with the + exception of the load instruction which requires special testing. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + + ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST); + if (ret != zero || value != max) + test_abort(); + + __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST); + if (value != zero) + test_abort(); + + ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); + + ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); +} + +int main() +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/speculative-store.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,57 @@ +/* { dg-do link } */ +/* { dg-options "--param allow-store-data-races=0" } */ +/* { dg-final { simulate-thread } } */ + +#include +#include "simulate-thread.h" + +/* This file tests that speculative store movement out of a loop doesn't + happen. This is disallowed when --param allow-store-data-races is 0. */ + +int global = 100; + +/* Other thread makes sure global is 100 before the next instruction is + * exceuted. */ +void simulate_thread_other_threads() +{ + global = 100; +} + +int simulate_thread_step_verify() +{ + if (global != 100) + { + printf("FAIL: global variable was assigned to. \n"); + return 1; + } +} + +int simulate_thread_final_verify() +{ + return 0; +} + +/* The variable global should never be assigned if func(0) is called. + This tests store movement out of loop thats never executed. */ +void test (int y) +{ + int x; + for (x=0; x< y; x++) + { + global = y; /* This should never speculatively execute. */ + } +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + test(0); + simulate_thread_done(); +} + +__attribute__((noinline)) +int main() +{ + simulate_thread_main(); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/strict-align-global.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,52 @@ +/* { dg-do link } */ +/* { dg-options "--param allow-packed-store-data-races=0" } */ +/* { dg-final { simulate-thread } } */ + +#include +#include "simulate-thread.h" + +/* This test verifies writes to globals do not write to adjacent + globals. This mostly happens on strict-align targets that are not + byte addressable (old Alphas, etc). */ + +char a = 0; +char b = 77; + +void simulate_thread_other_threads() +{ +} + +int simulate_thread_step_verify() +{ + if (b != 77) + { + printf("FAIL: Unexpected value. is %d, should be 77\n", b); + return 1; + } + return 0; +} + +/* Verify that every variable has the correct value. */ +int simulate_thread_final_verify() +{ + int ret = simulate_thread_step_verify (); + if (a != 66) + { + printf("FAIL: Unexpected value. is %d, should be 66\n", a); + return 1; + } + return ret; +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + a = 66; +} + +int main () +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/subfields.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/subfields.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/subfields.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,93 @@ +/* { dg-do link } */ +/* { dg-options "--param allow-packed-store-data-races=0" } */ +/* { dg-final { simulate-thread } } */ + +#include +#include "simulate-thread.h" + +/* This test verifies that data races aren't introduced by structure subfield + stores. */ + +struct test_struct { + char a; + char b; + char c; + char d; +} var = {0,0,0,0}; + + +/* This routine sets field a to 'x'. If executed properly, it will + not affect any of the other fields in the structure. An improper + implementation may load an entire word, change the 8 bits for field + 'a' and write the entire word back out. */ +__attribute__((noinline)) +void set_a(char x) +{ + var.a = x; +} + +static int global = 0; + +/* The other thread increments the value of each of the other fields + in the structure every cycle. If the store to the 'a' field does + an incorrect full or partial word load, mask and store, it will + write back an incorrect value to one or more of the other + fields. */ +void simulate_thread_other_threads() +{ + global++; + var.b = global; + var.c = global; + var.d = global; +} + + +/* Make sure that none of the other fields have been changed. */ +int simulate_thread_step_verify() +{ + int ret = 0; + if (var.b != global) + { + printf("FAIL: Unexpected value. var.b is %d, should be %d\n", + var.b, global); + ret = 1; + } + if (var.c != global) + { + printf("FAIL: Unexpected value. var.c is %d, should be %d\n", + var.c, global); + ret = 1; + } + if (var.d != global) + { + printf("FAIL: Unexpected value. var.d is %d, should be %d\n", + var.d, global); + ret = 1; + } + return ret; +} + +/* Verify that every variable has the correct value. */ +int simulate_thread_final_verify() +{ + int ret = simulate_thread_step_verify(); + if (var.a != 1) + { + printf("FAIL: Unexpected value. var.a is %d, should be %d\n", var.a, 1); + ret = 1; + } + return ret; +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + set_a(1); +} + +int main () +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,116 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_int_long } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + + +/* Testing load for atomicity is a little trickier. + + Set up the atomic value so that it changes value after every instruction + is executed. + + Simply alternating between 2 values wouldn't be sufficient since a load of + one part, followed by the load of the second part 2 instructions later would + appear to be valid. + + set up a table of 16 values which change a bit in every byte of the value + each time, this will give us a 16 instruction cycle before repetition + kicks in, which should be sufficient to detect any issues. Just to be sure, + we also change the table cycle size during execution. + + The end result is that all loads should always get one of the values from + the table. Any other pattern means the load failed. */ + +unsigned int ret; +unsigned int value = 0; +unsigned int result = 0; +unsigned int table[16] = { +0x00000000, +0x11111111, +0x22222222, +0x33333333, +0x44444444, +0x55555555, +0x66666666, +0x77777777, +0x88888888, +0x99999999, +0xAAAAAAAA, +0xBBBBBBBB, +0xCCCCCCCC, +0xDDDDDDDD, +0xEEEEEEEE, +0xFFFFFFFF +}; + +int table_cycle_size = 16; + +/* Return 0 if 'result' is a valid value to have loaded. */ +int verify_result () +{ + int x; + int found = 0; + + /* Check entire table for valid values. */ + for (x = 0; x < 16 ; x++) + if (result == table[x]) + { + found = 1; + break; + } + + if (!found) + printf("FAIL: Invalid result returned from fetch\n"); + + return !found; +} + +/* Iterate VALUE through the different valid values. */ +void simulate_thread_other_threads () +{ + static int current = 0; + + if (++current >= table_cycle_size) + current = 0; + value = table[current]; +} + +int simulate_thread_step_verify () +{ + return verify_result (); +} + +int simulate_thread_final_verify () +{ + return verify_result (); +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + int x; + + /* Execute loads with value changing at various cyclic values. */ + for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--) + { + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + /* In order to verify the returned value (which is not atomic), it needs + to be atomically stored into another variable and check that. */ + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + + /* Execute the fetch/store a couple of times just to ensure the cycles + have a chance to be interesting. */ + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + } +} + +main() +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-other-int.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,118 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_int_long } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + +/* Test all the __sync routines for proper atomicity on 4 byte values. */ + +unsigned int zero = 0; +unsigned int max = ~0; + +unsigned int changing_value = 0; +unsigned int value = 0; +unsigned int ret; + +void test_abort() +{ + static int reported = 0; + if (!reported) + { + printf ("FAIL: improper execution of __sync builtin.\n"); + reported = 1; + } +} + +void simulate_thread_other_threads () +{ +} + +int simulate_thread_step_verify () +{ + if (value != zero && value != max) + { + printf ("FAIL: invalid intermediate result for value.\n"); + return 1; + } + return 0; +} + +int simulate_thread_final_verify () +{ + if (value != 0) + { + printf ("FAIL: invalid final result for value.\n"); + return 1; + } + return 0; +} + +/* All values written to 'value' alternate between 'zero' and + 'max'. Any other value detected by simulate_thread_step_verify() + between instructions would indicate that the value was only + partially written, and would thus fail this atomicity test. + + This function tests each different __atomic routine once, with + the exception of the load instruction which requires special + testing. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + + ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST); + if (ret != zero || value != max) + test_abort(); + + __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST); + if (value != zero) + test_abort(); + + ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); + + ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); +} + +main () +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-load-longlong.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,117 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + + +/* Testing load for atomicity is a little trickier. + + Set up the atomic value so that it changes value after every instruction + is executed. + + Simply alternating between 2 values wouldn't be sufficient since a load of + one part, followed by the load of the second part 2 instructions later would + appear to be valid. + + set up a table of 16 values which change a bit in every byte of the value + each time, this will give us a 16 instruction cycle before repetition + kicks in, which should be sufficient to detect any issues. Just to be sure, + we also change the table cycle size during execution. + + The end result is that all loads should always get one of the values from + the table. Any other pattern means the load failed. */ + +unsigned long long ret; +unsigned long long value = 0; +unsigned long long result = 0; +unsigned long long table[16] = { +0x0000000000000000, +0x1111111111111111, +0x2222222222222222, +0x3333333333333333, +0x4444444444444444, +0x5555555555555555, +0x6666666666666666, +0x7777777777777777, +0x8888888888888888, +0x9999999999999999, +0xAAAAAAAAAAAAAAAA, +0xBBBBBBBBBBBBBBBB, +0xCCCCCCCCCCCCCCCC, +0xDDDDDDDDDDDDDDDD, +0xEEEEEEEEEEEEEEEE, +0xFFFFFFFFFFFFFFFF +}; + +int table_cycle_size = 16; + +/* Return 0 if 'result' is a valid value to have loaded. */ +int verify_result () +{ + int x; + int found = 0; + + /* Check entire table for valid values. */ + for (x = 0; x < 16 ; x++) + if (result == table[x]) + { + found = 1; + break; + } + + if (!found) + printf("FAIL: Invalid result returned from fetch\n"); + + return !found; +} + +/* Iterate VALUE through the different valid values. */ +void simulate_thread_other_threads () +{ + static int current = 0; + + if (++current >= table_cycle_size) + current = 0; + value = table[current]; +} + +int simulate_thread_step_verify () +{ + return verify_result (); +} + +int simulate_thread_final_verify () +{ + return verify_result (); +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + int x; + + /* Execute loads with value changing at various cyclic values. */ + for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--) + { + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + /* In order to verify the returned value (which is not atomic), it needs + to be atomically stored into another variable and check that. */ + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + + /* Execute the fetch/store a couple of times just to ensure the cycles + have a chance to be interesting. */ + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + } +} + +main() +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-load-short.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,116 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_char_short } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + + +/* Testing load for atomicity is a little trickier. + + Set up the atomic value so that it changes value after every instruction + is executed. + + Simply alternating between 2 values wouldn't be sufficient since a load of + one part, followed by the load of the second part 2 instructions later would + appear to be valid. + + set up a table of 16 values which change a bit in every byte of the value + each time, this will give us a 16 instruction cycle before repetition + kicks in, which should be sufficient to detect any issues. Just to be sure, + we also change the table cycle size during execution. + + The end result is that all loads should always get one of the values from + the table. Any other pattern means the load failed. */ + +unsigned short ret; +unsigned short value = 0; +unsigned short result = 0; +unsigned short table[16] = { +0x0000, +0x1111, +0x2222, +0x3333, +0x4444, +0x5555, +0x6666, +0x7777, +0x8888, +0x9999, +0xAAAA, +0xBBBB, +0xCCCC, +0xDDDD, +0xEEEE, +0xFFFF +}; + +int table_cycle_size = 16; + +/* Return 0 if 'result' is a valid value to have loaded. */ +int verify_result () +{ + int x; + int found = 0; + + /* Check entire table for valid values. */ + for (x = 0; x < 16 ; x++) + if (result == table[x]) + { + found = 1; + break; + } + + if (!found) + printf("FAIL: Invalid result returned from fetch\n"); + + return !found; +} + +/* Iterate VALUE through the different valid values. */ +void simulate_thread_other_threads () +{ + static int current = 0; + + if (++current >= table_cycle_size) + current = 0; + value = table[current]; +} + +int simulate_thread_step_verify () +{ + return verify_result (); +} + +int simulate_thread_final_verify () +{ + return verify_result (); +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + int x; + + /* Execute loads with value changing at various cyclic values. */ + for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--) + { + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + /* In order to verify the returned value (which is not atomic), it needs + to be atomically stored into another variable and check that. */ + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + + /* Execute the fetch/store a couple of times just to ensure the cycles + have a chance to be interesting. */ + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + } +} + +main() +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-other-longlong.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,117 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + +/* Test all the __sync routines for proper atomicity on 8 byte values. */ + +unsigned long long zero = 0; +unsigned long long max = ~0; + +unsigned long long changing_value = 0; +unsigned long long value = 0; +unsigned long long ret; + +void test_abort() +{ + static int reported = 0; + if (!reported) + { + printf ("FAIL: improper execution of __sync builtin.\n"); + reported = 1; + } +} + +void simulate_thread_other_threads () +{ +} + +int simulate_thread_step_verify () +{ + if (value != zero && value != max) + { + printf ("FAIL: invalid intermediate result for value.\n"); + return 1; + } + return 0; +} + +int simulate_thread_final_verify () +{ + if (value != 0) + { + printf ("FAIL: invalid final result for value.\n"); + return 1; + } + return 0; +} + +/* All values written to 'value' alternate between 'zero' and 'max'. Any other + value detected by simulate_thread_step_verify() between instructions would indicate + that the value was only partially written, and would thus fail this + atomicity test. + + This function tests each different __atomic routine once, with the + exception of the load instruction which requires special testing. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST); + if (ret != zero || value != max) + test_abort(); + + __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST); + if (value != zero) + test_abort(); + + ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); + + ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); +} + +int main () +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-other-short.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,117 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_char_short } */ +/* { dg-final { simulate-thread } } */ + + +#include +#include "simulate-thread.h" + +/* Test all the __sync routines for proper atomicity on 2 byte values. */ + +unsigned short zero = 0; +unsigned short max = ~0; + +unsigned short changing_value = 0; +unsigned short value = 0; +unsigned short ret; + +void test_abort() +{ + static int reported = 0; + if (!reported) + { + printf ("FAIL: improper execution of __sync builtin.\n"); + reported = 1; + } +} + +void simulate_thread_other_threads () +{ +} + +int simulate_thread_step_verify () +{ + if (value != zero && value != max) + { + printf ("FAIL: invalid intermediate result for value.\n"); + return 1; + } + return 0; +} + +int simulate_thread_final_verify () +{ + if (value != 0) + { + printf ("FAIL: invalid final result for value.\n"); + return 1; + } + return 0; +} + +/* All values written to 'value' alternate between 'zero' and + 'max'. Any other value detected by simulate_thread_step_verify() + between instructions would indicate that the value was only + partially written, and would thus fail this atomicity test. + + This function tests each different __atomic routine once, with + the exception of the load instruction which requires special + testing. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + ret = __atomic_exchange_n (&value, max, __ATOMIC_SEQ_CST); + if (ret != zero || value != max) + test_abort(); + + __atomic_store_n (&value, zero, __ATOMIC_SEQ_CST); + if (value != zero) + test_abort(); + + ret = __atomic_fetch_add (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_sub (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_fetch_or (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != zero) + test_abort (); + + ret = __atomic_fetch_and (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_fetch_xor (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != max) + test_abort (); + + ret = __atomic_add_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_sub_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); + + ret = __atomic_or_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_and_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != max || ret != max) + test_abort (); + + ret = __atomic_xor_fetch (&value, max, __ATOMIC_SEQ_CST); + if (value != zero || ret != zero) + test_abort (); +} + +int main () +{ + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c =================================================================== --- gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/simulate-thread/atomic-load-int128.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,132 @@ +/* { dg-do link } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* i?86-*-* } } } */ +/* { dg-final { simulate-thread } } */ + +#include +#include "simulate-thread.h" + + +/* Testing load for atomicity is a little trickier. + + Set up the atomic value so that it changes value after every instruction + is executed. + + Simply alternating between 2 values wouldn't be sufficient since a load of + one part, followed by the load of the second part 2 instructions later would + appear to be valid. + + set up a table of 16 values which change a bit in every byte of the value + each time, this will give us a 16 instruction cycle before repetition + kicks in, which should be sufficient to detect any issues. Just to be sure, + we also change the table cycle size during execution. + + The end result is that all loads should always get one of the values from + the table. Any other pattern means the load failed. */ + +__int128_t ret; +__int128_t value = 0; +__int128_t result = 0; +__int128_t table[16] = { +0x0000000000000000, +0x1111111111111111, +0x2222222222222222, +0x3333333333333333, +0x4444444444444444, +0x5555555555555555, +0x6666666666666666, +0x7777777777777777, +0x8888888888888888, +0x9999999999999999, +0xAAAAAAAAAAAAAAAA, +0xBBBBBBBBBBBBBBBB, +0xCCCCCCCCCCCCCCCC, +0xDDDDDDDDDDDDDDDD, +0xEEEEEEEEEEEEEEEE, +0xFFFFFFFFFFFFFFFF +}; + +int table_cycle_size = 16; + +/* Since we don't have 128 bit constants, we have to properly pad the table. */ +void fill_table() +{ + int x; + for (x = 0; x < 16; x++) + { + ret = table[x]; + ret = (ret << 64) | ret; + table[x] = ret; + } +} + +/* Return 0 if 'result' is a valid value to have loaded. */ +int verify_result () +{ + int x; + int found = 0; + + /* Check entire table for valid values. */ + for (x = 0; x < 16; x++) + if (result == table[x]) + { + found = 1; + break; + } + + if (!found) + printf("FAIL: Invalid result returned from fetch\n"); + + return !found; +} + +/* Iterate VALUE through the different valid values. */ +void simulate_thread_other_threads () +{ + static int current = 0; + + if (++current >= table_cycle_size) + current = 0; + value = table[current]; +} + +int simulate_thread_step_verify () +{ + return verify_result (); +} + +int simulate_thread_final_verify () +{ + return verify_result (); +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + int x; + + /* Make sure value starts with an atomic value now. */ + __atomic_store_n (&value, ret, __ATOMIC_SEQ_CST); + + /* Execute loads with value changing at various cyclic values. */ + for (table_cycle_size = 16; table_cycle_size > 4 ; table_cycle_size--) + { + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + /* In order to verify the returned value (which is not atomic), it needs + to be atomically stored into another variable and check that. */ + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + + /* Execute the fetch/store a couple of times just to ensure the cycles + have a chance to be interesting. */ + ret = __atomic_load_n (&value, __ATOMIC_SEQ_CST); + __atomic_store_n (&result, ret, __ATOMIC_SEQ_CST); + } +} + +main() +{ + fill_table (); + simulate_thread_main (); + simulate_thread_done (); + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-compare-exchange-1.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-compare-exchange-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-compare-exchange-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,85 @@ +/* Test __atomic routines for existence and proper execution on 1 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_compare_exchange_n builtin for a char. */ + +extern void abort(void); + +char v = 0; +char expected = 0; +char max = ~0; +char desired = ~0; +char zero = 0; + +#define STRONG 0 +#define WEAK 1 + +main () +{ + + if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + /* Now test the generic version. */ + + v = 0; + + if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-store-4.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-store-4.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-store-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,48 @@ +/* Test __atomic routines for existence and proper execution on 8 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ + +/* Test the execution of the __atomic_store_n builtin for a long long. */ + +extern void abort(void); + +long long v, count; + +main () +{ + v = 0; + count = 0; + + __atomic_store_n (&v, count + 1, __ATOMIC_RELAXED); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_RELEASE); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != ++count) + abort (); + + /* Now test the generic variant. */ + count++; + + __atomic_store (&v, &count, __ATOMIC_RELAXED); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_RELEASE); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_SEQ_CST); + if (v != count) + abort (); + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-load-1.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-load-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-load-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,66 @@ +/* Test __atomic routines for existence and proper execution on 1 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + + +/* Test the execution of the __atomic_load_n builtin for a char. */ + +extern void abort(void); + +char v, count; + +main () +{ + v = 0; + count = 0; + + if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++) + abort(); + else + v++; + + /* Now test the generic variants. */ + + __atomic_load (&v, &count, __ATOMIC_RELAXED); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_ACQUIRE); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_CONSUME); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_SEQ_CST); + if (count != v) + abort(); + else + v++; + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-compare-exchange-5.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-compare-exchange-5.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-compare-exchange-5.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,86 @@ +/* Test __atomic routines for existence and proper execution on 16 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* } } } */ + +/* Test the execution of __atomic_compare_exchange_n builtin for an int_128. */ + +extern void abort(void); + +__int128_t v = 0; +__int128_t expected = 0; +__int128_t max = ~0; +__int128_t desired = ~0; +__int128_t zero = 0; + +#define STRONG 0 +#define WEAK 1 + +main () +{ + + if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + /* Now test the generic version. */ + + v = 0; + + if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-load-5.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-load-5.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-load-5.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,65 @@ +/* Test __atomic routines for existence and proper execution on 16 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* } } } */ + +extern void abort(void); + +__int128_t v, count; + +main () +{ + v = 0; + count = 0; + + if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++) + abort(); + else + v++; + + /* Now test the generic variants. */ + + __atomic_load (&v, &count, __ATOMIC_RELAXED); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_ACQUIRE); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_CONSUME); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_SEQ_CST); + if (count != v) + abort(); + else + v++; + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-exchange-4.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-exchange-4.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-exchange-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,63 @@ +/* Test __atomic routines for existence and proper execution on 8 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ + +/* Test the execution of the __atomic_X builtin for a long_long. */ + +extern void abort(void); + +long long v, count, ret; + +main () +{ + v = 0; + count = 0; + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) + abort (); + + /* Now test the generic version. */ + + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); + if (ret != count - 1 || v != count) + abort (); + count++; + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-lockfree.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-lockfree.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-lockfree.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,120 @@ +/* Test __atomic routines for existence and execution with each valid + memory model. */ +/* { dg-options "-w" } */ +/* { dg-do run } */ +/* { dg-additional-sources "atomic-lockfree-aux.c" } */ + +/* Test that __atomic_{is,always}_lock_free builtins execute. + sync-mem-lockfree-aux.c supplies and external entry point for + __atomic_is_lock_free which always returns a 2. We can detect the + external routine was called if 2 is returned since that is not a valid + result normally. */ + +#include + +extern void abort(); + +int r1, r2; + +/* Test for consistency on sizes 1, 2, 4, 8, 16 and 32. */ +main () +{ + + r1 = __atomic_always_lock_free (sizeof(char), 0); + r2 = __atomic_is_lock_free (sizeof(char), 0); + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + r1 = __atomic_always_lock_free (2, 0); + r2 = __atomic_is_lock_free (2, 0); + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + + r1 = __atomic_always_lock_free (4, 0); + r2 = __atomic_is_lock_free (4, 0); /* Try passing in a variable. */ + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + + r1 = __atomic_always_lock_free (8, 0); + r2 = __atomic_is_lock_free (8, 0); + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + + r1 = __atomic_always_lock_free (16, 0); + r2 = __atomic_is_lock_free (16, 0); + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + + r1 = __atomic_always_lock_free (32, 0); + r2 = __atomic_is_lock_free (32, 0); + /* If always lock free, then is_lock_free must also be true. */ + if (r1) + { + if (r2 != 1) + abort (); + } + else + { + /* If it is not lock free, then the external routine must be called. */ + if (r2 != 2) + abort (); + } + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-op-4.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-op-4.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-op-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,555 @@ +/* Test __atomic routines for existence and proper execution on 8 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_long_long } */ +/* { dg-options "" } */ + +/* Test the execution of the __atomic_*OP builtin routines for long long. */ + +extern void abort(void); + +long long v, count, res; +const long long init = ~0; + +/* The fetch_op routines return the original value before the operation. */ + +void +test_fetch_add () +{ + v = 0; + count = 1; + + if (__atomic_fetch_add (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_CONSUME) != 1) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQUIRE) != 2) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_RELEASE) != 3) + abort (); + + if (__atomic_fetch_add (&v, count, __ATOMIC_ACQ_REL) != 4) + abort (); + + if (__atomic_fetch_add (&v, 1, __ATOMIC_SEQ_CST) != 5) + abort (); +} + + +void +test_fetch_sub() +{ + v = res = 20; + count = 0; + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_RELAXED) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_CONSUME) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQUIRE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE) != res--) + abort (); + + if (__atomic_fetch_sub (&v, count + 1, __ATOMIC_ACQ_REL) != res--) + abort (); + + if (__atomic_fetch_sub (&v, 1, __ATOMIC_SEQ_CST) != res--) + abort (); +} + +void +test_fetch_and () +{ + v = init; + + if (__atomic_fetch_and (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_and (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_fetch_and (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_fetch_nand () +{ + v = init; + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_ACQUIRE) != 0 ) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL) != 0) + abort (); + + if (__atomic_fetch_nand (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_xor () +{ + v = init; + count = 0; + + if (__atomic_fetch_xor (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_fetch_xor (&v, ~count, __ATOMIC_SEQ_CST) != init) + abort (); +} + +void +test_fetch_or () +{ + v = 0; + count = 1; + + if (__atomic_fetch_or (&v, count, __ATOMIC_RELAXED) != 0) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 2, __ATOMIC_CONSUME) != 1) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, 8, __ATOMIC_RELEASE) != 7) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_ACQ_REL) != 15) + abort (); + + count *= 2; + if (__atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST) != 31) + abort (); +} + +/* The OP_fetch routines return the new value after the operation. */ + +void +test_add_fetch () +{ + v = 0; + count = 1; + + if (__atomic_add_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_CONSUME) != 2) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQUIRE) != 3) + abort (); + + if (__atomic_add_fetch (&v, 1, __ATOMIC_RELEASE) != 4) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL) != 5) + abort (); + + if (__atomic_add_fetch (&v, count, __ATOMIC_SEQ_CST) != 6) + abort (); +} + + +void +test_sub_fetch () +{ + v = res = 20; + count = 0; + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_CONSUME) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQUIRE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, 1, __ATOMIC_RELEASE) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL) != --res) + abort (); + + if (__atomic_sub_fetch (&v, count + 1, __ATOMIC_SEQ_CST) != --res) + abort (); +} + +void +test_and_fetch () +{ + v = init; + + if (__atomic_and_fetch (&v, 0, __ATOMIC_RELAXED) != 0) + abort (); + + v = init; + if (__atomic_and_fetch (&v, init, __ATOMIC_CONSUME) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, init, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL) != 0) + abort (); + + v = ~v; + if (__atomic_and_fetch (&v, 0, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_nand_fetch () +{ + v = init; + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE) != init) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_RELEASE) != 0) + abort (); + + if (__atomic_nand_fetch (&v, init, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST) != init) + abort (); +} + + + +void +test_xor_fetch () +{ + v = init; + count = 0; + + if (__atomic_xor_fetch (&v, count, __ATOMIC_RELAXED) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_CONSUME) != 0) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE) != 0) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_RELEASE) != init) + abort (); + + if (__atomic_xor_fetch (&v, 0, __ATOMIC_ACQ_REL) != init) + abort (); + + if (__atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST) != 0) + abort (); +} + +void +test_or_fetch () +{ + v = 0; + count = 1; + + if (__atomic_or_fetch (&v, count, __ATOMIC_RELAXED) != 1) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 2, __ATOMIC_CONSUME) != 3) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQUIRE) != 7) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, 8, __ATOMIC_RELEASE) != 15) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL) != 31) + abort (); + + count *= 2; + if (__atomic_or_fetch (&v, count, __ATOMIC_SEQ_CST) != 63) + abort (); +} + + +/* Test the OP routines with a result which isn't used. Use both variations + within each function. */ + +void +test_add () +{ + v = 0; + count = 1; + + __atomic_add_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_CONSUME); + if (v != 2) + abort (); + + __atomic_add_fetch (&v, 1 , __ATOMIC_ACQUIRE); + if (v != 3) + abort (); + + __atomic_fetch_add (&v, 1, __ATOMIC_RELEASE); + if (v != 4) + abort (); + + __atomic_add_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 5) + abort (); + + __atomic_fetch_add (&v, count, __ATOMIC_SEQ_CST); + if (v != 6) + abort (); +} + + +void +test_sub() +{ + v = res = 20; + count = 0; + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_RELAXED); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_CONSUME); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, 1, __ATOMIC_ACQUIRE); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, 1, __ATOMIC_RELEASE); + if (v != --res) + abort (); + + __atomic_sub_fetch (&v, count + 1, __ATOMIC_ACQ_REL); + if (v != --res) + abort (); + + __atomic_fetch_sub (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != --res) + abort (); +} + +void +test_and () +{ + v = init; + + __atomic_and_fetch (&v, 0, __ATOMIC_RELAXED); + if (v != 0) + abort (); + + v = init; + __atomic_fetch_and (&v, init, __ATOMIC_CONSUME); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, init, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_and_fetch (&v, 0, __ATOMIC_ACQ_REL); + if (v != 0) + abort (); + + v = ~v; + __atomic_fetch_and (&v, 0, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_nand () +{ + v = init; + + __atomic_fetch_nand (&v, 0, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, init, __ATOMIC_RELEASE); + if (v != 0) + abort (); + + __atomic_fetch_nand (&v, init, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_nand_fetch (&v, 0, __ATOMIC_SEQ_CST); + if (v != init) + abort (); +} + + + +void +test_xor () +{ + v = init; + count = 0; + + __atomic_xor_fetch (&v, count, __ATOMIC_RELAXED); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_CONSUME); + if (v != 0) + abort (); + + __atomic_xor_fetch (&v, 0, __ATOMIC_ACQUIRE); + if (v != 0) + abort (); + + __atomic_fetch_xor (&v, ~count, __ATOMIC_RELEASE); + if (v != init) + abort (); + + __atomic_fetch_xor (&v, 0, __ATOMIC_ACQ_REL); + if (v != init) + abort (); + + __atomic_xor_fetch (&v, ~count, __ATOMIC_SEQ_CST); + if (v != 0) + abort (); +} + +void +test_or () +{ + v = 0; + count = 1; + + __atomic_or_fetch (&v, count, __ATOMIC_RELAXED); + if (v != 1) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_CONSUME); + if (v != 3) + abort (); + + count *= 2; + __atomic_or_fetch (&v, 4, __ATOMIC_ACQUIRE); + if (v != 7) + abort (); + + count *= 2; + __atomic_fetch_or (&v, 8, __ATOMIC_RELEASE); + if (v != 15) + abort (); + + count *= 2; + __atomic_or_fetch (&v, count, __ATOMIC_ACQ_REL); + if (v != 31) + abort (); + + count *= 2; + __atomic_fetch_or (&v, count, __ATOMIC_SEQ_CST); + if (v != 63) + abort (); +} + +main () +{ + test_fetch_add (); + test_fetch_sub (); + test_fetch_and (); + test_fetch_nand (); + test_fetch_xor (); + test_fetch_or (); + + test_add_fetch (); + test_sub_fetch (); + test_and_fetch (); + test_nand_fetch (); + test_xor_fetch (); + test_or_fetch (); + + test_add (); + test_sub (); + test_and (); + test_nand (); + test_xor (); + test_or (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-param.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-param.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-param.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,13 @@ +/* Test __atomic routines for invalid memory model errors. This only needs + to be tested on a single size. */ +/* { dg-do compile } */ +/* { dg-require-effective-target sync_int_long } */ + +int i; + +main () +{ + + __atomic_exchange_n (&i, 1); /* { dg-error "too few arguments" } */ + __atomic_exchange_n (&i, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); /* { dg-error "too many arguments" } */ +} Index: gcc/testsuite/gcc.dg/atomic-store-1.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-store-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-store-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,47 @@ +/* Test __atomic routines for existence and proper execution on 1 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_store_n builtin for a char. */ + +extern void abort(void); + +char v, count; + +main () +{ + v = 0; + count = 0; + + __atomic_store_n (&v, count + 1, __ATOMIC_RELAXED); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_RELEASE); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != ++count) + abort (); + + /* Now test the generic variant. */ + count++; + + __atomic_store (&v, &count, __ATOMIC_RELAXED); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_RELEASE); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_SEQ_CST); + if (v != count) + abort (); + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-compare-exchange-2.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-compare-exchange-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-compare-exchange-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,85 @@ +/* Test __atomic routines for existence and proper execution on 2 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_compare_exchange_n builtin for a short. */ + +extern void abort(void); + +short v = 0; +short expected = 0; +short max = ~0; +short desired = ~0; +short zero = 0; + +#define STRONG 0 +#define WEAK 1 + +main () +{ + + if (!__atomic_compare_exchange_n (&v, &expected, max, STRONG , __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, 0, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange_n (&v, &expected, desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange_n (&v, &expected, desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + /* Now test the generic version. */ + + v = 0; + + if (!__atomic_compare_exchange (&v, &expected, &max, STRONG, __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + abort (); + if (expected != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) + abort (); + if (expected != max) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &zero, STRONG , __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) + abort (); + if (expected != max) + abort (); + if (v != 0) + abort (); + + if (__atomic_compare_exchange (&v, &expected, &desired, WEAK, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)) + abort (); + if (expected != 0) + abort (); + + if (!__atomic_compare_exchange (&v, &expected, &desired, STRONG , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) + abort (); + if (expected != 0) + abort (); + if (v != max) + abort (); + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-store-5.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-store-5.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-store-5.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,48 @@ +/* Test __atomic routines for existence and proper execution on 16 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_int_128 } */ +/* { dg-options "-mcx16" { target { x86_64-*-* } } } */ + +/* Test the execution of the __atomic_store_n builtin for a 16 byte value. */ + +extern void abort(void); + +__int128_t v, count; + +main () +{ + v = 0; + count = 0; + + __atomic_store_n (&v, count + 1, __ATOMIC_RELAXED); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_RELEASE); + if (v != ++count) + abort (); + + __atomic_store_n (&v, count + 1, __ATOMIC_SEQ_CST); + if (v != ++count) + abort (); + + /* Now test the generic variant. */ + count++; + + __atomic_store (&v, &count, __ATOMIC_RELAXED); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_RELEASE); + if (v != count++) + abort (); + + __atomic_store (&v, &count, __ATOMIC_SEQ_CST); + if (v != count) + abort (); + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-load-2.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-load-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-load-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,68 @@ +/* Test __atomic routines for existence and proper execution on 2 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + + +/* Test the execution of the __atomic_load_n builtin for a short. */ + +extern void abort(void); + +short v, count; + + +main () +{ + v = 0; + count = 0; + + if (__atomic_load_n (&v, __ATOMIC_RELAXED) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_ACQUIRE) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_CONSUME) != count++) + abort(); + else + v++; + + if (__atomic_load_n (&v, __ATOMIC_SEQ_CST) != count++) + abort(); + else + v++; + + /* Now test the generic variants. */ + + __atomic_load (&v, &count, __ATOMIC_RELAXED); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_ACQUIRE); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_CONSUME); + if (count != v) + abort(); + else + v++; + + __atomic_load (&v, &count, __ATOMIC_SEQ_CST); + if (count != v) + abort(); + else + v++; + + + return 0; +} + Index: gcc/testsuite/gcc.dg/atomic-exchange-1.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-exchange-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-exchange-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,62 @@ +/* Test __atomic routines for existence and proper execution on 1 byte + values with each valid memory model. */ +/* { dg-do run } */ +/* { dg-require-effective-target sync_char_short } */ + +/* Test the execution of the __atomic_exchange_n builtin for a char. */ + +extern void abort(void); + +char v, count, ret; + +main () +{ + v = 0; + count = 0; + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELAXED) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQUIRE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_RELEASE) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_ACQ_REL) != count++) + abort (); + + if (__atomic_exchange_n (&v, count + 1, __ATOMIC_SEQ_CST) != count++) + abort (); + + /* Now test the generic version. */ + + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELAXED); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQUIRE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_RELEASE); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_ACQ_REL); + if (ret != count - 1 || v != count) + abort (); + count++; + + __atomic_exchange (&v, &count, &ret, __ATOMIC_SEQ_CST); + if (ret != count - 1 || v != count) + abort (); + count++; + + return 0; +} Index: gcc/testsuite/gcc.dg/atomic-noinline-aux.c =================================================================== --- gcc/testsuite/gcc.dg/atomic-noinline-aux.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.dg/atomic-noinline-aux.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,51 @@ +/* Supply a set of generic atomic functions to test the compiler make the + calls properly. */ +/* { dg-do compile } */ +/* { dg-options "-w" } */ + +/* Test that the generic builtins make calls as expected. This file provides + the exact entry points the test file will require. All these routines + simply set the first parameter to 1, and the caller will test for that. */ + +#include +#include +#include + + +char +__atomic_exchange_1 (char *p, char t, int i) +{ + *p = 1; +} + +short +__atomic_load_2 (short *p, int i) +{ + *p = 1; +} + +void +__atomic_store_1 (char *p, char v, int i) +{ + *p = 1; +} + +int __atomic_compare_exchange_2 (short *p, short *a, short b, int x, int y, int z) +{ + *p = 1; +} + +char __atomic_fetch_add_1 (char *p, char v, int i) +{ + *p = 1; +} + +short __atomic_fetch_add_2 (short *p, short v, short i) +{ + *p = 1; +} + +int __atomic_is_lock_free (int i, void *p) +{ + return 10; +} Index: gcc/testsuite/g++.dg/simulate-thread/atomics-2.C =================================================================== --- gcc/testsuite/g++.dg/simulate-thread/atomics-2.C (.../trunk) (revision 0) +++ gcc/testsuite/g++.dg/simulate-thread/atomics-2.C (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,58 @@ +/* { dg-do link } */ +/* { dg-options "-std=c++0x" } */ +/* { dg-final { simulate-thread } } */ + +using namespace std; + +#include +#include +#include +#include "simulate-thread.h" + +atomic_int atomi; + +/* Non-atomic. Use a type wide enough to possibly coerce GCC into + moving things around. */ +long double j; + + +/* Test that an atomic store synchronizes with an atomic load. + + In this case, test that the store to happens-before the atomic + store to . Make sure the compiler does not reorder the + stores. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + j = 13.0; + atomi.store(1); +} + +int main () +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} + +void simulate_thread_other_threads() +{ +} + +/* Verify that side-effects before an atomic store are correctly + synchronized with the an atomic load to the same location. */ +int simulate_thread_step_verify() +{ + if (atomi.load() == 1 && j != 13.0) + { + printf ("FAIL: invalid synchronization for atomic load/store.\n"); + return 1; + } + return 0; +} + + +int simulate_thread_final_verify() +{ + return simulate_thread_step_verify(); +} Index: gcc/testsuite/g++.dg/simulate-thread/bitfields-2.C =================================================================== --- gcc/testsuite/g++.dg/simulate-thread/bitfields-2.C (.../trunk) (revision 0) +++ gcc/testsuite/g++.dg/simulate-thread/bitfields-2.C (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,77 @@ +/* { dg-do link } */ +/* { dg-options "--param allow-load-data-races=0 --param allow-store-data-races=0" } */ +/* { dg-final { simulate-thread } } */ + +/* Test that setting does not touch either or . + In the C++ memory model, non contiguous bitfields ("a" and "c" + here) should be considered as distinct memory locations, so we + can't use bit twiddling to set either one. */ + +#include +#include "simulate-thread.h" + +#define CONSTA 12 + +static int global; +struct S +{ + unsigned int a : 4; + unsigned char b; + unsigned int c : 6; +} var; + +__attribute__((noinline)) +void set_a() +{ + var.a = CONSTA; +} + +void simulate_thread_other_threads() +{ + ++global; + var.b = global; + var.c = global; +} + +int simulate_thread_step_verify() +{ + int ret = 0; + if (var.b != global) + { + printf ("FAIL: Unexpected value: var.b is %d, should be %d\n", + var.b, global); + ret = 1; + } + if (var.c != global) + { + printf ("FAIL: Unexpected value: var.c is %d, should be %d\n", + var.c, global); + ret = 1; + } + return ret; +} + +int simulate_thread_final_verify() +{ + int ret = simulate_thread_step_verify(); + if (var.a != CONSTA) + { + printf ("FAIL: Unexpected value: var.a is %d, should be %d\n", + var.a, CONSTA); + ret = 1; + } + return ret; +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + set_a(); +} + +int main() +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} Index: gcc/testsuite/g++.dg/simulate-thread/bitfields.C =================================================================== --- gcc/testsuite/g++.dg/simulate-thread/bitfields.C (.../trunk) (revision 0) +++ gcc/testsuite/g++.dg/simulate-thread/bitfields.C (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,80 @@ +/* { dg-do link } */ +/* { dg-options "--param allow-load-data-races=0 --param allow-store-data-races=0" } */ +/* { dg-final { simulate-thread } } */ + +/* Test that setting does not touch either or . + In the C++ memory model, non contiguous bitfields ("a" and "c" + here) should be considered as distinct memory locations, so we + can't use bit twiddling to set either one. */ + +#include +#include "simulate-thread.h" + +#define CONSTA 12 + +static int global; +struct S +{ + /* On x86-64, the volatile causes us to access with a 32-bit + access, and thus trigger this test. */ + volatile unsigned int a : 4; + + unsigned char b; + unsigned int c : 6; +} var; + +__attribute__((noinline)) +void set_a() +{ + var.a = CONSTA; +} + +void simulate_thread_other_threads() +{ + ++global; + var.b = global; + var.c = global; +} + +int simulate_thread_step_verify() +{ + int ret = 0; + if (var.b != global) + { + printf ("FAIL: Unexpected value: var.b is %d, should be %d\n", + var.b, global); + ret = 1; + } + if (var.c != global) + { + printf ("FAIL: Unexpected value: var.c is %d, should be %d\n", + var.c, global); + ret = 1; + } + return ret; +} + +int simulate_thread_final_verify() +{ + int ret = simulate_thread_step_verify(); + if (var.a != CONSTA) + { + printf ("FAIL: Unexpected value: var.a is %d, should be %d\n", + var.a, CONSTA); + ret = 1; + } + return ret; +} + +__attribute__((noinline)) +void simulate_thread_main() +{ + set_a(); +} + +int main () +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} Index: gcc/testsuite/g++.dg/simulate-thread/atomics-1.C =================================================================== --- gcc/testsuite/g++.dg/simulate-thread/atomics-1.C (.../trunk) (revision 0) +++ gcc/testsuite/g++.dg/simulate-thread/atomics-1.C (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,73 @@ +/* { dg-do link } */ +/* { dg-options "-std=c++0x" } */ +/* { dg-final { simulate-thread } } */ + +/* Test that atomic int and atomic char work properly. */ + +using namespace std; + +#include +#include +#include +#include "simulate-thread.h" + +atomic atomi; +atomic atomc; + +/* No need for parallel threads to do anything */ +void simulate_thread_other_threads() +{ +} + +/* Verify after every instruction is executed, that the atmoic int and + char have one of the 2 legitimate values. */ +int simulate_thread_step_verify() +{ + if (atomi != 0 && atomi != INT_MAX) + { + printf ("FAIL: invalid intermediate result for atomi (%d).\n", + (int)atomi); + return 1; + } + if (atomc != 0 && atomc != CHAR_MAX) + { + printf ("FAIL: invalid intermediate result for atomc (%d).\n", + (int)atomc); + return 1; + } + return 0; +} + + +/* Verify that both atmoics have the corerct value. */ +int simulate_thread_final_verify() +{ + if (atomi != INT_MAX) + { + printf ("FAIL: invalid final result for atomi (%d).\n", + (int)atomi); + return 1; + } + if (atomc != CHAR_MAX) + { + printf ("FAIL: invalid final result for atomc (%d).\n", + (int)atomc); + return 1; + } + return 0; +} + +/* Test a store to an atomic int and an atomic char. */ +__attribute__((noinline)) +void simulate_thread_main() +{ + atomi = INT_MAX; + atomc = CHAR_MAX; +} + +int main () +{ + simulate_thread_main(); + simulate_thread_done(); + return 0; +} Index: gcc/testsuite/g++.dg/gomp/atomic-4.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-4.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-4.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,24 +0,0 @@ -/* { dg-do compile } */ - -int a[4]; -int *p; -struct S { int x; int y[4]; } s; -int *bar(void); - -void f1(void) -{ - #pragma omp atomic - a[4] += 1; - #pragma omp atomic - *p += 1; - #pragma omp atomic - s.x += 1; - #pragma omp atomic - s.y[*p] += 1; - #pragma omp atomic - s.y[*p] *= 42; - #pragma omp atomic - *bar() += 1; - #pragma omp atomic - *bar() *= 42; -} Index: gcc/testsuite/g++.dg/gomp/atomic-8.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-8.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-8.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,21 +0,0 @@ -/* { dg-do compile } */ - -long double z; - -void f3(void) -{ - #pragma omp atomic - z++; - #pragma omp atomic - z--; - #pragma omp atomic - ++z; - #pragma omp atomic - --z; - #pragma omp atomic - z += 1; - #pragma omp atomic - z *= 3; - #pragma omp atomic - z /= 3; -} Index: gcc/testsuite/g++.dg/gomp/atomic-11.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-11.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-11.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,306 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-gimple -g0" } */ -/* atomicvar should never be referenced in between the barrier and - following #pragma omp atomic_load. */ -/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ -/* { dg-final { cleanup-tree-dump "gimple" } } */ - -#ifdef __cplusplus -bool atomicvar, c; -#else -_Bool atomicvar, c; -#endif -int i, atomicvar2, c2; - -int -foo (void) -{ - #pragma omp barrier - #pragma omp atomic - atomicvar |= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar |= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar |= c; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar ^= c; - #pragma omp barrier - #pragma omp atomic - atomicvar &= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar &= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar &= c; - #pragma omp barrier - #pragma omp atomic - atomicvar += -1; - #pragma omp barrier - #pragma omp atomic - atomicvar += 0; - #pragma omp barrier - #pragma omp atomic - atomicvar += 1; - #pragma omp barrier - #pragma omp atomic - atomicvar += 2; - #pragma omp barrier - #pragma omp atomic - atomicvar += c; - #pragma omp barrier - #pragma omp atomic - atomicvar -= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar -= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar -= c; - #pragma omp barrier - #pragma omp atomic - atomicvar *= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar *= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar *= c; - #pragma omp barrier - #pragma omp atomic - atomicvar /= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar /= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar /= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar /= c; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar <<= i; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar >>= i; - #pragma omp barrier - #pragma omp atomic - atomicvar++; - #pragma omp barrier - #pragma omp atomic - ++atomicvar; - #pragma omp barrier -#ifndef __cplusplus - #pragma omp atomic - atomicvar--; - #pragma omp barrier - #pragma omp atomic - --atomicvar; - #pragma omp barrier -#endif - return 0; -} - -int -bar (void) -{ - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 |= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 ^= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 &= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 += c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 -= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 *= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= -1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 /= c2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 <<= i; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 0; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 1; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= 2; - #pragma omp barrier - #pragma omp atomic - atomicvar2 >>= i; - #pragma omp barrier - #pragma omp atomic - atomicvar2++; - #pragma omp barrier - #pragma omp atomic - ++atomicvar2; - #pragma omp barrier - #pragma omp atomic - atomicvar2--; - #pragma omp barrier - #pragma omp atomic - --atomicvar2; - #pragma omp barrier - return 0; -} Index: gcc/testsuite/g++.dg/gomp/atomic-15.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-15.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-15.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,46 +0,0 @@ -// { dg-do compile } -// { dg-options "-fopenmp" } - -int x = 6; - -int -main () -{ - int v; - #pragma omp atomic - x = x * 7 + 6; // { dg-error "expected" } - #pragma omp atomic - x = x * 7 ^ 6; // { dg-error "expected" } - #pragma omp atomic update - x = x - 8 + 6; // { dg-error "expected" } - #pragma omp atomic - x = x ^ 7 | 2; // { dg-error "expected" } - #pragma omp atomic - x = x / 7 * 2; // { dg-error "expected" } - #pragma omp atomic - x = x / 7 / 2; // { dg-error "expected" } - #pragma omp atomic capture - v = x = x | 6; // { dg-error "invalid operator" } - #pragma omp atomic capture - { v = x; x = x * 7 + 6; } // { dg-error "expected" } - #pragma omp atomic capture - { v = x; x = x * 7 ^ 6; } // { dg-error "expected" } - #pragma omp atomic capture - { v = x; x = x - 8 + 6; } // { dg-error "expected" } - #pragma omp atomic capture - { v = x; x = x ^ 7 | 2; } // { dg-error "expected" } - #pragma omp atomic capture - { v = x; x = x / 7 * 2; } // { dg-error "expected" } - #pragma omp atomic capture - { v = x; x = x / 7 / 2; } // { dg-error "expected" } - #pragma omp atomic capture - { x = x * 7 + 6; v = x; } // { dg-error "expected" } - #pragma omp atomic capture - { x = x * 7 ^ 6; v = x; } // { dg-error "expected" } - #pragma omp atomic capture - { x = x - 8 + 6; v = x; } // { dg-error "expected" } - #pragma omp atomic capture - { x = x ^ 7 | 2; v = x; } // { dg-error "expected" } - (void) v; - return 0; -} Index: gcc/testsuite/g++.dg/gomp/atomic-1.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-1.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-1.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,99 +0,0 @@ -/* { dg-do compile } */ - -int x; -volatile int y; -volatile unsigned char z; - -void f1(void) -{ - #pragma omp atomic - x++; - #pragma omp atomic - x--; - #pragma omp atomic - ++x; - #pragma omp atomic - --x; - #pragma omp atomic - x += 1; - #pragma omp atomic - x -= y; - #pragma omp atomic - x |= 1; - #pragma omp atomic - x &= 1; - #pragma omp atomic - x ^= 1; - #pragma omp atomic - x *= 3; - #pragma omp atomic - x /= 3; - #pragma omp atomic - x /= 3; - #pragma omp atomic - x <<= 3; - #pragma omp atomic - x >>= 3; -} - -void f2(void) -{ - #pragma omp atomic - y++; - #pragma omp atomic - y--; - #pragma omp atomic - ++y; - #pragma omp atomic - --y; - #pragma omp atomic - y += 1; - #pragma omp atomic - y -= x; - #pragma omp atomic - y |= 1; - #pragma omp atomic - y &= 1; - #pragma omp atomic - y ^= 1; - #pragma omp atomic - y *= 3; - #pragma omp atomic - y /= 3; - #pragma omp atomic - y /= 3; - #pragma omp atomic - y <<= 3; - #pragma omp atomic - y >>= 3; -} - -void f3(void) -{ - #pragma omp atomic - z++; - #pragma omp atomic - z--; - #pragma omp atomic - ++z; - #pragma omp atomic - --z; - #pragma omp atomic - z += 1; - #pragma omp atomic - z |= 1; - #pragma omp atomic - z &= 1; - #pragma omp atomic - z ^= 1; - #pragma omp atomic - z *= 3; - #pragma omp atomic - z /= 3; - #pragma omp atomic - z /= 3; - #pragma omp atomic - z <<= 3; - #pragma omp atomic - z >>= 3; -} Index: gcc/testsuite/g++.dg/gomp/atomic-9.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-9.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-9.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,13 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ - -volatile int *bar(void); - -void f1(void) -{ - #pragma omp atomic - *bar() += 1; -} - -/* { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 1 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ -/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/g++.dg/gomp/atomic-12.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-12.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-12.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,9 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-gimple -g0 -O2" } */ -/* atomicvar should never be referenced in between the barrier and - following #pragma omp atomic_load. */ -/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ -/* { dg-final { cleanup-tree-dump "gimple" } } */ - -#include "atomic-11.C" Index: gcc/testsuite/g++.dg/gomp/atomic-2.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-2.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-2.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,23 +0,0 @@ -/* { dg-do compile } */ - -float x, y; - -void f1(void) -{ - #pragma omp atomic - x++; - #pragma omp atomic - x--; - #pragma omp atomic - ++x; - #pragma omp atomic - --x; - #pragma omp atomic - x += 1; - #pragma omp atomic - x -= y; - #pragma omp atomic - x *= 3; - #pragma omp atomic - x /= 3; -} Index: gcc/testsuite/g++.dg/gomp/atomic-13.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-13.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-13.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,43 +0,0 @@ -/* PR middle-end/45423 */ -/* { dg-do compile } */ -/* { dg-options "-fopenmp" } */ - -#ifdef __cplusplus -bool *baz (); -#else -_Bool *baz (); -#endif -int *bar (); - -int -foo (void) -{ - #pragma omp barrier - #pragma omp atomic - (*bar ())++; - #pragma omp barrier - #pragma omp atomic - ++(*bar ()); - #pragma omp barrier - #pragma omp atomic - (*bar ())--; - #pragma omp barrier - #pragma omp atomic - --(*bar ()); - #pragma omp barrier - #pragma omp atomic - (*baz ())++; - #pragma omp barrier - #pragma omp atomic - ++(*baz ()); -#ifndef __cplusplus - #pragma omp barrier - #pragma omp atomic - (*baz ())--; - #pragma omp barrier - #pragma omp atomic - --(*baz ()); - #pragma omp barrier -#endif - return 0; -} Index: gcc/testsuite/g++.dg/gomp/atomic-3.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-3.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-3.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,13 +0,0 @@ -/* { dg-do compile } */ -/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ - -int *xyzzy; - -void f1(void) -{ - #pragma omp atomic - xyzzy++; -} - -/* { dg-final { scan-tree-dump-times "xyzzy, 4" 1 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } */ -/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/g++.dg/gomp/atomic-7.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-7.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-7.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,23 +0,0 @@ -/* { dg-do compile } */ - -double x, y; - -void f2(void) -{ - #pragma omp atomic - y++; - #pragma omp atomic - y--; - #pragma omp atomic - ++y; - #pragma omp atomic - --y; - #pragma omp atomic - y += 1; - #pragma omp atomic - y -= x; - #pragma omp atomic - y *= 3; - #pragma omp atomic - y /= 3; -} Index: gcc/testsuite/g++.dg/gomp/atomic-10.C =================================================================== --- gcc/testsuite/g++.dg/gomp/atomic-10.C (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/atomic-10.C (.../branches/cxx-mem-model) (revision 180811) @@ -1,24 +0,0 @@ -// PR middle-end/28046 -// { dg-do compile } -// { dg-options "-fopenmp -fdump-tree-ompexp" } - -int a[3], b; -struct C { int x; int y; } c; - -int bar (void), *baz (void); - -void -foo (void) -{ -#pragma omp atomic - a[2] += bar (); -#pragma omp atomic - b += bar (); -#pragma omp atomic - c.y += bar (); -#pragma omp atomic - *baz () += bar (); -} - -// { dg-final { scan-tree-dump-times "__sync_fetch_and_add" 4 "ompexp" { target i?86-*-* x86_64-*-* ia64-*-* powerpc*-*-* alpha*-*-* } } } -// { dg-final { cleanup-tree-dump "ompexp" } } Index: gcc/testsuite/g++.dg/gomp/gomp.exp =================================================================== --- gcc/testsuite/g++.dg/gomp/gomp.exp (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/gomp/gomp.exp (.../branches/cxx-mem-model) (revision 180811) @@ -27,7 +27,7 @@ if ![check_effective_target_fopenmp] { dg-init # Main loop. -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" "-fopenmp" +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/gomp/*.c]] "" "-fopenmp" # All done. dg-finish Index: gcc/testsuite/g++.dg/dg.exp =================================================================== --- gcc/testsuite/g++.dg/dg.exp (.../trunk) (revision 180790) +++ gcc/testsuite/g++.dg/dg.exp (.../branches/cxx-mem-model) (revision 180811) @@ -48,6 +48,7 @@ set tests [prune $tests $srcdir/$subdir/ set tests [prune $tests $srcdir/$subdir/torture/*] set tests [prune $tests $srcdir/$subdir/graphite/*] set tests [prune $tests $srcdir/$subdir/guality/*] +set tests [prune $tests $srcdir/$subdir/simulate-thread/*] # Main loop. dg-runtest $tests "" $DEFAULT_CXXFLAGS Index: gcc/testsuite/c-c++-common/gomp/atomic-14.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-14.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-14.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,43 @@ +/* PR middle-end/45423 */ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +#ifdef __cplusplus +bool *baz (); +#else +_Bool *baz (); +#endif +int *bar (); + +int +foo (void) +{ + #pragma omp barrier + #pragma omp atomic + (*bar ())++; + #pragma omp barrier + #pragma omp atomic + ++(*bar ()); + #pragma omp barrier + #pragma omp atomic + (*bar ())--; + #pragma omp barrier + #pragma omp atomic + --(*bar ()); + #pragma omp barrier + #pragma omp atomic + (*baz ())++; + #pragma omp barrier + #pragma omp atomic + ++(*baz ()); +#ifndef __cplusplus + #pragma omp barrier + #pragma omp atomic + (*baz ())--; + #pragma omp barrier + #pragma omp atomic + --(*baz ()); + #pragma omp barrier +#endif + return 0; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-15.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-15.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-15.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +int x = 6; + +int +main () +{ + int v; + #pragma omp atomic + x = x * 7 + 6; /* { dg-error "expected" } */ + #pragma omp atomic + x = x * 7 ^ 6; /* { dg-error "expected" } */ + #pragma omp atomic update + x = x - 8 + 6; /* { dg-error "expected" } */ + #pragma omp atomic + x = x ^ 7 | 2; /* { dg-error "expected" } */ + #pragma omp atomic + x = x / 7 * 2; /* { dg-error "expected" } */ + #pragma omp atomic + x = x / 7 / 2; /* { dg-error "expected" } */ + #pragma omp atomic capture + v = x = x | 6; /* { dg-error "invalid operator" } */ + #pragma omp atomic capture + { v = x; x = x * 7 + 6; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x * 7 ^ 6; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x - 8 + 6; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x ^ 7 | 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x / 7 * 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { v = x; x = x / 7 / 2; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x * 7 + 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x * 7 ^ 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x - 8 + 6; v = x; } /* { dg-error "expected" } */ + #pragma omp atomic capture + { x = x ^ 7 | 2; v = x; } /* { dg-error "expected" } */ + (void) v; + return 0; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-7.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-7.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-7.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +double x, y; + +void f2(void) +{ + #pragma omp atomic + y++; + #pragma omp atomic + y--; + #pragma omp atomic + ++y; + #pragma omp atomic + --y; + #pragma omp atomic + y += 1; + #pragma omp atomic + y -= x; + #pragma omp atomic + y *= 3; + #pragma omp atomic + y /= 3; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-8.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-8.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-8.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +long double z; + +void f3(void) +{ + #pragma omp atomic + z++; + #pragma omp atomic + z--; + #pragma omp atomic + ++z; + #pragma omp atomic + --z; + #pragma omp atomic + z += 1; + #pragma omp atomic + z *= 3; + #pragma omp atomic + z /= 3; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-9.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-9.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-9.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-require-effective-target cas_int } */ + +volatile int *bar(void); + +void f1(void) +{ + #pragma omp atomic + *bar() += 1; +} + +/* { dg-final { scan-tree-dump-times "__atomic_fetch_add" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/c-c++-common/gomp/atomic-1.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-1.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-1.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,99 @@ +/* { dg-do compile } */ + +int x; +volatile int y; +volatile unsigned char z; + +void f1(void) +{ + #pragma omp atomic + x++; + #pragma omp atomic + x--; + #pragma omp atomic + ++x; + #pragma omp atomic + --x; + #pragma omp atomic + x += 1; + #pragma omp atomic + x -= y; + #pragma omp atomic + x |= 1; + #pragma omp atomic + x &= 1; + #pragma omp atomic + x ^= 1; + #pragma omp atomic + x *= 3; + #pragma omp atomic + x /= 3; + #pragma omp atomic + x /= 3; + #pragma omp atomic + x <<= 3; + #pragma omp atomic + x >>= 3; +} + +void f2(void) +{ + #pragma omp atomic + y++; + #pragma omp atomic + y--; + #pragma omp atomic + ++y; + #pragma omp atomic + --y; + #pragma omp atomic + y += 1; + #pragma omp atomic + y -= x; + #pragma omp atomic + y |= 1; + #pragma omp atomic + y &= 1; + #pragma omp atomic + y ^= 1; + #pragma omp atomic + y *= 3; + #pragma omp atomic + y /= 3; + #pragma omp atomic + y /= 3; + #pragma omp atomic + y <<= 3; + #pragma omp atomic + y >>= 3; +} + +void f3(void) +{ + #pragma omp atomic + z++; + #pragma omp atomic + z--; + #pragma omp atomic + ++z; + #pragma omp atomic + --z; + #pragma omp atomic + z += 1; + #pragma omp atomic + z |= 1; + #pragma omp atomic + z &= 1; + #pragma omp atomic + z ^= 1; + #pragma omp atomic + z *= 3; + #pragma omp atomic + z /= 3; + #pragma omp atomic + z /= 3; + #pragma omp atomic + z <<= 3; + #pragma omp atomic + z >>= 3; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-10.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-10.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-10.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,25 @@ +/* PR middle-end/28046 */ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-require-effective-target cas_int } */ + +int a[3], b; +struct C { int x; int y; } c; + +int bar (void), *baz (void); + +void +foo (void) +{ +#pragma omp atomic + a[2] += bar (); +#pragma omp atomic + b += bar (); +#pragma omp atomic + c.y += bar (); +#pragma omp atomic + *baz () += bar (); +} + +/* { dg-final { scan-tree-dump-times "__atomic_fetch_add" 4 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/c-c++-common/gomp/atomic-2.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-2.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-2.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +float x, y; + +void f1(void) +{ + #pragma omp atomic + x++; + #pragma omp atomic + x--; + #pragma omp atomic + ++x; + #pragma omp atomic + --x; + #pragma omp atomic + x += 1; + #pragma omp atomic + x -= y; + #pragma omp atomic + x *= 3; + #pragma omp atomic + x /= 3; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-12.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-12.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-12.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,306 @@ +/* PR middle-end/45423 */ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple -g0" } */ +/* atomicvar should never be referenced in between the barrier and + following #pragma omp atomic_load. */ +/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ + +#ifdef __cplusplus +bool atomicvar, c; +#else +_Bool atomicvar, c; +#endif +int i, atomicvar2, c2; + +int +foo (void) +{ + #pragma omp barrier + #pragma omp atomic + atomicvar |= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar |= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar |= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar |= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar |= c; + #pragma omp barrier + #pragma omp atomic + atomicvar ^= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar ^= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar ^= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar ^= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar ^= c; + #pragma omp barrier + #pragma omp atomic + atomicvar &= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar &= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar &= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar &= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar &= c; + #pragma omp barrier + #pragma omp atomic + atomicvar += -1; + #pragma omp barrier + #pragma omp atomic + atomicvar += 0; + #pragma omp barrier + #pragma omp atomic + atomicvar += 1; + #pragma omp barrier + #pragma omp atomic + atomicvar += 2; + #pragma omp barrier + #pragma omp atomic + atomicvar += c; + #pragma omp barrier + #pragma omp atomic + atomicvar -= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar -= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar -= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar -= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar -= c; + #pragma omp barrier + #pragma omp atomic + atomicvar *= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar *= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar *= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar *= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar *= c; + #pragma omp barrier + #pragma omp atomic + atomicvar /= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar /= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar /= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar /= c; + #pragma omp barrier + #pragma omp atomic + atomicvar <<= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar <<= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar <<= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar <<= i; + #pragma omp barrier + #pragma omp atomic + atomicvar >>= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar >>= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar >>= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar >>= i; + #pragma omp barrier + #pragma omp atomic + atomicvar++; + #pragma omp barrier + #pragma omp atomic + ++atomicvar; + #pragma omp barrier +#ifndef __cplusplus + #pragma omp atomic + atomicvar--; + #pragma omp barrier + #pragma omp atomic + --atomicvar; + #pragma omp barrier +#endif + return 0; +} + +int +bar (void) +{ + #pragma omp barrier + #pragma omp atomic + atomicvar2 |= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 |= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 |= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 |= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 |= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 ^= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 ^= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 ^= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 ^= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 ^= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 &= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 &= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 &= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 &= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 &= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 += -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 += 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 += 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 += 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 += c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 -= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 -= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 -= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 -= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 -= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 *= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 *= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 *= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 *= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 *= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 /= -1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 /= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 /= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 /= c2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 <<= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 <<= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 <<= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 <<= i; + #pragma omp barrier + #pragma omp atomic + atomicvar2 >>= 0; + #pragma omp barrier + #pragma omp atomic + atomicvar2 >>= 1; + #pragma omp barrier + #pragma omp atomic + atomicvar2 >>= 2; + #pragma omp barrier + #pragma omp atomic + atomicvar2 >>= i; + #pragma omp barrier + #pragma omp atomic + atomicvar2++; + #pragma omp barrier + #pragma omp atomic + ++atomicvar2; + #pragma omp barrier + #pragma omp atomic + atomicvar2--; + #pragma omp barrier + #pragma omp atomic + --atomicvar2; + #pragma omp barrier + return 0; +} Index: gcc/testsuite/c-c++-common/gomp/atomic-3.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-3.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-3.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-ompexp" } */ +/* { dg-require-effective-target cas_int } */ + +int *xyzzy; + +void f1(void) +{ + #pragma omp atomic + xyzzy++; +} + +/* { dg-final { scan-tree-dump-times "xyzzy, 4" 1 "ompexp" } } */ +/* { dg-final { cleanup-tree-dump "ompexp" } } */ Index: gcc/testsuite/c-c++-common/gomp/atomic-13.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-13.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-13.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,9 @@ +/* PR middle-end/45423 */ +/* { dg-do compile } */ +/* { dg-options "-fopenmp -fdump-tree-gimple -g0 -O2" } */ +/* atomicvar should never be referenced in between the barrier and + following #pragma omp atomic_load. */ +/* { dg-final { scan-tree-dump-not "barrier\[^#\]*atomicvar" "gimple" } } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ + +#include "atomic-12.c" Index: gcc/testsuite/c-c++-common/gomp/atomic-4.c =================================================================== --- gcc/testsuite/c-c++-common/gomp/atomic-4.c (.../trunk) (revision 0) +++ gcc/testsuite/c-c++-common/gomp/atomic-4.c (.../branches/cxx-mem-model) (revision 180811) @@ -0,0 +1,24 @@ +/* { dg-do compile } */ + +int a[4]; +int *p; +struct S { int x; int y[4]; } s; +int *bar(void); + +void f1(void) +{ + #pragma omp atomic + a[4] += 1; + #pragma omp atomic + *p += 1; + #pragma omp atomic + s.x += 1; + #pragma omp atomic + s.y[*p] += 1; + #pragma omp atomic + s.y[*p] *= 42; + #pragma omp atomic + *bar() += 1; + #pragma omp atomic + *bar() *= 42; +}