Cc: ja...@redhat.com
---
 gcc/omp-low.c |   55 +++++++++++------------
 gcc/optabs.c  |  134 +++++++++++++++++++--------------------------------------
 gcc/optabs.h  |   13 ++++++
 3 files changed, 84 insertions(+), 118 deletions(-)

diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 5faa084..972cb6d 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -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);
diff --git a/gcc/optabs.c b/gcc/optabs.c
index b7c00be..f594226 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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)
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 2ca0fcd..4487f52 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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);
-- 
1.7.6.4

Reply via email to