diff options
author | Mikael Morin <mikael.morin@tele2.fr> | 2008-11-16 23:45:10 +0100 |
---|---|---|
committer | Mikael Morin <mikael@gcc.gnu.org> | 2008-11-16 22:45:10 +0000 |
commit | 2b0bd71482ce011ac9c399534feb9c62a7d75a80 (patch) | |
tree | 232858a8b76bd4730269441ec98967c72d4e5605 | |
parent | d3ea650c44d79a7ba10ec2964cf2bfd707c7b396 (diff) | |
download | gcc-2b0bd71482ce011ac9c399534feb9c62a7d75a80.zip gcc-2b0bd71482ce011ac9c399534feb9c62a7d75a80.tar.gz gcc-2b0bd71482ce011ac9c399534feb9c62a7d75a80.tar.bz2 |
re PR fortran/35681 (wrong result for vector subscripted array expression in MVBITS)
2008-11-16 Mikael Morin <mikael.morin@tele2.fr>
PR fortran/35681
* dependency.c (gfc_check_argument_var_dependency): Add
elemental check flag. Issue a warning if we find a dependency
but don't generate a temporary. Add the case of an elemental
function call as actual argument to an elemental procedure.
Add the case of an operator expression as actual argument
to an elemental procedure.
(gfc_check_argument_dependency): Add elemental check flag.
Update calls to gfc_check_argument_var_dependency.
(gfc_check_fncall_dependency): Add elemental check flag.
Update call to gfc_check_argument_dependency.
* trans-stmt.c (gfc_trans_call): Make call to
gfc_conv_elemental_dependency unconditional, but with a flag
whether we should check dependencies between variables.
(gfc_conv_elemental_dependency): Add elemental check flag.
Update call to gfc_check_fncall_dependency.
* trans-expr.c (gfc_trans_arrayfunc_assign): Update call to
gfc_check_fncall_dependency.
* resolve.c (find_noncopying_intrinsics): Update call to
gfc_check_fncall_dependency.
* dependency.h (enum gfc_dep_check): New enum.
(gfc_check_fncall_dependency): Update prototype.
2008-11-16 Mikael Morin <mikael.morin@tele2.fr>
PR fortran/35681
* gfortran.dg/elemental_dependency_1.f90: New test.
From-SVN: r141931
-rw-r--r-- | gcc/fortran/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/fortran/dependency.c | 80 | ||||
-rw-r--r-- | gcc/fortran/dependency.h | 13 | ||||
-rw-r--r-- | gcc/fortran/resolve.c | 3 | ||||
-rw-r--r-- | gcc/fortran/trans-expr.c | 3 | ||||
-rw-r--r-- | gcc/fortran/trans-stmt.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 |
7 files changed, 128 insertions, 22 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index a72820c..69d8df2 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,28 @@ +2008-11-16 Mikael Morin <mikael.morin@tele2.fr> + + PR fortran/35681 + * dependency.c (gfc_check_argument_var_dependency): Add + elemental check flag. Issue a warning if we find a dependency + but don't generate a temporary. Add the case of an elemental + function call as actual argument to an elemental procedure. + Add the case of an operator expression as actual argument + to an elemental procedure. + (gfc_check_argument_dependency): Add elemental check flag. + Update calls to gfc_check_argument_var_dependency. + (gfc_check_fncall_dependency): Add elemental check flag. + Update call to gfc_check_argument_dependency. + * trans-stmt.c (gfc_trans_call): Make call to + gfc_conv_elemental_dependency unconditional, but with a flag + whether we should check dependencies between variables. + (gfc_conv_elemental_dependency): Add elemental check flag. + Update call to gfc_check_fncall_dependency. + * trans-expr.c (gfc_trans_arrayfunc_assign): Update call to + gfc_check_fncall_dependency. + * resolve.c (find_noncopying_intrinsics): Update call to + gfc_check_fncall_dependency. + * dependency.h (enum gfc_dep_check): New enum. + (gfc_check_fncall_dependency): Update prototype. + 2008-11-16 Mikael Morin <mikael.morin@tele2.fr> PR fortran/37992 diff --git a/gcc/fortran/dependency.c b/gcc/fortran/dependency.c index 44187fe..cd768be 100644 --- a/gcc/fortran/dependency.c +++ b/gcc/fortran/dependency.c @@ -432,25 +432,81 @@ gfc_ref_needs_temporary_p (gfc_ref *ref) static int gfc_check_argument_var_dependency (gfc_expr *var, sym_intent intent, - gfc_expr *expr) + gfc_expr *expr, gfc_dep_check elemental) { + gfc_expr *arg; + 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, 1)); + /* In case of elemental subroutines, there is no dependency + between two same-range array references. */ + if (gfc_ref_needs_temporary_p (expr->ref) + || gfc_check_dependency (var, expr, !elemental)) + { + if (elemental == ELEM_DONT_CHECK_VARIABLE) + { + /* Elemental procedures forbid unspecified intents, + and we don't check dependencies for INTENT_IN args. */ + gcc_assert (intent == INTENT_OUT || intent == INTENT_INOUT); + + /* We are told not to check dependencies. + We do it, however, and issue a warning in case we find one. + If a dependency is found in the case + elemental == ELEM_CHECK_VARIABLE, we will generate + a temporary, so we don't need to bother the user. */ + gfc_warning ("INTENT(%s) actual argument at %L might interfere " + "with actual argument at %L.", + intent == INTENT_OUT ? "OUT" : "INOUT", + &var->where, &expr->where); + return 0; + } + else + return 1; + } + return 0; case EXPR_ARRAY: return gfc_check_dependency (var, expr, 1); case EXPR_FUNCTION: - if (intent != INTENT_IN && expr->inline_noncopying_intrinsic) + if (intent != INTENT_IN && expr->inline_noncopying_intrinsic + && (arg = gfc_get_noncopying_intrinsic_argument (expr)) + && gfc_check_argument_var_dependency (var, intent, arg, elemental)) + return 1; + if (elemental) { - expr = gfc_get_noncopying_intrinsic_argument (expr); - return gfc_check_argument_var_dependency (var, intent, expr); + if ((expr->value.function.esym + && expr->value.function.esym->attr.elemental) + || (expr->value.function.isym + && expr->value.function.isym->elemental)) + return gfc_check_fncall_dependency (var, intent, NULL, + expr->value.function.actual, + ELEM_CHECK_VARIABLE); + } + return 0; + + case EXPR_OP: + /* In case of non-elemental procedures, there is no need to catch + dependencies, as we will make a temporary anyway. */ + if (elemental) + { + /* If the actual arg EXPR is an expression, we need to catch + a dependency between variables in EXPR and VAR, + an intent((IN)OUT) variable. */ + if (expr->value.op.op1 + && gfc_check_argument_var_dependency (var, intent, + expr->value.op.op1, + ELEM_CHECK_VARIABLE)) + return 1; + else if (expr->value.op.op2 + && gfc_check_argument_var_dependency (var, intent, + expr->value.op.op2, + ELEM_CHECK_VARIABLE)) + return 1; } return 0; @@ -465,18 +521,19 @@ gfc_check_argument_var_dependency (gfc_expr *var, sym_intent intent, static int gfc_check_argument_dependency (gfc_expr *other, sym_intent intent, - gfc_expr *expr) + gfc_expr *expr, gfc_dep_check elemental) { switch (other->expr_type) { case EXPR_VARIABLE: - return gfc_check_argument_var_dependency (other, intent, expr); + return gfc_check_argument_var_dependency (other, intent, expr, elemental); 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 gfc_check_argument_dependency (other, INTENT_IN, expr, + elemental); } return 0; @@ -491,7 +548,8 @@ gfc_check_argument_dependency (gfc_expr *other, sym_intent intent, int gfc_check_fncall_dependency (gfc_expr *other, sym_intent intent, - gfc_symbol *fnsym, gfc_actual_arglist *actual) + gfc_symbol *fnsym, gfc_actual_arglist *actual, + gfc_dep_check elemental) { gfc_formal_arglist *formal; gfc_expr *expr; @@ -514,7 +572,7 @@ gfc_check_fncall_dependency (gfc_expr *other, sym_intent intent, && formal->sym->attr.intent == INTENT_IN) continue; - if (gfc_check_argument_dependency (other, intent, expr)) + if (gfc_check_argument_dependency (other, intent, expr, elemental)) return 1; } diff --git a/gcc/fortran/dependency.h b/gcc/fortran/dependency.h index 041b0d5..1920c55 100644 --- a/gcc/fortran/dependency.h +++ b/gcc/fortran/dependency.h @@ -19,13 +19,24 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ +/****************************** Enums *********************************/ +typedef enum +{ + NOT_ELEMENTAL, /* Not elemental case: normal dependency check. */ + ELEM_CHECK_VARIABLE, /* Test whether variables overlap. */ + ELEM_DONT_CHECK_VARIABLE /* Test whether variables overlap only if used + in an expression. */ +} +gfc_dep_check; +/*********************** Functions prototypes **************************/ + bool gfc_ref_needs_temporary_p (gfc_ref *); bool gfc_full_array_ref_p (gfc_ref *); gfc_expr *gfc_get_noncopying_intrinsic_argument (gfc_expr *); int gfc_check_fncall_dependency (gfc_expr *, sym_intent, gfc_symbol *, - gfc_actual_arglist *); + gfc_actual_arglist *, gfc_dep_check); int gfc_check_dependency (gfc_expr *, gfc_expr *, bool); int gfc_is_same_range (gfc_array_ref *, gfc_array_ref *, int, int); int gfc_expr_is_one (gfc_expr *, int); diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index aae1ef7..e4766d6 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -1491,7 +1491,8 @@ find_noncopying_intrinsics (gfc_symbol *fnsym, gfc_actual_arglist *actual) 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)) + && !gfc_check_fncall_dependency (expr, INTENT_IN, fnsym, actual, + NOT_ELEMENTAL)) ap->expr->inline_noncopying_intrinsic = 1; } diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 58a18b9..e096021 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -4288,7 +4288,8 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) /* Check for a dependency. */ if (gfc_check_fncall_dependency (expr1, INTENT_OUT, expr2->value.function.esym, - expr2->value.function.actual)) + expr2->value.function.actual, + NOT_ELEMENTAL)) return NULL; /* The frontend doesn't seem to bother filling in expr->symtree for intrinsic diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 343d535..9505dfb 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -201,7 +201,8 @@ gfc_trans_entry (gfc_code * code) can be used, as is, to copy the result back to the variable. */ static void gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse, - gfc_symbol * sym, gfc_actual_arglist * arg) + gfc_symbol * sym, gfc_actual_arglist * arg, + gfc_dep_check check_variable) { gfc_actual_arglist *arg0; gfc_expr *e; @@ -249,7 +250,7 @@ gfc_conv_elemental_dependencies (gfc_se * se, gfc_se * loopse, && e->rank && fsym && fsym->attr.intent != INTENT_IN && gfc_check_fncall_dependency (e, fsym->attr.intent, - sym, arg0)) + sym, arg0, check_variable)) { tree initial; stmtblock_t temp_post; @@ -333,6 +334,7 @@ gfc_trans_call (gfc_code * code, bool dependency_check) gfc_se se; gfc_ss * ss; int has_alternate_specifier; + gfc_dep_check check_variable; /* A CALL starts a new block because the actual arguments may have to be evaluated first. */ @@ -395,6 +397,10 @@ gfc_trans_call (gfc_code * code, bool dependency_check) gfc_add_ss_to_loop (&loop, ss); gfc_conv_ss_startstride (&loop); + /* TODO: gfc_conv_loop_setup generates a temporary for vector + subscripts. This could be prevented in the elemental case + as temporaries are handled separatedly + (below in gfc_conv_elemental_dependencies). */ gfc_conv_loop_setup (&loop, &code->expr->where); gfc_mark_ss_chain_used (ss, 1); @@ -404,12 +410,11 @@ gfc_trans_call (gfc_code * code, bool dependency_check) /* For operator assignment, do dependency checking. */ if (dependency_check) - { - gfc_symbol *sym; - sym = code->resolved_sym; - gfc_conv_elemental_dependencies (&se, &loopse, sym, - code->ext.actual); - } + check_variable = ELEM_CHECK_VARIABLE; + else + check_variable = ELEM_DONT_CHECK_VARIABLE; + gfc_conv_elemental_dependencies (&se, &loopse, code->resolved_sym, + code->ext.actual, check_variable); /* Generate the loop body. */ gfc_start_scalarized_body (&loop, &body); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index daa937c..ae6939f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2008-11-16 Mikael Morin <mikael.morin@tele2.fr> + + PR fortran/35681 + * gfortran.dg/elemental_dependency_1.f90: New test. + 2008-11-16 Mikael Morin <mikael.morin@tele2.fr> PR fortran/37992 |