aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimplify.cc')
-rw-r--r--gcc/gimplify.cc168
1 files changed, 137 insertions, 31 deletions
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 9f4722f..22ff107 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -1405,18 +1405,46 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
|| alloc == NULL_TREE
|| !integer_onep (alloc)))
{
- tree tmp = build_pointer_type (TREE_TYPE (t));
- tree v = create_tmp_var (tmp, get_name (t));
- DECL_IGNORED_P (v) = 0;
- tmp = remove_attribute ("omp allocate", DECL_ATTRIBUTES (t));
- DECL_ATTRIBUTES (v)
- = tree_cons (get_identifier ("omp allocate var"),
- build_tree_list (NULL_TREE, t), tmp);
- tmp = build_fold_indirect_ref (v);
- TREE_THIS_NOTRAP (tmp) = 1;
- SET_DECL_VALUE_EXPR (t, tmp);
- DECL_HAS_VALUE_EXPR_P (t) = 1;
- tree sz = TYPE_SIZE_UNIT (TREE_TYPE (t));
+ /* Fortran might already use a pointer type internally;
+ use that pointer except for type(C_ptr) and type(C_funptr);
+ note that normal proc pointers are rejected. */
+ tree type = TREE_TYPE (t);
+ tree tmp, v;
+ if (lang_GNU_Fortran ()
+ && POINTER_TYPE_P (type)
+ && TREE_TYPE (type) != void_type_node
+ && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE)
+ {
+ type = TREE_TYPE (type);
+ v = t;
+ }
+ else
+ {
+ tmp = build_pointer_type (type);
+ v = create_tmp_var (tmp, get_name (t));
+ DECL_IGNORED_P (v) = 0;
+ DECL_ATTRIBUTES (v)
+ = tree_cons (get_identifier ("omp allocate var"),
+ build_tree_list (NULL_TREE, t),
+ remove_attribute ("omp allocate",
+ DECL_ATTRIBUTES (t)));
+ tmp = build_fold_indirect_ref (v);
+ TREE_THIS_NOTRAP (tmp) = 1;
+ SET_DECL_VALUE_EXPR (t, tmp);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ }
+ tree sz = TYPE_SIZE_UNIT (type);
+ /* The size to use in Fortran might not match TYPE_SIZE_UNIT;
+ hence, for some decls, a size variable is saved in the
+ attributes; use it, if available. */
+ if (TREE_CHAIN (TREE_VALUE (attr))
+ && TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr)))
+ && TREE_PURPOSE (
+ TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr)))))
+ {
+ sz = TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr)));
+ sz = TREE_PURPOSE (sz);
+ }
if (alloc == NULL_TREE)
alloc = build_zero_cst (ptr_type_node);
if (align == NULL_TREE)
@@ -1425,28 +1453,98 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
align = build_int_cst (size_type_node,
MAX (tree_to_uhwi (align),
DECL_ALIGN_UNIT (t)));
+ location_t loc = DECL_SOURCE_LOCATION (t);
tmp = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
- tmp = build_call_expr_loc (DECL_SOURCE_LOCATION (t), tmp,
- 3, align, sz, alloc);
- tmp = fold_build2_loc (DECL_SOURCE_LOCATION (t), MODIFY_EXPR,
- TREE_TYPE (v), v,
+ tmp = build_call_expr_loc (loc, tmp, 3, align, sz, alloc);
+ tmp = fold_build2_loc (loc, MODIFY_EXPR, TREE_TYPE (v), v,
fold_convert (TREE_TYPE (v), tmp));
- gcc_assert (BIND_EXPR_BODY (bind_expr) != NULL_TREE
- && (TREE_CODE (BIND_EXPR_BODY (bind_expr))
- == STATEMENT_LIST));
- tree_stmt_iterator e = tsi_start (BIND_EXPR_BODY (bind_expr));
- while (!tsi_end_p (e))
+ gcc_assert (BIND_EXPR_BODY (bind_expr) != NULL_TREE);
+ /* Ensure that either TREE_CHAIN (TREE_VALUE (attr) is set
+ and GOMP_FREE added here or that DECL_HAS_VALUE_EXPR_P (t)
+ is set, using in a condition much further below. */
+ gcc_assert (DECL_HAS_VALUE_EXPR_P (t)
+ || TREE_CHAIN (TREE_VALUE (attr)));
+ if (TREE_CHAIN (TREE_VALUE (attr)))
{
- if ((TREE_CODE (*e) == DECL_EXPR
- && TREE_OPERAND (*e, 0) == t)
- || (TREE_CODE (*e) == CLEANUP_POINT_EXPR
- && TREE_CODE (TREE_OPERAND (*e, 0)) == DECL_EXPR
- && TREE_OPERAND (TREE_OPERAND (*e, 0), 0) == t))
- break;
+ /* Fortran is special as it does not have properly nest
+ declarations in blocks. And as there is no
+ initializer, there is also no expression to look for.
+ Hence, the FE makes the statement list of the
+ try-finally block available. We can put the GOMP_alloc
+ at the top, unless an allocator or size expression
+ requires to put it afterward; note that the size is
+ always later in generated code; for strings, no
+ size expr but still an expr might be available.
+ As LTO does not handle a statement list, 'sl' has
+ to be removed; done so by removing the attribute. */
+ DECL_ATTRIBUTES (t)
+ = remove_attribute ("omp allocate",
+ DECL_ATTRIBUTES (t));
+ tree sl = TREE_PURPOSE (TREE_CHAIN (TREE_VALUE (attr)));
+ tree_stmt_iterator e = tsi_start (sl);
+ tree needle = NULL_TREE;
+ if (TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr))))
+ {
+ needle = TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr)));
+ needle = (TREE_VALUE (needle) ? TREE_VALUE (needle)
+ : sz);
+ }
+ else if (TREE_CHAIN (TREE_CHAIN (TREE_VALUE (attr))))
+ needle = sz;
+ else if (DECL_P (alloc) && DECL_ARTIFICIAL (alloc))
+ needle = alloc;
+
+ if (needle != NULL_TREE)
+ {
+ while (!tsi_end_p (e))
+ {
+ if (*e == needle
+ || (TREE_CODE (*e) == MODIFY_EXPR
+ && TREE_OPERAND (*e, 0) == needle))
+ break;
+ ++e;
+ }
+ gcc_assert (!tsi_end_p (e));
+ }
+ tsi_link_after (&e, tmp, TSI_SAME_STMT);
+
+ /* As the cleanup is in BIND_EXPR_BODY, GOMP_free is added
+ here; for C/C++ it will be added in the 'cleanup'
+ section after gimplification. But Fortran already has
+ a try-finally block. */
+ sl = TREE_VALUE (TREE_CHAIN (TREE_VALUE (attr)));
+ e = tsi_last (sl);
+ tmp = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
+ tmp = build_call_expr_loc (EXPR_LOCATION (*e), tmp, 2, v,
+ build_zero_cst (ptr_type_node));
+ tsi_link_after (&e, tmp, TSI_SAME_STMT);
+ tmp = build_clobber (TREE_TYPE (v), CLOBBER_EOL);
+ tmp = fold_build2_loc (loc, MODIFY_EXPR, TREE_TYPE (v), v,
+ fold_convert (TREE_TYPE (v), tmp));
++e;
+ tsi_link_after (&e, tmp, TSI_SAME_STMT);
}
- gcc_assert (!tsi_end_p (e));
- tsi_link_before (&e, tmp, TSI_SAME_STMT);
+ else
+ {
+ gcc_assert (TREE_CODE (BIND_EXPR_BODY (bind_expr))
+ == STATEMENT_LIST);
+ tree_stmt_iterator e;
+ e = tsi_start (BIND_EXPR_BODY (bind_expr));
+ while (!tsi_end_p (e))
+ {
+ if ((TREE_CODE (*e) == DECL_EXPR
+ && TREE_OPERAND (*e, 0) == t)
+ || (TREE_CODE (*e) == CLEANUP_POINT_EXPR
+ && (TREE_CODE (TREE_OPERAND (*e, 0))
+ == DECL_EXPR)
+ && (TREE_OPERAND (TREE_OPERAND (*e, 0), 0)
+ == t)))
+ break;
+ ++e;
+ }
+ gcc_assert (!tsi_end_p (e));
+ tsi_link_before (&e, tmp, TSI_SAME_STMT);
+ }
}
}
@@ -1544,11 +1642,19 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
&& TREE_USED (t)
&& lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t)))
{
+ /* For Fortran, TREE_CHAIN (TREE_VALUE (attr)) is set, which
+ causes that the GOMP_free call is already added above;
+ and "omp allocate" is removed from DECL_ATTRIBUTES. */
+ tree v = TREE_OPERAND (DECL_VALUE_EXPR (t), 0);
tree tmp = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
- tmp = build_call_expr_loc (end_locus, tmp, 2,
- TREE_OPERAND (DECL_VALUE_EXPR (t), 0),
+ tmp = build_call_expr_loc (end_locus, tmp, 2, v,
build_zero_cst (ptr_type_node));
gimplify_and_add (tmp, &cleanup);
+ gimple *clobber_stmt;
+ tmp = build_clobber (TREE_TYPE (v), CLOBBER_EOL);
+ clobber_stmt = gimple_build_assign (v, tmp);
+ gimple_set_location (clobber_stmt, end_locus);
+ gimplify_seq_add_stmt (&cleanup, clobber_stmt);
}
if (!DECL_HARD_REGISTER (t)
&& !TREE_THIS_VOLATILE (t)