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);
