@@ -5009,13 +5009,16 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
{
enum built_in_function oldbase, newbase, tmpbase;
tree decl, itype, call;
- direct_optab optab, oldoptab, newoptab;
+ const struct atomic_op_functions *optab;
tree lhs, rhs;
basic_block store_bb = single_succ (load_bb);
gimple_stmt_iterator gsi;
gimple stmt;
location_t loc;
bool need_old, need_new;
+ enum rtx_code r_code;
+ enum machine_mode imode;
+ bool have_old, have_new, have_noval;
/* We expect to find the following sequences:
@@ -5053,41 +5056,33 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
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;
+ r_code = PLUS;
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;
+ r_code = MINUS;
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;
+ r_code = AND;
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;
+ r_code = IOR;
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;
+ r_code = XOR;
break;
default:
return false;
}
+ optab = get_atomic_op_for_code (r_code);
+
/* 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,31 +5098,33 @@ expand_omp_atomic_fetch_op (basic_block load_bb,
if (decl == NULL_TREE)
return false;
itype = TREE_TYPE (TREE_TYPE (decl));
+ imode = TYPE_MODE (itype);
+
+ have_new =
+ (direct_optab_handler (optab->mem_fetch_after, imode) == CODE_FOR_nothing
+ || direct_optab_handler (optab->fetch_after, imode) == CODE_FOR_nothing);
+ have_old =
+ (direct_optab_handler (optab->mem_fetch_before, imode) == CODE_FOR_nothing
+ || direct_optab_handler (optab->fetch_before, imode) == CODE_FOR_nothing);
+ have_noval =
+ (direct_optab_handler (optab->mem_no_result, imode) == CODE_FOR_nothing
+ || direct_optab_handler (optab->no_result, imode) == CODE_FOR_nothing);
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)
+ if (!have_new && !have_old)
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))
+ can compensate only if the operation is reversible. */
+ if (!have_old && !(have_new && optab->reverse_code != UNKNOWN))
return false;
}
- else if (direct_optab_handler (optab, TYPE_MODE (itype)) == CODE_FOR_nothing)
+ else if (!have_noval && !have_new && !have_old)
return false;
gsi = gsi_last_bb (load_bb);
@@ -7172,70 +7172,48 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model)
/* Structure containing the pointers and values required to process the
various forms of the atomic_fetch_op and atomic_op_fetch builtins. */
-struct 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;
-};
-/* Initialize the fields for each supported opcode. */
-static const struct 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
- };
-
-static const struct op_functions 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
- };
-
-static const struct op_functions xor_op = { atomic_fetch_xor_optab,
- atomic_xor_fetch_optab,
- atomic_xor_optab,
- sync_old_xor_optab,
- sync_new_xor_optab,
- sync_xor_optab,
- UNKNOWN
- };
-
-static const struct op_functions 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
- };
-
-static const struct op_functions 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
- };
-
-static const struct op_functions or_op = { atomic_fetch_or_optab,
- atomic_or_fetch_optab,
- atomic_or_optab,
- sync_old_ior_optab,
- sync_new_ior_optab,
- sync_ior_optab,
- UNKNOWN
- };
+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
+ };
+
+ switch (code)
+ {
+ case PLUS:
+ return &add_op;
+ case MINUS:
+ return &sub_op;
+ case XOR:
+ return &xor_op;
+ case AND:
+ return &and_op;
+ case IOR:
+ return &ior_op;
+ case NOT:
+ return &nand_op;
+ default:
+ gcc_unreachable ();
+ }
+}
/* Try to emit an instruction for a specific operation varaition.
OPTAB contains the OP functions.
@@ -7247,8 +7225,8 @@ static const struct op_functions or_op = { atomic_fetch_or_optab,
AFTER is true if the returned result is the value after the operation. */
static rtx
-maybe_emit_op (const struct op_functions *optab, rtx target, rtx mem, rtx val,
- bool use_memmodel, enum memmodel model, bool after)
+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;
@@ -7317,33 +7295,11 @@ 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 op_functions *optab;
+ const struct atomic_op_functions *optab;
rtx result;
bool unused_result = (target == const0_rtx);
- switch (code)
- {
- case PLUS:
- optab = &add_op;
- break;
- case MINUS:
- optab = &sub_op;
- break;
- case AND:
- optab = &and_op;
- break;
- case XOR:
- optab = &xor_op;
- break;
- case IOR:
- optab = &or_op;
- break;
- case NOT:
- optab = &nand_op;
- break;
- default:
- gcc_unreachable();
- }
+ optab = get_atomic_op_for_code (code);
/* Check for the case where the result isn't used and try those patterns. */
if (unused_result)
@@ -955,6 +955,19 @@ 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);
+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;
+};
+
+extern const struct atomic_op_functions *get_atomic_op_for_code (enum rtx_code);
+
/* Generate code for a compare and swap. */
extern bool expand_atomic_compare_and_swap (rtx *, rtx *, rtx, rtx, rtx, bool,
enum memmodel, enum memmodel);