diff options
author | Richard Sandiford <richard@codesourcery.com> | 2005-12-13 05:23:12 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2005-12-13 05:23:12 +0000 |
commit | 1524f80b1ceeda3c293142f4e370616be6dcf2cf (patch) | |
tree | 8b430f1a509f3fecd45aafac44d2707a38eb02d2 /gcc/fortran | |
parent | 264c41eda5b1d3b073053da88f7e757635269cc3 (diff) | |
download | gcc-1524f80b1ceeda3c293142f4e370616be6dcf2cf.zip gcc-1524f80b1ceeda3c293142f4e370616be6dcf2cf.tar.gz gcc-1524f80b1ceeda3c293142f4e370616be6dcf2cf.tar.bz2 |
Make-lang.in (fortran/trans-resolve.o): Depend on fortran/dependency.h.
gcc/fortran/
* Make-lang.in (fortran/trans-resolve.o): Depend on
fortran/dependency.h.
* gfortran.h (gfc_expr): Add an "inline_noncopying_intrinsic" flag.
* dependency.h (gfc_get_noncopying_intrinsic_argument): Declare.
(gfc_check_fncall_dependency): Change prototype.
* dependency.c (gfc_get_noncopying_intrinsic_argument): New function.
(gfc_check_argument_var_dependency): New function, split from
gfc_check_fncall_dependency.
(gfc_check_argument_dependency): New function.
(gfc_check_fncall_dependency): Replace the expression parameter with
separate symbol and argument list parameters. Generalize the function
to handle dependencies for any type of expression, not just variables.
Accept a further argument giving the intent of the expression being
tested. Ignore intent(in) arguments if that expression is also
intent(in).
* resolve.c: Include dependency.h.
(find_noncopying_intrinsics): New function.
(resolve_function, resolve_call): Call it on success.
* trans-array.h (gfc_conv_array_transpose): Declare.
(gfc_check_fncall_dependency): Remove prototype.
* trans-array.c (gfc_conv_array_transpose): New function.
* trans-intrinsic.c (gfc_conv_intrinsic_function): Don't use the
libcall handling if the expression is to be evaluated inline.
Add a case for handling inline transpose()s.
* trans-expr.c (gfc_trans_arrayfunc_assign): Adjust for the new
interface provided by gfc_check_fncall_dependency.
libgfortran/
* m4/matmul.m4: Use a different order in the special case of a
transposed first argument.
* generated/matmul_c4.c, generated/matmul_c8.c, generated/matmul_c10.c,
* generated/matmul_c16.c, generated/matmul_i4.c, generated/matmul_i8.c,
* generated/matmul_i10.c, generated/matmul_r4.c, generated/matmul_r8.c
* generated/matmul_r10.c, generated/matmul_r16.c: Regenerated.
Co-Authored-By: Victor Leikehman <LEI@il.ibm.com>
From-SVN: r108459
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 29 | ||||
-rw-r--r-- | gcc/fortran/Make-lang.in | 1 | ||||
-rw-r--r-- | gcc/fortran/dependency.c | 132 | ||||
-rw-r--r-- | gcc/fortran/dependency.h | 4 | ||||
-rw-r--r-- | gcc/fortran/gfortran.h | 3 | ||||
-rw-r--r-- | gcc/fortran/resolve.c | 57 | ||||
-rw-r--r-- | gcc/fortran/trans-array.c | 89 | ||||
-rw-r--r-- | gcc/fortran/trans-array.h | 4 | ||||
-rw-r--r-- | gcc/fortran/trans-expr.c | 4 | ||||
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 12 |
10 files changed, 285 insertions, 50 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index d480b6f..ea1afe1 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,32 @@ +2005-12-13 Richard Sandiford <richard@codesourcery.com> + + * Make-lang.in (fortran/trans-resolve.o): Depend on + fortran/dependency.h. + * gfortran.h (gfc_expr): Add an "inline_noncopying_intrinsic" flag. + * dependency.h (gfc_get_noncopying_intrinsic_argument): Declare. + (gfc_check_fncall_dependency): Change prototype. + * dependency.c (gfc_get_noncopying_intrinsic_argument): New function. + (gfc_check_argument_var_dependency): New function, split from + gfc_check_fncall_dependency. + (gfc_check_argument_dependency): New function. + (gfc_check_fncall_dependency): Replace the expression parameter with + separate symbol and argument list parameters. Generalize the function + to handle dependencies for any type of expression, not just variables. + Accept a further argument giving the intent of the expression being + tested. Ignore intent(in) arguments if that expression is also + intent(in). + * resolve.c: Include dependency.h. + (find_noncopying_intrinsics): New function. + (resolve_function, resolve_call): Call it on success. + * trans-array.h (gfc_conv_array_transpose): Declare. + (gfc_check_fncall_dependency): Remove prototype. + * trans-array.c (gfc_conv_array_transpose): New function. + * trans-intrinsic.c (gfc_conv_intrinsic_function): Don't use the + libcall handling if the expression is to be evaluated inline. + Add a case for handling inline transpose()s. + * trans-expr.c (gfc_trans_arrayfunc_assign): Adjust for the new + interface provided by gfc_check_fncall_dependency. + 2005-12-12 Steven G. Kargl <kargls@comcast.net> PR fortran/25078 diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in index c1dbfef..4be0f7c 100644 --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -286,4 +286,5 @@ fortran/trans-intrinsic.o: $(GFORTRAN_TRANS_DEPS) fortran/mathbuiltins.def \ gt-fortran-trans-intrinsic.h fortran/dependency.o: $(GFORTRAN_TRANS_DEPS) fortran/dependency.h fortran/trans-common.o: $(GFORTRAN_TRANS_DEPS) +fortran/resolve.o: fortran/dependency.h diff --git a/gcc/fortran/dependency.c b/gcc/fortran/dependency.c index b93808a..d3a486e 100644 --- a/gcc/fortran/dependency.c +++ b/gcc/fortran/dependency.c @@ -175,6 +175,32 @@ gfc_is_same_range (gfc_array_ref * ar1, gfc_array_ref * ar2, int n, int def) } +/* Some array-returning intrinsics can be implemented by reusing the + data from one of the array arguments. For example, TRANPOSE does + not necessarily need to allocate new data: it can be implemented + by copying the original array's descriptor and simply swapping the + two dimension specifications. + + If EXPR is a call to such an intrinsic, return the argument + whose data can be reused, otherwise return NULL. */ + +gfc_expr * +gfc_get_noncopying_intrinsic_argument (gfc_expr * expr) +{ + if (expr->expr_type != EXPR_FUNCTION || !expr->value.function.isym) + return NULL; + + switch (expr->value.function.isym->generic_id) + { + case GFC_ISYM_TRANSPOSE: + return expr->value.function.actual->expr; + + default: + return NULL; + } +} + + /* Return true if the result of reference REF can only be constructed using a temporary array. */ @@ -214,23 +240,82 @@ gfc_ref_needs_temporary_p (gfc_ref *ref) } -/* Dependency checking for direct function return by reference. - Returns true if the arguments of the function depend on the - destination. This is considerably less conservative than other - dependencies because many function arguments will already be - copied into a temporary. */ +/* Return true if array variable VAR could be passed to the same function + as argument EXPR without interfering with EXPR. INTENT is the intent + of VAR. + + This is considerably less conservative than other dependencies + because many function arguments will already be copied into a + temporary. */ + +static int +gfc_check_argument_var_dependency (gfc_expr * var, sym_intent intent, + gfc_expr * expr) +{ + gcc_assert (var->expr_type == EXPR_VARIABLE); + gcc_assert (var->rank > 0); + + switch (expr->expr_type) + { + case EXPR_VARIABLE: + return (gfc_ref_needs_temporary_p (expr->ref) + || gfc_check_dependency (var, expr, NULL, 0)); + + case EXPR_ARRAY: + return gfc_check_dependency (var, expr, NULL, 0); + + case EXPR_FUNCTION: + if (intent != INTENT_IN && expr->inline_noncopying_intrinsic) + { + expr = gfc_get_noncopying_intrinsic_argument (expr); + return gfc_check_argument_var_dependency (var, intent, expr); + } + return 0; + + default: + return 0; + } +} + + +/* Like gfc_check_argument_var_dependency, but extended to any + array expression OTHER, not just variables. */ + +static int +gfc_check_argument_dependency (gfc_expr * other, sym_intent intent, + gfc_expr * expr) +{ + switch (other->expr_type) + { + case EXPR_VARIABLE: + return gfc_check_argument_var_dependency (other, intent, expr); + + case EXPR_FUNCTION: + if (other->inline_noncopying_intrinsic) + { + other = gfc_get_noncopying_intrinsic_argument (other); + return gfc_check_argument_dependency (other, INTENT_IN, expr); + } + return 0; + + default: + return 0; + } +} + + +/* Like gfc_check_argument_dependency, but check all the arguments in ACTUAL. + FNSYM is the function being called, or NULL if not known. */ int -gfc_check_fncall_dependency (gfc_expr * dest, gfc_expr * fncall) +gfc_check_fncall_dependency (gfc_expr * other, sym_intent intent, + gfc_symbol * fnsym, gfc_actual_arglist * actual) { - gfc_actual_arglist *actual; + gfc_formal_arglist *formal; gfc_expr *expr; - gcc_assert (dest->expr_type == EXPR_VARIABLE - && fncall->expr_type == EXPR_FUNCTION); - gcc_assert (fncall->rank > 0); - - for (actual = fncall->value.function.actual; actual; actual = actual->next) + formal = fnsym ? fnsym->formal : NULL; + for (; actual; actual = actual->next, formal = formal ? formal->next : NULL) { expr = actual->expr; @@ -238,23 +323,14 @@ gfc_check_fncall_dependency (gfc_expr * dest, gfc_expr * fncall) if (!expr) continue; - /* Non-variable expressions will be allocated temporaries anyway. */ - switch (expr->expr_type) - { - case EXPR_VARIABLE: - if (!gfc_ref_needs_temporary_p (expr->ref) - && gfc_check_dependency (dest, expr, NULL, 0)) - return 1; - break; - - case EXPR_ARRAY: - if (gfc_check_dependency (dest, expr, NULL, 0)) - return 1; - break; + /* Skip intent(in) arguments if OTHER itself is intent(in). */ + if (formal + && intent == INTENT_IN + && formal->sym->attr.intent == INTENT_IN) + continue; - default: - break; - } + if (gfc_check_argument_dependency (other, intent, expr)) + return 1; } return 0; diff --git a/gcc/fortran/dependency.h b/gcc/fortran/dependency.h index c4fe493..7ef2edd 100644 --- a/gcc/fortran/dependency.h +++ b/gcc/fortran/dependency.h @@ -22,7 +22,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA bool gfc_ref_needs_temporary_p (gfc_ref *); -int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *); +gfc_expr *gfc_get_noncopying_intrinsic_argument (gfc_expr *); +int gfc_check_fncall_dependency (gfc_expr *, sym_intent, gfc_symbol *, + gfc_actual_arglist *); int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int); int gfc_is_same_range (gfc_array_ref *, gfc_array_ref *, int, int); int gfc_dep_compare_expr (gfc_expr *, gfc_expr *); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index f22f6a48..7d0c725 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1129,6 +1129,9 @@ typedef struct gfc_expr /* True if it is converted from Hollerith constant. */ unsigned int from_H : 1; + /* True if the expression is a call to a function that returns an array, + and if we have decided not to allocate temporary data for that array. */ + unsigned int inline_noncopying_intrinsic : 1; union { diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index c543a95..e363763 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -24,6 +24,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor,Boston, MA #include "system.h" #include "gfortran.h" #include "arith.h" /* For gfc_compare_expr(). */ +#include "dependency.h" /* Types used in equivalence statements. */ @@ -804,6 +805,24 @@ resolve_actual_arglist (gfc_actual_arglist * arg) } +/* Go through each actual argument in ACTUAL and see if it can be + implemented as an inlined, non-copying intrinsic. FNSYM is the + function being called, or NULL if not known. */ + +static void +find_noncopying_intrinsics (gfc_symbol * fnsym, gfc_actual_arglist * actual) +{ + gfc_actual_arglist *ap; + gfc_expr *expr; + + for (ap = actual; ap; ap = ap->next) + if (ap->expr + && (expr = gfc_get_noncopying_intrinsic_argument (ap->expr)) + && !gfc_check_fncall_dependency (expr, INTENT_IN, fnsym, actual)) + ap->expr->inline_noncopying_intrinsic = 1; +} + + /************* Function resolution *************/ /* Resolve a function call known to be generic. @@ -1150,6 +1169,9 @@ resolve_function (gfc_expr * expr) } } + if (t == SUCCESS) + find_noncopying_intrinsics (expr->value.function.esym, + expr->value.function.actual); return t; } @@ -1372,27 +1394,28 @@ resolve_call (gfc_code * c) if (resolve_actual_arglist (c->ext.actual) == FAILURE) return FAILURE; - if (c->resolved_sym != NULL) - return SUCCESS; - - switch (procedure_kind (c->symtree->n.sym)) - { - case PTYPE_GENERIC: - t = resolve_generic_s (c); - break; + t = SUCCESS; + if (c->resolved_sym == NULL) + switch (procedure_kind (c->symtree->n.sym)) + { + case PTYPE_GENERIC: + t = resolve_generic_s (c); + break; - case PTYPE_SPECIFIC: - t = resolve_specific_s (c); - break; + case PTYPE_SPECIFIC: + t = resolve_specific_s (c); + break; - case PTYPE_UNKNOWN: - t = resolve_unknown_s (c); - break; + case PTYPE_UNKNOWN: + t = resolve_unknown_s (c); + break; - default: - gfc_internal_error ("resolve_subroutine(): bad function type"); - } + default: + gfc_internal_error ("resolve_subroutine(): bad function type"); + } + if (t == SUCCESS) + find_noncopying_intrinsics (c->resolved_sym, c->ext.actual); return t; } diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index a94d7e8..45c8351 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -673,6 +673,95 @@ gfc_trans_allocate_temp_array (stmtblock_t * pre, stmtblock_t * post, } +/* Generate code to tranpose array EXPR by creating a new descriptor + in which the dimension specifications have been reversed. */ + +void +gfc_conv_array_transpose (gfc_se * se, gfc_expr * expr) +{ + tree dest, src, dest_index, src_index; + gfc_loopinfo *loop; + gfc_ss_info *dest_info, *src_info; + gfc_ss *dest_ss, *src_ss; + gfc_se src_se; + int n; + + loop = se->loop; + + src_ss = gfc_walk_expr (expr); + dest_ss = se->ss; + + src_info = &src_ss->data.info; + dest_info = &dest_ss->data.info; + + /* Get a descriptor for EXPR. */ + gfc_init_se (&src_se, NULL); + gfc_conv_expr_descriptor (&src_se, expr, src_ss); + gfc_add_block_to_block (&se->pre, &src_se.pre); + gfc_add_block_to_block (&se->post, &src_se.post); + src = src_se.expr; + + /* Allocate a new descriptor for the return value. */ + dest = gfc_create_var (TREE_TYPE (src), "atmp"); + dest_info->descriptor = dest; + se->expr = dest; + + /* Copy across the dtype field. */ + gfc_add_modify_expr (&se->pre, + gfc_conv_descriptor_dtype (dest), + gfc_conv_descriptor_dtype (src)); + + /* Copy the dimension information, renumbering dimension 1 to 0 and + 0 to 1. */ + gcc_assert (dest_info->dimen == 2); + gcc_assert (src_info->dimen == 2); + for (n = 0; n < 2; n++) + { + dest_info->delta[n] = integer_zero_node; + dest_info->start[n] = integer_zero_node; + dest_info->stride[n] = integer_one_node; + dest_info->dim[n] = n; + + dest_index = gfc_rank_cst[n]; + src_index = gfc_rank_cst[1 - n]; + + gfc_add_modify_expr (&se->pre, + gfc_conv_descriptor_stride (dest, dest_index), + gfc_conv_descriptor_stride (src, src_index)); + + gfc_add_modify_expr (&se->pre, + gfc_conv_descriptor_lbound (dest, dest_index), + gfc_conv_descriptor_lbound (src, src_index)); + + gfc_add_modify_expr (&se->pre, + gfc_conv_descriptor_ubound (dest, dest_index), + gfc_conv_descriptor_ubound (src, src_index)); + + if (!loop->to[n]) + { + gcc_assert (integer_zerop (loop->from[n])); + loop->to[n] = build2 (MINUS_EXPR, gfc_array_index_type, + gfc_conv_descriptor_ubound (dest, dest_index), + gfc_conv_descriptor_lbound (dest, dest_index)); + } + } + + /* Copy the data pointer. */ + dest_info->data = gfc_conv_descriptor_data_get (src); + gfc_conv_descriptor_data_set (&se->pre, dest, dest_info->data); + + /* Copy the offset. This is not changed by transposition: the top-left + element is still at the same offset as before. */ + dest_info->offset = gfc_conv_descriptor_offset (src); + gfc_add_modify_expr (&se->pre, + gfc_conv_descriptor_offset (dest), + dest_info->offset); + + if (dest_info->dimen > loop->temp_dim) + loop->temp_dim = dest_info->dimen; +} + + /* Return the number of iterations in a loop that starts at START, ends at END, and has step STEP. */ diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h index af990a9..8ceced9 100644 --- a/gcc/fortran/trans-array.h +++ b/gcc/fortran/trans-array.h @@ -91,6 +91,8 @@ void gfc_conv_tmp_ref (gfc_se *); void gfc_conv_expr_descriptor (gfc_se *, gfc_expr *, gfc_ss *); /* Convert an array for passing as an actual function parameter. */ void gfc_conv_array_parameter (gfc_se *, gfc_expr *, gfc_ss *, int); +/* Evaluate and transpose a matrix expression. */ +void gfc_conv_array_transpose (gfc_se *, gfc_expr *); /* These work with both descriptors and descriptorless arrays. */ tree gfc_conv_array_data (tree); @@ -112,8 +114,6 @@ tree gfc_conv_descriptor_ubound (tree, tree); /* Dependency checking for WHERE and FORALL. */ int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int); -/* Dependency checking for function calls. */ -int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *); /* Add pre-loop scalarization code for intrinsic functions which require special handling. */ diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index a0339af..5e1535e 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2627,7 +2627,9 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) } /* Check for a dependency. */ - if (gfc_check_fncall_dependency (expr1, expr2)) + if (gfc_check_fncall_dependency (expr1, INTENT_OUT, + expr2->value.function.esym, + expr2->value.function.actual)) return NULL; /* The frontend doesn't seem to bother filling in expr->symtree for intrinsic diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index ea9c2e3..0a61cd4 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -2894,7 +2894,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) name = &expr->value.function.name[2]; - if (expr->rank > 0) + if (expr->rank > 0 && !expr->inline_noncopying_intrinsic) { lib = gfc_is_intrinsic_libcall (expr); if (lib != 0) @@ -3119,6 +3119,16 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) gfc_conv_intrinsic_bound (se, expr, 0); break; + case GFC_ISYM_TRANSPOSE: + if (se->ss && se->ss->useflags) + { + gfc_conv_tmp_array_ref (se); + gfc_advance_se_ss_chain (se); + } + else + gfc_conv_array_transpose (se, expr->value.function.actual->expr); + break; + case GFC_ISYM_LEN: gfc_conv_intrinsic_len (se, expr); break; |