-/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as:
-
- oldval = *addr;
- repeat:
- newval = rhs; // with oldval replacing *addr in rhs
- oldval = __sync_val_compare_and_swap (addr, oldval, newval);
- if (oldval != newval)
- goto repeat;
-
- INDEX is log2 of the size of the data type, and thus usable to find the
- index of the builtin decl. */
-
-static enum gimplify_status
-gimplify_omp_atomic_pipeline (tree *expr_p, tree *pre_p, tree addr,
- tree rhs, int index)
-{
- tree oldval, oldival, oldival2, newval, newival, label;
- tree type, itype, cmpxchg, args, x, iaddr;
-
- cmpxchg = built_in_decls[BUILT_IN_VAL_COMPARE_AND_SWAP_N + index + 1];
- type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
- itype = TREE_TYPE (TREE_TYPE (cmpxchg));
-
- if (sync_compare_and_swap[TYPE_MODE (itype)] == CODE_FOR_nothing)
- return GS_UNHANDLED;
-
- oldval = create_tmp_var (type, NULL);
- newval = create_tmp_var (type, NULL);
-
- /* Precompute as much of RHS as possible. In the same walk, replace
- occurrences of the lhs value with our temporary. */
- if (goa_stabilize_expr (&rhs, pre_p, addr, oldval) < 0)
- return GS_ERROR;
-
- x = build_fold_indirect_ref (addr);
- x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
- gimplify_and_add (x, pre_p);
-
- /* For floating-point values, we'll need to view-convert them to integers
- so that we can perform the atomic compare and swap. Simplify the
- following code by always setting up the "i"ntegral variables. */
- if (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type))
- {
- oldival = oldval;
- newival = newval;
- iaddr = addr;
- }
- else
- {
- oldival = create_tmp_var (itype, NULL);
- newival = create_tmp_var (itype, NULL);
-
- x = build1 (VIEW_CONVERT_EXPR, itype, oldval);
- x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
- gimplify_and_add (x, pre_p);
- iaddr = fold_convert (build_pointer_type (itype), addr);
- }
-
- oldival2 = create_tmp_var (itype, NULL);
-
- label = create_artificial_label ();
- x = build1 (LABEL_EXPR, void_type_node, label);
- gimplify_and_add (x, pre_p);
-
- x = build2 (MODIFY_EXPR, void_type_node, newval, rhs);
- gimplify_and_add (x, pre_p);
-
- if (newval != newival)
- {
- x = build1 (VIEW_CONVERT_EXPR, itype, newval);
- x = build2 (MODIFY_EXPR, void_type_node, newival, x);
- gimplify_and_add (x, pre_p);
- }
-
- x = build2 (MODIFY_EXPR, void_type_node, oldival2,
- fold_convert (itype, oldival));
- gimplify_and_add (x, pre_p);
-
- args = tree_cons (NULL, fold_convert (itype, newival), NULL);
- args = tree_cons (NULL, fold_convert (itype, oldival), args);
- args = tree_cons (NULL, iaddr, args);
- x = build_function_call_expr (cmpxchg, args);
- if (oldval == oldival)
- x = fold_convert (type, x);
- x = build2 (MODIFY_EXPR, void_type_node, oldival, x);
- gimplify_and_add (x, pre_p);
-
- /* For floating point, be prepared for the loop backedge. */
- if (oldval != oldival)
- {
- x = build1 (VIEW_CONVERT_EXPR, type, oldival);
- x = build2 (MODIFY_EXPR, void_type_node, oldval, x);
- gimplify_and_add (x, pre_p);
- }
-
- /* Note that we always perform the comparison as an integer, even for
- floating point. This allows the atomic operation to properly
- succeed even with NaNs and -0.0. */
- x = build3 (COND_EXPR, void_type_node,
- build2 (NE_EXPR, boolean_type_node, oldival, oldival2),
- build1 (GOTO_EXPR, void_type_node, label), NULL);
- gimplify_and_add (x, pre_p);
-
- *expr_p = NULL;
- return GS_ALL_DONE;
-}
-
-/* A subroutine of gimplify_omp_atomic. Implement the atomic operation as:
-
- GOMP_atomic_start ();
- *addr = rhs;
- GOMP_atomic_end ();
-
- The result is not globally atomic, but works so long as all parallel
- references are within #pragma omp atomic directives. According to
- responses received from omp@openmp.org, appears to be within spec.
- Which makes sense, since that's how several other compilers handle
- this situation as well. */
-
-static enum gimplify_status
-gimplify_omp_atomic_mutex (tree *expr_p, tree *pre_p, tree addr, tree rhs)
-{
- tree t;
-
- t = built_in_decls[BUILT_IN_GOMP_ATOMIC_START];
- t = build_function_call_expr (t, NULL);
- gimplify_and_add (t, pre_p);
-
- t = build_fold_indirect_ref (addr);
- t = build2 (MODIFY_EXPR, void_type_node, t, rhs);
- gimplify_and_add (t, pre_p);
-
- t = built_in_decls[BUILT_IN_GOMP_ATOMIC_END];
- t = build_function_call_expr (t, NULL);
- gimplify_and_add (t, pre_p);
-
- *expr_p = NULL;
- return GS_ALL_DONE;
-}
-