OSDN Git Service

2008-11-16 Mikael Morin <mikael.morin@tele2.fr>
authormikael <mikael@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 16 Nov 2008 22:45:10 +0000 (22:45 +0000)
committermikael <mikael@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 16 Nov 2008 22:45:10 +0000 (22:45 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@141931 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/fortran/ChangeLog
gcc/fortran/dependency.c
gcc/fortran/dependency.h
gcc/fortran/resolve.c
gcc/fortran/trans-expr.c
gcc/fortran/trans-stmt.c
gcc/testsuite/ChangeLog

index a72820c..69d8df2 100644 (file)
@@ -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
index 44187fe..cd768be 100644 (file)
@@ -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;
     }
 
index 041b0d5..1920c55 100644 (file)
@@ -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);
index aae1ef7..e4766d6 100644 (file)
@@ -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;
 }
 
index 58a18b9..e096021 100644 (file)
@@ -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
index 343d535..9505dfb 100644 (file)
@@ -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);
index daa937c..ae6939f 100644 (file)
@@ -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