Commit cedb4a1a by Richard Henderson Committed by Richard Henderson

Allow libcalls to be installed for legacy __sync optabs.

This allows a target which implements the __sync interfaces
in libgcc to continue to use them transparently with the
new __atomic builtins.

It is assumed that these libgcc routines DO NOT use spinlocks.
This is true of all extant libgcc instances.

        * optabs.h (OTI_sync_compare_and_swap, OTI_sync_lock_test_and_set,
        OTI_sync_old_add, OTI_sync_old_sub, OTI_sync_old_ior,
        OTI_sync_old_and, OTI_sync_old_xor, OTI_sync_old_nand,
        OTI_sync_new_add, OTI_sync_new_sub, OTI_sync_new_ior,
        OTI_sync_new_and, OTI_sync_new_xor, OTI_sync_new_nand): Move and
        rename from the direct_optab_index enum.
        (sync_compare_and_swap_optab, sync_lock_test_and_set_optab,
        sync_old_add_optab, sync_old_sub_optab, sync_old_ior_optab,
        sync_old_and_optab, sync_old_xor_optab, sync_old_nand_optab,
        sync_new_add_optab, sync_new_sub_optab, sync_new_ior_optab,
        sync_new_and_optab, sync_new_xor_optab, sync_new_nand_optab): Read
        from the optab_table, not the direct_optab_table.
        (init_sync_libfuncs): Declare.
        (can_compare_and_swap_p): Update parameters.
        * optabs.c (init_sync_libfuncs_1, init_sync_libfuncs): New.
        (can_compare_and_swap_p): Add allow_libcall parameter; if true,
        test for the legacy compare-and-swap libcall.
        (expand_atomic_exchange): Use the legacy test-and-set libcall.
        (expand_atomic_compare_and_swap): Use the legacy CAS libcall.
        (struct atomic_op_functions): Update for optab type changes.
        (maybe_emit_op): Likewise.
        (expand_atomic_fetch_op): Use the legacy fetch-op libcalls.
        * builtins.c (fold_builtin_atomic_always_lock_free): Update call
        to can_compare_and_swap_p.
        * omp-low.c (expand_omp_atomic_fetch_op): Likewise.
        (expand_omp_atomic_pipeline): Likewise.
        * genopinit.c (optabs): Make sync_old_*_optab, sync_new_*_optab,
        sync_compare_and_swap_optab, sync_lock_test_and_set_optab regular
        optabs.

From-SVN: r181134
parent 13fc31c2
2011-11-07 Richard Henderson <rth@redhat.com>
* optabs.h (OTI_sync_compare_and_swap, OTI_sync_lock_test_and_set,
OTI_sync_old_add, OTI_sync_old_sub, OTI_sync_old_ior,
OTI_sync_old_and, OTI_sync_old_xor, OTI_sync_old_nand,
OTI_sync_new_add, OTI_sync_new_sub, OTI_sync_new_ior,
OTI_sync_new_and, OTI_sync_new_xor, OTI_sync_new_nand): Move and
rename from the direct_optab_index enum.
(sync_compare_and_swap_optab, sync_lock_test_and_set_optab,
sync_old_add_optab, sync_old_sub_optab, sync_old_ior_optab,
sync_old_and_optab, sync_old_xor_optab, sync_old_nand_optab,
sync_new_add_optab, sync_new_sub_optab, sync_new_ior_optab,
sync_new_and_optab, sync_new_xor_optab, sync_new_nand_optab): Read
from the optab_table, not the direct_optab_table.
(init_sync_libfuncs): Declare.
(can_compare_and_swap_p): Update parameters.
* optabs.c (init_sync_libfuncs_1, init_sync_libfuncs): New.
(can_compare_and_swap_p): Add allow_libcall parameter; if true,
test for the legacy compare-and-swap libcall.
(expand_atomic_exchange): Use the legacy test-and-set libcall.
(expand_atomic_compare_and_swap): Use the legacy CAS libcall.
(struct atomic_op_functions): Update for optab type changes.
(maybe_emit_op): Likewise.
(expand_atomic_fetch_op): Use the legacy fetch-op libcalls.
* builtins.c (fold_builtin_atomic_always_lock_free): Update call
to can_compare_and_swap_p.
* omp-low.c (expand_omp_atomic_fetch_op): Likewise.
(expand_omp_atomic_pipeline): Likewise.
* genopinit.c (optabs): Make sync_old_*_optab, sync_new_*_optab,
sync_compare_and_swap_optab, sync_lock_test_and_set_optab regular
optabs.
* doc/md.texi (sync_compare_and_swap): Update docs for libcalls.
2011-11-07 Jakub Jelinek <jakub@redhat.com>
* config/i386/i386-bultin-types.def (V8SI_FTYPE_V4DF_V4DF): Add.
......@@ -5512,7 +5512,7 @@ fold_builtin_atomic_always_lock_free (tree arg0, tree arg1)
/* 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))
if (can_compare_and_swap_p (mode, true))
return integer_one_node;
else
return integer_zero_node;
......
......@@ -5595,6 +5595,17 @@ be able to take the destination of the @code{MODE_CC} set and pass it
to the @code{cbranchcc4} or @code{cstorecc4} pattern as the first
operand of the comparison (the second will be @code{(const_int 0)}).
For targets where the operating system may provide support for this
operation via library calls, the @code{sync_compare_and_swap_optab}
may be initialized to a function with the same interface as the
@code{__sync_val_compare_and_swap_@var{n}} built-in. If the entire
set of @var{__sync} builtins are supported via library calls, the
target can initialize all of the optabs at once with
@code{init_sync_libfuncs}.
For the purposes of C++11 @code{std::atomic::is_lock_free}, it is
assumed that these library calls do @emph{not} use any kind of
interruptable locking.
@cindex @code{sync_add@var{mode}} instruction pattern
@cindex @code{sync_sub@var{mode}} instruction pattern
@cindex @code{sync_ior@var{mode}} instruction pattern
......
......@@ -228,20 +228,20 @@ static const char * const optabs[] =
"set_direct_optab_handler (sync_and_optab, $A, CODE_FOR_$(sync_and$I$a$))",
"set_direct_optab_handler (sync_xor_optab, $A, CODE_FOR_$(sync_xor$I$a$))",
"set_direct_optab_handler (sync_nand_optab, $A, CODE_FOR_$(sync_nand$I$a$))",
"set_direct_optab_handler (sync_old_add_optab, $A, CODE_FOR_$(sync_old_add$I$a$))",
"set_direct_optab_handler (sync_old_sub_optab, $A, CODE_FOR_$(sync_old_sub$I$a$))",
"set_direct_optab_handler (sync_old_ior_optab, $A, CODE_FOR_$(sync_old_ior$I$a$))",
"set_direct_optab_handler (sync_old_and_optab, $A, CODE_FOR_$(sync_old_and$I$a$))",
"set_direct_optab_handler (sync_old_xor_optab, $A, CODE_FOR_$(sync_old_xor$I$a$))",
"set_direct_optab_handler (sync_old_nand_optab, $A, CODE_FOR_$(sync_old_nand$I$a$))",
"set_direct_optab_handler (sync_new_add_optab, $A, CODE_FOR_$(sync_new_add$I$a$))",
"set_direct_optab_handler (sync_new_sub_optab, $A, CODE_FOR_$(sync_new_sub$I$a$))",
"set_direct_optab_handler (sync_new_ior_optab, $A, CODE_FOR_$(sync_new_ior$I$a$))",
"set_direct_optab_handler (sync_new_and_optab, $A, CODE_FOR_$(sync_new_and$I$a$))",
"set_direct_optab_handler (sync_new_xor_optab, $A, CODE_FOR_$(sync_new_xor$I$a$))",
"set_direct_optab_handler (sync_new_nand_optab, $A, CODE_FOR_$(sync_new_nand$I$a$))",
"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_optab_handler (sync_old_add_optab, $A, CODE_FOR_$(sync_old_add$I$a$))",
"set_optab_handler (sync_old_sub_optab, $A, CODE_FOR_$(sync_old_sub$I$a$))",
"set_optab_handler (sync_old_ior_optab, $A, CODE_FOR_$(sync_old_ior$I$a$))",
"set_optab_handler (sync_old_and_optab, $A, CODE_FOR_$(sync_old_and$I$a$))",
"set_optab_handler (sync_old_xor_optab, $A, CODE_FOR_$(sync_old_xor$I$a$))",
"set_optab_handler (sync_old_nand_optab, $A, CODE_FOR_$(sync_old_nand$I$a$))",
"set_optab_handler (sync_new_add_optab, $A, CODE_FOR_$(sync_new_add$I$a$))",
"set_optab_handler (sync_new_sub_optab, $A, CODE_FOR_$(sync_new_sub$I$a$))",
"set_optab_handler (sync_new_ior_optab, $A, CODE_FOR_$(sync_new_ior$I$a$))",
"set_optab_handler (sync_new_and_optab, $A, CODE_FOR_$(sync_new_and$I$a$))",
"set_optab_handler (sync_new_xor_optab, $A, CODE_FOR_$(sync_new_xor$I$a$))",
"set_optab_handler (sync_new_nand_optab, $A, CODE_FOR_$(sync_new_nand$I$a$))",
"set_optab_handler (sync_compare_and_swap_optab, $A, CODE_FOR_$(sync_compare_and_swap$I$a$))",
"set_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$))",
......
2011-11-07 Richard Henderson <rth@redhat.com>
* builtins.c (compareAndSwapInt_builtin): Use can_compare_and_swap_p.
(compareAndSwapLong_builtin): Likewise.
(compareAndSwapObject_builtin): Likewise.
(VMSupportsCS8_builtin): Likewise.
2011-11-02 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* Make-lang.in (jvspec.o): Pass SHLIB instead of SHLIB_LINK.
......
......@@ -319,9 +319,7 @@ compareAndSwapInt_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call)
{
enum machine_mode mode = TYPE_MODE (int_type_node);
if (direct_optab_handler (sync_compare_and_swap_optab, mode)
!= CODE_FOR_nothing
|| flag_use_atomic_builtins)
if (can_compare_and_swap_p (mode, flag_use_atomic_builtins))
{
tree addr, stmt;
enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_4;
......@@ -342,13 +340,12 @@ compareAndSwapLong_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call)
{
enum machine_mode mode = TYPE_MODE (long_type_node);
if (direct_optab_handler (sync_compare_and_swap_optab, mode)
!= CODE_FOR_nothing
|| (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (word_mode)
&& flag_use_atomic_builtins))
/* We don't trust flag_use_atomic_builtins for multi-word
compareAndSwap. Some machines such as ARM have atomic libfuncs
but not the multi-word versions. */
/* We don't trust flag_use_atomic_builtins for multi-word compareAndSwap.
Some machines such as ARM have atomic libfuncs but not the multi-word
versions. */
if (can_compare_and_swap_p (mode,
(flag_use_atomic_builtins
&& GET_MODE_SIZE (mode) <= UNITS_PER_WORD)))
{
tree addr, stmt;
enum built_in_function fncode = BUILT_IN_SYNC_BOOL_COMPARE_AND_SWAP_8;
......@@ -368,9 +365,7 @@ compareAndSwapObject_builtin (tree method_return_type ATTRIBUTE_UNUSED,
tree orig_call)
{
enum machine_mode mode = TYPE_MODE (ptr_type_node);
if (direct_optab_handler (sync_compare_and_swap_optab, mode)
!= CODE_FOR_nothing
|| flag_use_atomic_builtins)
if (can_compare_and_swap_p (mode, flag_use_atomic_builtins))
{
tree addr, stmt;
enum built_in_function builtin;
......@@ -448,8 +443,7 @@ VMSupportsCS8_builtin (tree method_return_type,
{
enum machine_mode mode = TYPE_MODE (long_type_node);
gcc_assert (method_return_type == boolean_type_node);
if (direct_optab_handler (sync_compare_and_swap_optab, mode)
!= CODE_FOR_nothing)
if (can_compare_and_swap_p (mode, false))
return boolean_true_node;
else
return boolean_false_node;
......
......@@ -5097,7 +5097,7 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
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))
if (!can_compare_and_swap_p (imode, true))
return false;
gsi = gsi_last_bb (load_bb);
......@@ -5168,7 +5168,7 @@ expand_omp_atomic_pipeline (basic_block load_bb, basic_block store_bb,
type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
itype = TREE_TYPE (TREE_TYPE (cmpxchg));
if (!can_compare_and_swap_p (TYPE_MODE (itype)))
if (!can_compare_and_swap_p (TYPE_MODE (itype), true))
return false;
/* Load the initial value, replacing the GIMPLE_OMP_ATOMIC_LOAD. */
......
......@@ -386,6 +386,30 @@ enum optab_index
/* Perform a raise to the power of integer. */
OTI_powi,
/* Atomic compare and swap. */
OTI_sync_compare_and_swap,
/* Atomic exchange with acquire semantics. */
OTI_sync_lock_test_and_set,
/* This second set is atomic operations in which we return the value
that existed in memory before the operation. */
OTI_sync_old_add,
OTI_sync_old_sub,
OTI_sync_old_ior,
OTI_sync_old_and,
OTI_sync_old_xor,
OTI_sync_old_nand,
/* This third set is atomic operations in which we return the value
that resulted after performing the operation. */
OTI_sync_new_add,
OTI_sync_new_sub,
OTI_sync_new_ior,
OTI_sync_new_and,
OTI_sync_new_xor,
OTI_sync_new_nand,
OTI_MAX
};
......@@ -570,6 +594,23 @@ enum optab_index
#define powi_optab (&optab_table[OTI_powi])
#define sync_compare_and_swap_optab \
(&optab_table[(int) OTI_sync_compare_and_swap])
#define sync_lock_test_and_set_optab \
(&optab_table[(int) OTI_sync_lock_test_and_set])
#define sync_old_add_optab (&optab_table[(int) OTI_sync_old_add])
#define sync_old_sub_optab (&optab_table[(int) OTI_sync_old_sub])
#define sync_old_ior_optab (&optab_table[(int) OTI_sync_old_ior])
#define sync_old_and_optab (&optab_table[(int) OTI_sync_old_and])
#define sync_old_xor_optab (&optab_table[(int) OTI_sync_old_xor])
#define sync_old_nand_optab (&optab_table[(int) OTI_sync_old_nand])
#define sync_new_add_optab (&optab_table[(int) OTI_sync_new_add])
#define sync_new_sub_optab (&optab_table[(int) OTI_sync_new_sub])
#define sync_new_ior_optab (&optab_table[(int) OTI_sync_new_ior])
#define sync_new_and_optab (&optab_table[(int) OTI_sync_new_and])
#define sync_new_xor_optab (&optab_table[(int) OTI_sync_new_xor])
#define sync_new_nand_optab (&optab_table[(int) OTI_sync_new_nand])
/* Conversion optabs have their own table and indexes. */
enum convert_optab_index
{
......@@ -659,8 +700,10 @@ enum direct_optab_index
DOI_cmpstrn,
DOI_cmpmem,
/* Synchronization primitives. This first set is atomic operation for
which we don't care about the resulting value. */
/* Atomic clear with release semantics. */
DOI_sync_lock_release,
/* Atomic operation with no resulting value. */
DOI_sync_add,
DOI_sync_sub,
DOI_sync_ior,
......@@ -668,33 +711,6 @@ enum direct_optab_index
DOI_sync_xor,
DOI_sync_nand,
/* This second set is atomic operations in which we return the value
that existed in memory before the operation. */
DOI_sync_old_add,
DOI_sync_old_sub,
DOI_sync_old_ior,
DOI_sync_old_and,
DOI_sync_old_xor,
DOI_sync_old_nand,
/* This third set is atomic operations in which we return the value
that resulted after performing the operation. */
DOI_sync_new_add,
DOI_sync_new_sub,
DOI_sync_new_ior,
DOI_sync_new_and,
DOI_sync_new_xor,
DOI_sync_new_nand,
/* Atomic compare and swap. */
DOI_sync_compare_and_swap,
/* Atomic exchange with acquire semantics. */
DOI_sync_lock_test_and_set,
/* Atomic clear with release semantics. */
DOI_sync_lock_release,
/* Atomic operations with memory model parameters. */
DOI_atomic_exchange,
DOI_atomic_compare_and_swap,
......@@ -748,30 +764,14 @@ typedef struct direct_optab_d *direct_optab;
#define cmpstr_optab (&direct_optab_table[(int) DOI_cmpstr])
#define cmpstrn_optab (&direct_optab_table[(int) DOI_cmpstrn])
#define cmpmem_optab (&direct_optab_table[(int) DOI_cmpmem])
#define sync_lock_release_optab \
(&direct_optab_table[(int) DOI_sync_lock_release])
#define sync_add_optab (&direct_optab_table[(int) DOI_sync_add])
#define sync_sub_optab (&direct_optab_table[(int) DOI_sync_sub])
#define sync_ior_optab (&direct_optab_table[(int) DOI_sync_ior])
#define sync_and_optab (&direct_optab_table[(int) DOI_sync_and])
#define sync_xor_optab (&direct_optab_table[(int) DOI_sync_xor])
#define sync_nand_optab (&direct_optab_table[(int) DOI_sync_nand])
#define sync_old_add_optab (&direct_optab_table[(int) DOI_sync_old_add])
#define sync_old_sub_optab (&direct_optab_table[(int) DOI_sync_old_sub])
#define sync_old_ior_optab (&direct_optab_table[(int) DOI_sync_old_ior])
#define sync_old_and_optab (&direct_optab_table[(int) DOI_sync_old_and])
#define sync_old_xor_optab (&direct_optab_table[(int) DOI_sync_old_xor])
#define sync_old_nand_optab (&direct_optab_table[(int) DOI_sync_old_nand])
#define sync_new_add_optab (&direct_optab_table[(int) DOI_sync_new_add])
#define sync_new_sub_optab (&direct_optab_table[(int) DOI_sync_new_sub])
#define sync_new_ior_optab (&direct_optab_table[(int) DOI_sync_new_ior])
#define sync_new_and_optab (&direct_optab_table[(int) DOI_sync_new_and])
#define sync_new_xor_optab (&direct_optab_table[(int) DOI_sync_new_xor])
#define sync_new_nand_optab (&direct_optab_table[(int) DOI_sync_new_nand])
#define sync_compare_and_swap_optab \
(&direct_optab_table[(int) DOI_sync_compare_and_swap])
#define sync_lock_test_and_set_optab \
(&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])
......@@ -956,6 +956,9 @@ extern void set_optab_libfunc (optab, enum machine_mode, const char *);
extern void set_conv_libfunc (convert_optab, enum machine_mode,
enum machine_mode, const char *);
/* Call this to install all of the __sync libcalls up to size MAX. */
extern void init_sync_libfuncs (int max);
/* Generate code for a FIXED_CONVERT_EXPR. */
extern void expand_fixed_convert (rtx, rtx, int, int);
......@@ -966,7 +969,7 @@ extern void expand_float (rtx, rtx, int);
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);
extern bool can_compare_and_swap_p (enum machine_mode, bool);
/* Generate code for a compare and swap. */
extern bool expand_atomic_compare_and_swap (rtx *, rtx *, rtx, rtx, rtx, bool,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment