diff mbox

[fortran] Fix for PR 60522

Message ID 53257FE2.5010802@netcologne.de
State New
Headers show

Commit Message

Thomas Koenig March 16, 2014, 10:41 a.m. UTC
Hello world,

the attached patch fixes PR 60522, a regresseion where temporary
variables were incorrectly introduced in a BLOCK within a WHERE
statement.

Regression-tested on x86_64-unknown-linux-gnu.

OK for trunk and the other open branches?

	Thomas

2014-04-16  Thomas Koenig  <tkoenig@gcc.gnu.org>

        PR fortran/60522
        * frontend-passes.c (top level): New variables where_level
        and where_code.
        (optimize_code):  Set where_code if we are within a
        WHERE statment.
        (cfe_code):  Likewise.
        (create_var):  Use where_code if within a WHERE statement.
        (optimize_namespace):  Set where_level.
        (gfc_code_walker):  Keep track of where_level.

2014-04-16  Thomas Koenig  <tkoenig@gcc.gnu.org>

        PR fortran/60522
        * gfortran.dg/where_4.f90:  New test case.

Comments

Mikael Morin March 16, 2014, 9:03 p.m. UTC | #1
Le 16/03/2014 11:41, Thomas Koenig a écrit :
> Hello world,
> 
> the attached patch fixes PR 60522, a regresseion where temporary 
> variables were incorrectly introduced in a BLOCK within a WHERE 
> statement.
> 
> Regression-tested on x86_64-unknown-linux-gnu.
> 
> OK for trunk and the other open branches?
> 
I have a testcase that I'm pretty sure you won't like. ;-)

I outputs with -ffrontend-optimize:
0	0	260	442	696

and without:
0	0	1468	8202	31260


Mikael


program foo

  implicit none
  integer, parameter :: n = 5

  integer :: i

  integer, dimension(n) :: a
  integer, dimension(n) :: b = (/ (i + 2, i=1,size(b)) /)
  integer, dimension(n) :: c = (/ (i*i, i=1,size(c)) /)
  integer, dimension(n) :: d

  d = 0
  a = b
  where(c > b)
    a = c
    d = bar(a) + bar(a)
  end where

  print *, d

contains

  pure function bar(x)
    integer, dimension(n), intent(in) :: x
    integer, dimension(n) :: bar

    bar = x * x * x + 5
  end function bar

end program foo
diff mbox

Patch

Index: frontend-passes.c
===================================================================
--- frontend-passes.c	(Revision 208592)
+++ frontend-passes.c	(Arbeitskopie)
@@ -84,6 +84,12 @@  static int iterator_level;
 static gfc_code **doloop_list;
 static int doloop_size, doloop_level;
 
+/* Keep track of whether we are within a WHERE
+   statement.  */
+
+static int where_level;
+static gfc_code **where_code;
+
 /* Vector of gfc_expr * to keep track of DO loops.  */
 
 struct my_struct *evec;
@@ -139,6 +145,18 @@  optimize_code (gfc_code **c, int *walk_subtrees AT
   inserted_block = NULL;
   changed_statement = NULL;
 
+
+  /* Keep track where to put a block around a WHERE statement.
+     TODO: We can do the same thing for FORALL.  */
+
+  if (where_level == 0)
+    {
+      if ((*c)->op == EXEC_WHERE)
+	where_code = c;
+      else
+	where_code = NULL;
+    }
+
   if (op == EXEC_ASSIGN)
     optimize_assignment (*c);
   return 0;
@@ -442,34 +460,40 @@  create_var (gfc_expr * e)
   gfc_expr *result;
   gfc_code *n;
   gfc_namespace *ns;
+  gfc_code **cc;
   int i;
 
+  if (where_level > 0)
+    cc = where_code;
+  else
+    cc = current_code;
+
   /* If the block hasn't already been created, do so.  */
   if (inserted_block == NULL)
     {
       inserted_block = XCNEW (gfc_code);
       inserted_block->op = EXEC_BLOCK;
-      inserted_block->loc = (*current_code)->loc;
+      inserted_block->loc = (*cc)->loc;
       ns = gfc_build_block_ns (current_ns);
       inserted_block->ext.block.ns = ns;
       inserted_block->ext.block.assoc = NULL;
 
-      ns->code = *current_code;
+      ns->code = *cc;
 
       /* If the statement has a label,  make sure it is transferred to
 	 the newly created block.  */
 
-      if ((*current_code)->here) 
+      if ((*cc)->here) 
 	{
 	  inserted_block->here = (*current_code)->here;
-	  (*current_code)->here = NULL;
+	  (*cc)->here = NULL;
 	}
 
-      inserted_block->next = (*current_code)->next;
+      inserted_block->next = (*cc)->next;
       changed_statement = &(inserted_block->ext.block.ns->code);
-      (*current_code)->next = NULL;
+      (*cc)->next = NULL;
       /* Insert the BLOCK at the right position.  */
-      *current_code = inserted_block;
+      *cc = inserted_block;
       ns->parent = current_ns;
     }
   else
@@ -633,6 +657,18 @@  cfe_code (gfc_code **c, int *walk_subtrees ATTRIBU
   current_code = c;
   inserted_block = NULL;
   changed_statement = NULL;
+
+  /* Keep track where to put a block around a WHERE statement.
+     TODO: We can do the same thing for FORALL.  */
+
+  if (where_level == 0)
+    {
+      if ((*c)->op == EXEC_WHERE)
+	where_code = c;
+      else
+	where_code = NULL;
+    }
+
   return 0;
 }
 
@@ -798,6 +834,7 @@  optimize_namespace (gfc_namespace *ns)
   forall_level = 0;
   iterator_level = 0;
   in_omp_workshare = false;
+  where_level = 0;
 
   gfc_code_walker (&ns->code, convert_do_while, dummy_expr_callback, NULL);
   gfc_code_walker (&ns->code, convert_elseif, dummy_expr_callback, NULL);
@@ -1980,6 +2017,10 @@  gfc_code_walker (gfc_code **c, walk_code_fn_t code
 		break;
 	      }
 
+	    case EXEC_WHERE:
+	      where_level ++;
+	      break;
+
 	    case EXEC_OPEN:
 	      WALK_SUBEXPR (co->ext.open->unit);
 	      WALK_SUBEXPR (co->ext.open->file);
@@ -2144,6 +2185,9 @@  gfc_code_walker (gfc_code **c, walk_code_fn_t code
 	  if (co->op == EXEC_DO)
 	    doloop_level --;
 
+	  if (co-> op == EXEC_WHERE)
+	    where_level --;
+
 	  in_omp_workshare = saved_in_omp_workshare;
 	}
     }