aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-intrinsic.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-intrinsic.c')
-rw-r--r--gcc/fortran/trans-intrinsic.c219
1 files changed, 206 insertions, 13 deletions
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 5aa5683..a285e9d 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -8339,25 +8339,104 @@ conv_co_minmaxsum (gfc_code *code)
static tree
-conv_intrinsic_atomic_def (gfc_code *code)
+conv_intrinsic_atomic_op (gfc_code *code)
{
- gfc_se atom, value;
- stmtblock_t block;
+ gfc_se atom, value, old;
+ tree tmp;
+ stmtblock_t block, post_block;
gfc_expr *atom_expr = code->ext.actual->expr;
+ gfc_expr *stat;
+ built_in_function fn;
if (atom_expr->expr_type == EXPR_FUNCTION
&& atom_expr->value.function.isym
&& atom_expr->value.function.isym->id == GFC_ISYM_CAF_GET)
atom_expr = atom_expr->value.function.actual->expr;
+ gfc_start_block (&block);
+ gfc_init_block (&post_block);
gfc_init_se (&atom, NULL);
gfc_init_se (&value, NULL);
+ atom.want_pointer = 1;
gfc_conv_expr (&atom, atom_expr);
+ gfc_add_block_to_block (&block, &atom.pre);
+ gfc_add_block_to_block (&post_block, &atom.post);
gfc_conv_expr (&value, code->ext.actual->next->expr);
+ gfc_add_block_to_block (&block, &value.pre);
+ gfc_add_block_to_block (&post_block, &value.post);
- gfc_init_block (&block);
- gfc_add_modify (&block, atom.expr,
- fold_convert (TREE_TYPE (atom.expr), value.expr));
+ switch (code->resolved_isym->id)
+ {
+ case GFC_ISYM_ATOMIC_ADD:
+ case GFC_ISYM_ATOMIC_FETCH_ADD:
+ fn = BUILT_IN_ATOMIC_FETCH_ADD_N;
+ break;
+ case GFC_ISYM_ATOMIC_AND:
+ case GFC_ISYM_ATOMIC_FETCH_AND:
+ fn = BUILT_IN_ATOMIC_FETCH_AND_N;
+ break;
+ case GFC_ISYM_ATOMIC_DEF:
+ fn = BUILT_IN_ATOMIC_STORE_N;
+ break;
+ case GFC_ISYM_ATOMIC_OR:
+ case GFC_ISYM_ATOMIC_FETCH_OR:
+ fn = BUILT_IN_ATOMIC_FETCH_OR_N;
+ break;
+ case GFC_ISYM_ATOMIC_XOR:
+ case GFC_ISYM_ATOMIC_FETCH_XOR:
+ fn = BUILT_IN_ATOMIC_FETCH_XOR_N;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ tmp = TREE_TYPE (TREE_TYPE (atom.expr));
+ fn = (built_in_function) ((int) fn
+ + exact_log2 (tree_to_uhwi (TYPE_SIZE_UNIT (tmp)))
+ + 1);
+ tmp = builtin_decl_explicit (fn);
+ tree itype = TREE_TYPE (TREE_TYPE (atom.expr));
+ tmp = builtin_decl_explicit (fn);
+
+ switch (code->resolved_isym->id)
+ {
+ case GFC_ISYM_ATOMIC_ADD:
+ case GFC_ISYM_ATOMIC_AND:
+ case GFC_ISYM_ATOMIC_DEF:
+ case GFC_ISYM_ATOMIC_OR:
+ case GFC_ISYM_ATOMIC_XOR:
+ stat = code->ext.actual->next->next->expr;
+ tmp = build_call_expr_loc (input_location, tmp, 3, atom.expr,
+ fold_convert (itype, value.expr),
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+ gfc_add_expr_to_block (&block, tmp);
+ break;
+ default:
+ stat = code->ext.actual->next->next->next->expr;
+ gfc_init_se (&old, NULL);
+ gfc_conv_expr (&old, code->ext.actual->next->next->expr);
+ gfc_add_block_to_block (&block, &old.pre);
+ gfc_add_block_to_block (&post_block, &old.post);
+ tmp = build_call_expr_loc (input_location, tmp, 3, atom.expr,
+ fold_convert (itype, value.expr),
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+ gfc_add_modify (&block, old.expr,
+ fold_convert (TREE_TYPE (old.expr), tmp));
+ break;
+ }
+
+ /* STAT= */
+ if (stat != NULL)
+ {
+ gcc_assert (stat->expr_type == EXPR_VARIABLE);
+ gfc_init_se (&value, NULL);
+ gfc_conv_expr_val (&value, stat);
+ gfc_add_block_to_block (&block, &value.pre);
+ gfc_add_block_to_block (&post_block, &value.post);
+ gfc_add_modify (&block, value.expr,
+ build_int_cst (TREE_TYPE (value.expr), 0));
+ }
+ gfc_add_block_to_block (&block, &post_block);
return gfc_finish_block (&block);
}
@@ -8366,22 +8445,124 @@ static tree
conv_intrinsic_atomic_ref (gfc_code *code)
{
gfc_se atom, value;
- stmtblock_t block;
- gfc_expr *atom_expr = code->ext.actual->expr;
+ tree tmp;
+ stmtblock_t block, post_block;
+ built_in_function fn;
+ gfc_expr *atom_expr = code->ext.actual->next->expr;
if (atom_expr->expr_type == EXPR_FUNCTION
&& atom_expr->value.function.isym
&& atom_expr->value.function.isym->id == GFC_ISYM_CAF_GET)
atom_expr = atom_expr->value.function.actual->expr;
+ gfc_start_block (&block);
+ gfc_init_block (&post_block);
gfc_init_se (&atom, NULL);
gfc_init_se (&value, NULL);
- gfc_conv_expr (&value, atom_expr);
- gfc_conv_expr (&atom, code->ext.actual->next->expr);
+ atom.want_pointer = 1;
+ gfc_conv_expr (&value, code->ext.actual->expr);
+ gfc_add_block_to_block (&block, &value.pre);
+ gfc_add_block_to_block (&post_block, &value.post);
+ gfc_conv_expr (&atom, atom_expr);
+ gfc_add_block_to_block (&block, &atom.pre);
+ gfc_add_block_to_block (&post_block, &atom.post);
+
+ tmp = TREE_TYPE (TREE_TYPE (atom.expr));
+ fn = (built_in_function) ((int) BUILT_IN_ATOMIC_LOAD_N
+ + exact_log2 (tree_to_uhwi (TYPE_SIZE_UNIT (tmp)))
+ + 1);
+ tmp = builtin_decl_explicit (fn);
+ tmp = build_call_expr_loc (input_location, tmp, 2, atom.expr,
+ build_int_cst (integer_type_node,
+ MEMMODEL_RELAXED));
+ gfc_add_modify (&block, value.expr,
+ fold_convert (TREE_TYPE (value.expr), tmp));
+
+ /* STAT= */
+ if (code->ext.actual->next->next->expr != NULL)
+ {
+ gcc_assert (code->ext.actual->next->next->expr->expr_type
+ == EXPR_VARIABLE);
+ gfc_init_se (&value, NULL);
+ gfc_conv_expr_val (&value, code->ext.actual->next->next->expr);
+ gfc_add_block_to_block (&block, &value.pre);
+ gfc_add_block_to_block (&post_block, &value.post);
+ gfc_add_modify (&block, value.expr,
+ build_int_cst (TREE_TYPE (value.expr), 0));
+ }
+ gfc_add_block_to_block (&block, &post_block);
+ return gfc_finish_block (&block);
+}
+
+
+static tree
+conv_intrinsic_atomic_cas (gfc_code *code)
+{
+ gfc_se argse;
+ tree tmp, atom, old, new_val, comp;
+ stmtblock_t block, post_block;
+ built_in_function fn;
+ gfc_expr *atom_expr = code->ext.actual->expr;
+
+ if (atom_expr->expr_type == EXPR_FUNCTION
+ && atom_expr->value.function.isym
+ && atom_expr->value.function.isym->id == GFC_ISYM_CAF_GET)
+ atom_expr = atom_expr->value.function.actual->expr;
gfc_init_block (&block);
- gfc_add_modify (&block, value.expr,
- fold_convert (TREE_TYPE (value.expr), atom.expr));
+ gfc_init_block (&post_block);
+ gfc_init_se (&argse, NULL);
+ argse.want_pointer = 1;
+ gfc_conv_expr (&argse, atom_expr);
+ atom = argse.expr;
+
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, code->ext.actual->next->expr);
+ gfc_add_block_to_block (&block, &argse.pre);
+ gfc_add_block_to_block (&post_block, &argse.post);
+ old = argse.expr;
+
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, code->ext.actual->next->next->expr);
+ gfc_add_block_to_block (&block, &argse.pre);
+ gfc_add_block_to_block (&post_block, &argse.post);
+ comp = argse.expr;
+
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, code->ext.actual->next->next->next->expr);
+ gfc_add_block_to_block (&block, &argse.pre);
+ gfc_add_block_to_block (&post_block, &argse.post);
+ new_val = argse.expr;
+
+ tmp = TREE_TYPE (TREE_TYPE (atom));
+ fn = (built_in_function) ((int) BUILT_IN_ATOMIC_COMPARE_EXCHANGE_N
+ + exact_log2 (tree_to_uhwi (TYPE_SIZE_UNIT (tmp)))
+ + 1);
+ tmp = builtin_decl_explicit (fn);
+
+ gfc_add_modify (&block, old, comp);
+ tmp = build_call_expr_loc (input_location, tmp, 6, atom,
+ gfc_build_addr_expr (NULL, old),
+ fold_convert (TREE_TYPE (old), new_val),
+ boolean_false_node,
+ build_int_cst (NULL, MEMMODEL_RELAXED),
+ build_int_cst (NULL, MEMMODEL_RELAXED));
+ gfc_add_expr_to_block (&block, tmp);
+
+ /* STAT= */
+ if (code->ext.actual->next->next->next->next->expr != NULL)
+ {
+ gcc_assert (code->ext.actual->next->next->next->next->expr->expr_type
+ == EXPR_VARIABLE);
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr_val (&argse,
+ code->ext.actual->next->next->next->next->expr);
+ gfc_add_block_to_block (&block, &argse.pre);
+ gfc_add_block_to_block (&post_block, &argse.post);
+ gfc_add_modify (&block, argse.expr,
+ build_int_cst (TREE_TYPE (argse.expr), 0));
+ }
+ gfc_add_block_to_block (&block, &post_block);
return gfc_finish_block (&block);
}
@@ -8632,8 +8813,20 @@ gfc_conv_intrinsic_subroutine (gfc_code *code)
res = conv_intrinsic_move_alloc (code);
break;
+ case GFC_ISYM_ATOMIC_CAS:
+ res = conv_intrinsic_atomic_cas (code);
+ break;
+
+ case GFC_ISYM_ATOMIC_ADD:
+ case GFC_ISYM_ATOMIC_AND:
case GFC_ISYM_ATOMIC_DEF:
- res = conv_intrinsic_atomic_def (code);
+ case GFC_ISYM_ATOMIC_OR:
+ case GFC_ISYM_ATOMIC_XOR:
+ case GFC_ISYM_ATOMIC_FETCH_ADD:
+ case GFC_ISYM_ATOMIC_FETCH_AND:
+ case GFC_ISYM_ATOMIC_FETCH_OR:
+ case GFC_ISYM_ATOMIC_FETCH_XOR:
+ res = conv_intrinsic_atomic_op (code);
break;
case GFC_ISYM_ATOMIC_REF: