public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch, fortran] PR 40628, front-end optimization pass
@ 2010-07-17 18:38 Thomas Koenig
  2010-07-18  8:41 ` Daniel Kraft
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Koenig @ 2010-07-17 18:38 UTC (permalink / raw)
  To: fortran; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 739 bytes --]

Hello world,

finally, here's the first attempt at a front-end optimization pass.
Right now, it fixes PR 40626 and optimizes comparisons between variables
(which only really is relevant for character comparisons).  Many more
things could (and should) be added over time.

This now passes regression-testing for trunk.

OK for trunk?

	Thomas

2010-0717  Thomas Koenig  <tkoenig@gcc.gnu.org>

	* Make-lang.in:  Add fortran/optimize.o.
	* gfortran.h:  Add prototype for gfc_optimize_namespace.
	* trans-decl.c (gfc_generate_function_code):  If optimizing,
	call gfc_optimize_namespace.
	* optimize.c:  New file.

2010-0717  Thomas Koenig  <tkoenig@gcc.gnu.org>

	* trim_optimize_1.f90:  New test.
	* character_comparision_1.f90:  New test.


[-- Attachment #2: optimize.c --]
[-- Type: text/x-csrc, Size: 9152 bytes --]

/* Optimize statements on expressions, using fortran front end expressions.
   Copyright (C) 2010 Free Software Foundation, Inc.
   Contributed by Thomas König.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

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/>.  */

#include "config.h"
#include "system.h"
#include "gfortran.h"
#include "arith.h"

/* Forward declarations.  */

static void strip_function_call (gfc_expr *);
static void optimize_assignment (gfc_code *);
static void optimize_expr_0 (gfc_expr *);
static bool optimize_expr (gfc_expr *);
static bool optimize_op (gfc_expr *);
static bool optimize_equality (gfc_expr *, bool);
static void optimize_code (gfc_code *);
static void optimize_code_node (gfc_code *);
static void optimize_actual_arglist (gfc_actual_arglist *);


/* Go through all executable statements of a namespace, invoking
   specific optimizations along the way.  */

void
gfc_optimize_namespace (gfc_namespace * ns)
{
  optimize_code (ns->code);
}


static void
optimize_code (gfc_code *c)
{
  for (; c; c = c->next)
    optimize_code_node (c);
}


/* Do the optimizations for assignments.  */

static void
optimize_code_node (gfc_code *c)
{

  gfc_forall_iterator *fa;
  gfc_code *d;
  gfc_alloc *a;

  switch (c->op)
    {
    case EXEC_ASSIGN:
      optimize_assignment (c);
      break;

    case EXEC_CALL:
    case EXEC_ASSIGN_CALL:
    case EXEC_CALL_PPC:
      optimize_actual_arglist (c->ext.actual);
      break;

    case EXEC_ARITHMETIC_IF:
      optimize_expr_0 (c->expr1);
      break;

    case EXEC_PAUSE:
    case EXEC_RETURN:
    case EXEC_ERROR_STOP:
    case EXEC_STOP:
    case EXEC_COMPCALL:
      optimize_expr_0 (c->expr1);
      break;

    case EXEC_SYNC_ALL:
    case EXEC_SYNC_MEMORY:
    case EXEC_SYNC_IMAGES:
      optimize_expr_0 (c->expr2);
      break;

    case EXEC_IF:
      d = c->block;
      optimize_expr_0 (d->expr1);
      optimize_code (d->next);

      for (d = d->block; d; d = d->block)
	{
	  optimize_expr_0 (d->expr1);

	  optimize_code (d->next);
	}


      break;

    case EXEC_SELECT:
      d = c->block;

      optimize_expr_0 (c->expr1);

      for (; d; d = d->block)
	optimize_code (d->next);

      break;

    case EXEC_WHERE:
      d = c->block;
      optimize_expr_0 (d->expr1);
      optimize_code (d->next);

      for (d = d->block; d; d = d->block)
	{
	  optimize_expr_0 (d->expr1);
	  optimize_code (d->next);
	}
      break;

    case EXEC_FORALL:

      for (fa = c->ext.forall_iterator; fa; fa = fa->next)
	{
	  optimize_expr_0 (fa->start);
	  optimize_expr_0 (fa->end);
	  optimize_expr_0 (fa->stride);
	}

      if (c->expr1 != NULL)
	  optimize_expr_0 (c->expr1);

      optimize_code (c->block->next);

      break;

    case EXEC_CRITICAL:
      optimize_code (c->block->next);
      break;

    case EXEC_DO:
      optimize_expr_0 (c->ext.iterator->start);
      optimize_expr_0 (c->ext.iterator->end);
      optimize_expr_0 (c->ext.iterator->step);
      optimize_code (c->block->next);

      break;

    case EXEC_DO_WHILE:
      optimize_expr_0 (c->expr1);
      optimize_code (c->block->next);
      break;


    case EXEC_ALLOCATE:
      for (a = c->ext.alloc.list; a; a = a->next)
	  optimize_expr_0 (a->expr);
      break;

      /* Todo:  Some of these may need to be optimized, as well.  */
    case EXEC_WRITE:
    case EXEC_READ:
    case EXEC_OPEN:
    case EXEC_INQUIRE:
    case EXEC_REWIND:
    case EXEC_ENDFILE:
    case EXEC_BACKSPACE:
    case EXEC_CLOSE:
    case EXEC_WAIT:
    case EXEC_TRANSFER:
    case EXEC_FLUSH:
    case EXEC_IOLENGTH:
    case EXEC_END_PROCEDURE:
    case EXEC_NOP:
    case EXEC_CONTINUE:
    case EXEC_ENTRY:
    case EXEC_INIT_ASSIGN:
    case EXEC_LABEL_ASSIGN:
    case EXEC_POINTER_ASSIGN:
    case EXEC_GOTO:
    case EXEC_CYCLE:
    case EXEC_EXIT:
    case EXEC_BLOCK:
    case EXEC_END_BLOCK:
    case EXEC_OMP_ATOMIC:
    case EXEC_OMP_BARRIER:
    case EXEC_OMP_CRITICAL:
    case EXEC_OMP_FLUSH:
    case EXEC_OMP_DO:
    case EXEC_OMP_MASTER:
    case EXEC_OMP_ORDERED:
    case EXEC_OMP_PARALLEL:
    case EXEC_OMP_PARALLEL_DO:
    case EXEC_OMP_PARALLEL_SECTIONS:
    case EXEC_OMP_PARALLEL_WORKSHARE:
    case EXEC_OMP_SECTIONS:
    case EXEC_OMP_SINGLE:
    case EXEC_OMP_TASK:
    case EXEC_OMP_TASKWAIT:
    case EXEC_OMP_WORKSHARE:
    case EXEC_DEALLOCATE:
      
      break;

    default:
      gcc_unreachable ();

    }
}

static void
optimize_assignment (gfc_code * c)
{
  gfc_expr *lhs, *rhs;

  lhs = c->expr1;
  rhs = c->expr2;

  /* Optimize away a = trim(b), where a is a character variable.  */

  if (lhs->ts.type == BT_CHARACTER)
    {
      if (rhs->expr_type == EXPR_FUNCTION &&
	  rhs->value.function.isym &&
	  rhs->value.function.isym->id == GFC_ISYM_TRIM)
	{
	  strip_function_call (rhs);
	  optimize_assignment (c);
	  return;
	}
    }

  /* All direct optimizations have been done.  Now it's time
     to optimize the rhs.  */

  optimize_expr_0 (rhs);
}


/* Remove an unneeded function call, modifying the expression.
   This replaces the function call with the value of its
   first argument.  The rest of the argument list is freed.  */

static void
strip_function_call (gfc_expr *e)
{
  gfc_expr *e1;
  gfc_actual_arglist *a;

  a = e->value.function.actual;

  /* We should have at least one argument.  */
  gcc_assert (a->expr != NULL);

  e1 = a->expr;

  /* Free the remaining arglist, if any.  */
  if (a->next)
    gfc_free_actual_arglist (a->next);

  /* Graft the argument expression onto the original function.  */
  *e = *e1;
  gfc_free (e1);

}

/* Top-level optimization of expressions.  Calls gfc_simplify_expr if
   optimize_expr succeeds in doing something.
   TODO: Optimization of multiple function occurrence to come here.  */

static void
optimize_expr_0 (gfc_expr * e)
{
  if (optimize_expr (e))
    gfc_simplify_expr (e, 0);

  return;
}

/* Recursive optimization of expressions.
 TODO:  Make this handle many more things.  */

static bool
optimize_expr (gfc_expr *e)
{
  bool ret;

  if (e == NULL)
    return false;

  ret = false;

  switch (e->expr_type)
    {
    case EXPR_OP:
      return optimize_op (e);
      break;

    case EXPR_FUNCTION:
      optimize_actual_arglist (e->value.function.actual);
      break;

    default:
      break;
    }

  return ret;
}

/* Recursive optimization of operators.  */

static bool
optimize_op (gfc_expr *e)
{

  gfc_intrinsic_op op;

  op = e->value.op.op;

  switch (op)
    {
    case INTRINSIC_EQ:
    case INTRINSIC_EQ_OS:
    case INTRINSIC_GE:
    case INTRINSIC_GE_OS:
    case INTRINSIC_LE:
    case INTRINSIC_LE_OS:
      return optimize_equality (e, true);
      break;

    case INTRINSIC_NE:
    case INTRINSIC_NE_OS:
    case INTRINSIC_GT:
    case INTRINSIC_GT_OS:
    case INTRINSIC_LT:
    case INTRINSIC_LT_OS:
      return optimize_equality (e, false);
      break;

    default:
      break;
    }

  return false;
}

/* Optimize expressions for equality.  */

static bool
optimize_equality (gfc_expr *e, bool equal)
{

  gfc_expr *op1, *op2;
  bool change;

  op1 = e->value.op.op1;
  op2 = e->value.op.op2;

  /* Strip off unneeded TRIM calls from string comparisons.  */

  change = false;

  if (op1->expr_type == EXPR_FUNCTION 
      && op1->value.function.isym
      && op1->value.function.isym->id == GFC_ISYM_TRIM)
    {
      strip_function_call (op1);
      change = true;
    }

  if (op2->expr_type == EXPR_FUNCTION 
      && op2->value.function.isym
      && op2->value.function.isym->id == GFC_ISYM_TRIM)
    {
      strip_function_call (op2);
      change = true;
    }

  if (change)
    {
      optimize_equality (e, equal);
      return true;
    }

  /* Check for direct comparison between identical variables.
     TODO: Handle cases with identical refs.  */
  if (op1->expr_type == EXPR_VARIABLE
      && op2->expr_type == EXPR_VARIABLE
      && op1->symtree == op2->symtree
      && op1->ref == NULL && op2->ref == NULL
      && op1->ts.type != BT_REAL && op2->ts.type != BT_REAL
      && op1->ts.type != BT_COMPLEX && op2->ts.type !=BT_COMPLEX)
    {
      /* Replace the expression by a constant expression.  The typespec
	 and where remains the way it is.  */
      gfc_free (op1);
      gfc_free (op2);
      e->expr_type = EXPR_CONSTANT;
      e->value.logical = equal;
      return true;
    }
  return false;
}

/* Optimize a call list.  Right now, this just goes through the actual
   arg list and optimizes each expression in turn.  */

static void
optimize_actual_arglist (gfc_actual_arglist *a)
{

  for (; a; a = a->next)
    {
      if (a->expr != NULL)
	optimize_expr_0 (a->expr);
    }
  
  return;
}

[-- Attachment #3: opt-1.diff --]
[-- Type: text/x-patch, Size: 1230 bytes --]

Index: Make-lang.in
===================================================================
--- Make-lang.in	(Revision 161930)
+++ Make-lang.in	(Arbeitskopie)
@@ -66,7 +66,7 @@
     fortran/trans.o fortran/trans-array.o fortran/trans-common.o \
     fortran/trans-const.o fortran/trans-decl.o fortran/trans-expr.o \
     fortran/trans-intrinsic.o fortran/trans-io.o fortran/trans-openmp.o \
-    fortran/trans-stmt.o fortran/trans-types.o
+    fortran/trans-stmt.o fortran/trans-types.o fortran/optimize.o
 
 fortran_OBJS = $(F95_OBJS) gfortranspec.o
 
Index: gfortran.h
===================================================================
--- gfortran.h	(Revision 161930)
+++ gfortran.h	(Arbeitskopie)
@@ -2828,4 +2828,8 @@
 
 #define CLASS_DATA(sym) sym->ts.u.derived->components
 
+/* optimize.c */
+
+void gfc_optimize_namespace (gfc_namespace *);
+
 #endif /* GCC_GFORTRAN_H  */
Index: trans-decl.c
===================================================================
--- trans-decl.c	(Revision 161930)
+++ trans-decl.c	(Arbeitskopie)
@@ -4374,6 +4374,9 @@
   int rank;
   bool is_recursive;
 
+  if (optimize)
+    gfc_optimize_namespace (ns);
+
   sym = ns->proc_name;
 
   /* Check that the frontend isn't still using this.  */

[-- Attachment #4: character_comparison_1.f90 --]
[-- Type: text/x-fortran, Size: 825 bytes --]

! { dg-do run }
! { dg-options "-O -fdump-tree-original" }
program main
  implicit none
  character(len=4) :: c
  integer :: n
  integer :: i
  common /foo/ i

  n = 0
  i = 0
  c = 'abcd'
  n = n + 1 ; if (c == c) call yes
  n = n + 1 ; if (c >= c) call yes
  n = n + 1 ; if (c <= c) call yes
  n = n + 1 ; if (c .eq. c) call yes
  n = n + 1 ; if (c .ge. c) call yes
  n = n + 1 ; if (c .le. c) call yes
  if (c /= c) call abort
  if (c > c) call abort
  if (c < c) call abort
  if (c .ne. c) call abort
  if (c .gt. c) call abort
  if (c .lt. c) call abort
  if (n /= i) call abort
end program main

subroutine yes
  implicit none
  common /foo/ i
  integer :: i
  i = i + 1
end subroutine yes

! { dg-final { scan-tree-dump-times "gfortran_compare_string" 0 "original" } }
! { dg-final { cleanup-tree-dump "original" } }


[-- Attachment #5: trim_optimize_1.f90 --]
[-- Type: text/x-fortran, Size: 410 bytes --]

! { dg-do run }
! { dg-options "-O -fdump-tree-original" }
! PR 40628 - optimize unnecessary TRIMs on assignment
program main
  character(len=3) :: a
  character(len=4) :: b,c
  b = 'abcd'
  a = trim(b)
  c = trim(trim(a))
  if (a /= 'abc') call abort
  if (c /= 'abc') call abort
end program main

! { dg-final { scan-tree-dump-times "memmove" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-17 18:38 [patch, fortran] PR 40628, front-end optimization pass Thomas Koenig
@ 2010-07-18  8:41 ` Daniel Kraft
  2010-07-18 10:18   ` Thomas Koenig
  2010-07-19  4:12   ` Jerry DeLisle
  0 siblings, 2 replies; 22+ messages in thread
From: Daniel Kraft @ 2010-07-18  8:41 UTC (permalink / raw)
  To: Thomas Koenig; +Cc: fortran, gcc-patches

Hi Thomas,

Thomas Koenig wrote:
> finally, here's the first attempt at a front-end optimization pass.
> Right now, it fixes PR 40626 and optimizes comparisons between variables
> (which only really is relevant for character comparisons).  Many more
> things could (and should) be added over time.

thinking about this, I'm not really convinced that we want "front-end 
optimization passes".  At least for heavier optimization, at least 
conceptually the middle-end should be responsible.  And for smaller ones 
that are Fortran-specific, we already have the "simplify" code-path.  So 
what do you think are appropriate use-cases for your new optimization pass?

On the other hand, I like the idea of a general high-level 
pass-framework.  I think that this could help in implementing F2003 
features (and co), because I'm not sure the current handling during 
resolution is the best and cleanest (at least not for all constructs). 
I would have liked to add some construct lowering as seperate passes in 
the past, so that it does not interfere with real resolution.

What do you (and others) think about introducing your patch as a general 
pass-framework (and probably not calling it "optimization"), which could 
then both handle construct implementations as well as certain 
optimization passes (if it seems reasonable to implement them that way)?

Yours,
Daniel

-- 
http://www.pro-vegan.info/
--
Done:  Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-18  8:41 ` Daniel Kraft
@ 2010-07-18 10:18   ` Thomas Koenig
  2010-07-19 18:59     ` Toon Moene
  2010-07-19  4:12   ` Jerry DeLisle
  1 sibling, 1 reply; 22+ messages in thread
From: Thomas Koenig @ 2010-07-18 10:18 UTC (permalink / raw)
  To: Daniel Kraft; +Cc: fortran, gcc-patches

Hi Daniel.

> Hi Thomas,
> 
> Thomas Koenig wrote:
> > finally, here's the first attempt at a front-end optimization pass.
> > Right now, it fixes PR 40626 and optimizes comparisons between variables
> > (which only really is relevant for character comparisons).  Many more
> > things could (and should) be added over time.
> 
> thinking about this, I'm not really convinced that we want "front-end 
> optimization passes".  At least for heavier optimization, at least 
> conceptually the middle-end should be responsible.

There are things which are hard for the middle-end to do, especially
character and array expressions.  See, for example, PR 22572 (double
occurrence of matmul not optimized).

> And for smaller ones 
> that are Fortran-specific, we already have the "simplify" code-path.

Simplify is very much geared toward constant simplification.  I made
some attempt at optimization, only to find I would have to modify large
chunks, leading to unnecessary and error-prone changes.

Also, in simplify.c, removing whole statements, adding new variables
etc. is not forseen, also leading to large changes.

Adding a new pass seamed cleaner.  I also wanted the possibility of
making the front-end optimizations

> So 
> what do you think are appropriate use-cases for your new optimization pass?

Things like PR 22572, optimizing expressions like f(x) + f(x) (and warning about
cases where f(x) is non-PURE), optimizing string assignments, PR 30609, ...
A lot of cases where a programmer might be tempted to write "lazy" code
that is currently sub-optimally translated.

> On the other hand, I like the idea of a general high-level 
> pass-framework.  I think that this could help in implementing F2003 
> features (and co), because I'm not sure the current handling during 
> resolution is the best and cleanest (at least not for all constructs). 
> I would have liked to add some construct lowering as seperate passes in 
> the past, so that it does not interfere with real resolution.

That also makes sense.

> What do you (and others) think about introducing your patch as a general 
> pass-framework (and probably not calling it "optimization"), which could 
> then both handle construct implementations as well as certain 
> optimization passes (if it seems reasonable to implement them that way)?

We can use my pass as a starting point, certainly.  Currently, my patch
is run after resolution, but we could certainly set up a general pass
management system.

	Thomas


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-18  8:41 ` Daniel Kraft
  2010-07-18 10:18   ` Thomas Koenig
@ 2010-07-19  4:12   ` Jerry DeLisle
  2010-07-19 18:21     ` Richard Henderson
                       ` (2 more replies)
  1 sibling, 3 replies; 22+ messages in thread
From: Jerry DeLisle @ 2010-07-19  4:12 UTC (permalink / raw)
  To: Daniel Kraft; +Cc: Thomas Koenig, fortran, gcc-patches

On 07/18/2010 01:46 AM, Daniel Kraft wrote:
> Hi Thomas,
>
> Thomas Koenig wrote:
>> finally, here's the first attempt at a front-end optimization pass.
>> Right now, it fixes PR 40626 and optimizes comparisons between variables
>> (which only really is relevant for character comparisons). Many more
>> things could (and should) be added over time.
>

I like the idea as long as we do not duplicate middle-end work. If we can 
improve performance without sacrificing maintainability and correctness, I am 
all for it.  The idea of general passes is good.  Rather than optimize.c maybe 
call it early_pass.c or whatever.

Do any middle-end maintainers have an opinion on adding this optimization?

Jerry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-19  4:12   ` Jerry DeLisle
@ 2010-07-19 18:21     ` Richard Henderson
  2010-07-19 19:06     ` Jakub Jelinek
  2010-07-19 22:31     ` Thomas Koenig
  2 siblings, 0 replies; 22+ messages in thread
From: Richard Henderson @ 2010-07-19 18:21 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Daniel Kraft, Thomas Koenig, fortran, gcc-patches

On 07/18/2010 09:11 PM, Jerry DeLisle wrote:
> On 07/18/2010 01:46 AM, Daniel Kraft wrote:
>> Hi Thomas,
>>
>> Thomas Koenig wrote:
>>> finally, here's the first attempt at a front-end optimization pass.
>>> Right now, it fixes PR 40626 and optimizes comparisons between variables
>>> (which only really is relevant for character comparisons). Many more
>>> things could (and should) be added over time.
>>
> 
> I like the idea as long as we do not duplicate middle-end work. If we
> can improve performance without sacrificing maintainability and
> correctness, I am all for it.  The idea of general passes is good. 
> Rather than optimize.c maybe call it early_pass.c or whatever.
> 
> Do any middle-end maintainers have an opinion on adding this optimization?

As long as the optimizations here are fortran-specific (e.g. high-level
matrix, string, or loop pre-expansion optimizations), I don't mind.


r~

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-18 10:18   ` Thomas Koenig
@ 2010-07-19 18:59     ` Toon Moene
  2010-07-19 19:11       ` Thomas Koenig
  0 siblings, 1 reply; 22+ messages in thread
From: Toon Moene @ 2010-07-19 18:59 UTC (permalink / raw)
  To: Thomas Koenig; +Cc: Daniel Kraft, fortran, gcc-patches

Thomas Koenig wrote:

> Hi Daniel.
> 
>> Hi Thomas,
>>
>> Thomas Koenig wrote:
>>> finally, here's the first attempt at a front-end optimization pass.
>>> Right now, it fixes PR 40626 

I have the feeling this isn't the right bug number - because it was 
already closed a year ago.

Which one do you mean ?

[ BTW, as I showed in my GCC-Summit talk in 2007, we already perform
   Fortran specific optimizations in the Front End, so it would be rather
   silly to oppose them from a middle-end perspective :-) ]

-- 
Toon Moene - e-mail: toon@moene.org - phone: +31 346 214290
Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands
At home: http://moene.org/~toon/; weather: http://moene.org/~hirlam/
Progress of GNU Fortran: http://gcc.gnu.org/gcc-4.5/changes.html#Fortran

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-19  4:12   ` Jerry DeLisle
  2010-07-19 18:21     ` Richard Henderson
@ 2010-07-19 19:06     ` Jakub Jelinek
  2010-07-19 22:31     ` Thomas Koenig
  2 siblings, 0 replies; 22+ messages in thread
From: Jakub Jelinek @ 2010-07-19 19:06 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Daniel Kraft, Thomas Koenig, fortran, gcc-patches

On Sun, Jul 18, 2010 at 09:11:38PM -0700, Jerry DeLisle wrote:
> On 07/18/2010 01:46 AM, Daniel Kraft wrote:
> >Hi Thomas,
> >
> >Thomas Koenig wrote:
> >>finally, here's the first attempt at a front-end optimization pass.
> >>Right now, it fixes PR 40626 and optimizes comparisons between variables
> >>(which only really is relevant for character comparisons). Many more
> >>things could (and should) be added over time.
> >
> 
> I like the idea as long as we do not duplicate middle-end work. If
> we can improve performance without sacrificing maintainability and
> correctness, I am all for it.  The idea of general passes is good.
> Rather than optimize.c maybe call it early_pass.c or whatever.

What I think would be very useful to do in -fwhole-file mode do a pass
through the front-end trees and improve using that slightly e.g.
dependency.c stuff (unless we jump to middle-end arrays, that's an easy way
to get rid e.g. of unnecessary array temporaries).  E.g. in tonto POINTER
vars are ALLOCATED in one routine and not changed afterwards, such vars
could be handled like allocatables.

	Jakub

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-19 18:59     ` Toon Moene
@ 2010-07-19 19:11       ` Thomas Koenig
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Koenig @ 2010-07-19 19:11 UTC (permalink / raw)
  To: Toon Moene; +Cc: Daniel Kraft, fortran, gcc-patches

Am Montag, den 19.07.2010, 20:59 +0200 schrieb Toon Moene:
> Thomas Koenig wrote:
> 
> > Hi Daniel.
> > 
> >> Hi Thomas,
> >>
> >> Thomas Koenig wrote:
> >>> finally, here's the first attempt at a front-end optimization
> pass.
> >>> Right now, it fixes PR 40626 
> 
> I have the feeling this isn't the right bug number - because it was 
> already closed a year ago.

I meant PR 40628, optimizing TRIM away (I got it right in the Subject
line).

	Thomas

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-19  4:12   ` Jerry DeLisle
  2010-07-19 18:21     ` Richard Henderson
  2010-07-19 19:06     ` Jakub Jelinek
@ 2010-07-19 22:31     ` Thomas Koenig
  2010-07-20  1:19       ` Jerry DeLisle
  2 siblings, 1 reply; 22+ messages in thread
From: Thomas Koenig @ 2010-07-19 22:31 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Daniel Kraft, fortran, gcc-patches

Hi Jerry,
> On 07/18/2010 01:46 AM, Daniel Kraft wrote:
> > Hi Thomas,
> >
> > Thomas Koenig wrote:
> >> finally, here's the first attempt at a front-end optimization pass.
> >> Right now, it fixes PR 40626 and optimizes comparisons between variables
> >> (which only really is relevant for character comparisons). Many more
> >> things could (and should) be added over time.
> >
> 
> I like the idea as long as we do not duplicate middle-end work. If we can 
> improve performance without sacrificing maintainability and correctness, I am 
> all for it.  The idea of general passes is good.  Rather than optimize.c maybe 
> call it early_pass.c or whatever.

So, how do we proceed?

I could set up a general pass framework.  This have structs of
containing pointers to functions which handle assignments,
expressions, operators and actual arglists, one for each pass,
and a routine for walking the expressions and invoking the correct
functions.

This would mean one file passes.c (which contains the handle_code and
handle_code_node functions), a passes.h header and a single file (e.g.
pass-optimize.c) for each pass containing the individual functions.

This sounds doable, but will take a bit of time.

Further comments?

Thomas

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-19 22:31     ` Thomas Koenig
@ 2010-07-20  1:19       ` Jerry DeLisle
  2010-07-20  2:08         ` Steve Kargl
                           ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Jerry DeLisle @ 2010-07-20  1:19 UTC (permalink / raw)
  To: Thomas Koenig; +Cc: Daniel Kraft, fortran, gcc-patches

On 07/19/2010 03:31 PM, Thomas Koenig wrote:
> Hi Jerry,
>> On 07/18/2010 01:46 AM, Daniel Kraft wrote:
>>> Hi Thomas,
>>>
>>> Thomas Koenig wrote:
>>>> finally, here's the first attempt at a front-end optimization pass.
>>>> Right now, it fixes PR 40626 and optimizes comparisons between variables
>>>> (which only really is relevant for character comparisons). Many more
>>>> things could (and should) be added over time.
>>>
>>
>> I like the idea as long as we do not duplicate middle-end work. If we can
>> improve performance without sacrificing maintainability and correctness, I am
>> all for it.  The idea of general passes is good.  Rather than optimize.c maybe
>> call it early_pass.c or whatever.
>
> So, how do we proceed?
>
> I could set up a general pass framework.  This have structs of
> containing pointers to functions which handle assignments,
> expressions, operators and actual arglists, one for each pass,
> and a routine for walking the expressions and invoking the correct
> functions.
>
> This would mean one file passes.c (which contains the handle_code and
> handle_code_node functions), a passes.h header and a single file (e.g.
> pass-optimize.c) for each pass containing the individual functions.
>
> This sounds doable, but will take a bit of time.
>
> Further comments?
>
> Thomas
>
>

Why not start by just changing the filename optimize.c to passes.c and go with 
what you have now, then this can evolve further with time.

One thing I would like to suggest is can you identify a real world application 
that benefits from this initial optimization pass?  Proof in the pudding so to 
speak, but not strictly necessary.  I am more curious then anything.

Jerry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  1:19       ` Jerry DeLisle
@ 2010-07-20  2:08         ` Steve Kargl
  2010-07-20  2:39         ` Diego Novillo
  2010-07-20  8:05         ` Tobias Burnus
  2 siblings, 0 replies; 22+ messages in thread
From: Steve Kargl @ 2010-07-20  2:08 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Thomas Koenig, Daniel Kraft, fortran, gcc-patches

On Mon, Jul 19, 2010 at 06:19:32PM -0700, Jerry DeLisle wrote:
> 
> One thing I would like to suggest is can you identify a real world 
> application that benefits from this initial optimization pass?  Proof in 
> the pudding so to speak, but not strictly necessary.  I am more curious 
> then anything.
> 

See Thomas's recent c.l.f post.

module foo
  implicit none
  integer :: n = 0
contains
  integer function f(k)
    integer, intent(in) :: k
    f = k
    n = n + 1
  end function f
end module foo

program main
  use foo
  implicit none
  print *,f(3) + f(3)
  print *,n
end program main 

An optimizer can replace the 2 function calls in the print 
statement to 'print *, 2*f(3)'.  If the optimizer is really
smart, it can replace it by 'print *, 6'.  The question
then becomes what does 'print *, n' print?  The answer is
that it can print 0, 1, 2, or some other value.  The thread
has been quite interesting.

-- 
Steve

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  1:19       ` Jerry DeLisle
  2010-07-20  2:08         ` Steve Kargl
@ 2010-07-20  2:39         ` Diego Novillo
  2010-07-20  2:54           ` Jerry DeLisle
  2010-07-20  8:05         ` Tobias Burnus
  2 siblings, 1 reply; 22+ messages in thread
From: Diego Novillo @ 2010-07-20  2:39 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Thomas Koenig, Daniel Kraft, fortran, gcc-patches

On 10-07-19 21:19 , Jerry DeLisle wrote:

> Why not start by just changing the filename optimize.c to passes.c and
> go with what you have now, then this can evolve further with time.
>
> One thing I would like to suggest is can you identify a real world
> application that benefits from this initial optimization pass? Proof in
> the pudding so to speak, but not strictly necessary. I am more curious
> then anything.

Just so I don't get confused, y'all are talking about adding a general 
pass framework to the fortran FE files, right?

One thing you may want to consider is see how much of the existing pass 
manager framework can be made to share with fortran/*.


Diego.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  2:39         ` Diego Novillo
@ 2010-07-20  2:54           ` Jerry DeLisle
  0 siblings, 0 replies; 22+ messages in thread
From: Jerry DeLisle @ 2010-07-20  2:54 UTC (permalink / raw)
  To: Diego Novillo; +Cc: Thomas Koenig, Daniel Kraft, fortran, gcc-patches

On 07/19/2010 07:39 PM, Diego Novillo wrote:
> On 10-07-19 21:19 , Jerry DeLisle wrote:
>
>> Why not start by just changing the filename optimize.c to passes.c and
>> go with what you have now, then this can evolve further with time.
>>
>> One thing I would like to suggest is can you identify a real world
>> application that benefits from this initial optimization pass? Proof in
>> the pudding so to speak, but not strictly necessary. I am more curious
>> then anything.
>
> Just so I don't get confused, y'all are talking about adding a general
> pass framework to the fortran FE files, right?
>

Right!

Jerry

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  1:19       ` Jerry DeLisle
  2010-07-20  2:08         ` Steve Kargl
  2010-07-20  2:39         ` Diego Novillo
@ 2010-07-20  8:05         ` Tobias Burnus
  2010-07-20  8:21           ` Daniel Kraft
  2 siblings, 1 reply; 22+ messages in thread
From: Tobias Burnus @ 2010-07-20  8:05 UTC (permalink / raw)
  To: Jerry DeLisle; +Cc: Thomas Koenig, Daniel Kraft, fortran, gcc-patches

On 07/20/2010 03:19 AM, Jerry DeLisle wrote:
>>>> Thomas Koenig wrote:
>>>>> finally, here's the first attempt at a front-end optimization pass.
>>>>> Right now, it fixes PR 40626 and optimizes comparisons between
>>>>> variables
>>>>> (which only really is relevant for character comparisons). Many more
>>>>> things could (and should) be added over time.
> Why not start by just changing the filename optimize.c to passes.c and
> go with what you have now, then this can evolve further with time.

I concur and I like Jakub's idea. In general, avoiding function calls
(e.g. TRIM()) and avoiding the generation of temporaries helps a lot as
the ME has difficulties to optimize those way while the FE knows the
language constraints and has a more high-level view which facilitates
certain optimizations.

> One thing I would like to suggest is can you identify a real world
> application that benefits from this initial optimization pass?  Proof
> in the pudding so to speak, but not strictly necessary.  I am more
> curious then anything.

That the such code exists and that a real-world spends quite some time
with trim can be seen at the link of the PR. For many Fortran program,
it probably does not help much as the string processing part is small
(though if you go to 10000s of processes, a single-process config read
starts to matter), but in some cases (like memory tracing in this
example), it can matter a lot.

In case of the real-code program linked in the PR, "TRIM(a) == TRIM(b)"
was changed to "a == b" and the commit log was:

" I think I solved the performance hit when running profiling in memory.
The problem is that trim was being called 8 million times for the c60
test, while not being really necessary. So I got rid of it. Now trim is
only called 200 000 times ;)"

Cf. http://www.tddft.org/trac/octopus/changeset/5672  (octopus is an
electronic structure calculation program available under the GPL from
http://tddft.org/ )

Tobias

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  8:05         ` Tobias Burnus
@ 2010-07-20  8:21           ` Daniel Kraft
  2010-07-20  9:44             ` Toon Moene
  0 siblings, 1 reply; 22+ messages in thread
From: Daniel Kraft @ 2010-07-20  8:21 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: Jerry DeLisle, Thomas Koenig, fortran, gcc-patches

Tobias Burnus wrote:
> On 07/20/2010 03:19 AM, Jerry DeLisle wrote:
>>>>> Thomas Koenig wrote:
>>>>>> finally, here's the first attempt at a front-end optimization pass.
>>>>>> Right now, it fixes PR 40626 and optimizes comparisons between
>>>>>> variables
>>>>>> (which only really is relevant for character comparisons). Many more
>>>>>> things could (and should) be added over time.
>> Why not start by just changing the filename optimize.c to passes.c and
>> go with what you have now, then this can evolve further with time.
> 
> I concur and I like Jakub's idea. In general, avoiding function calls
> (e.g. TRIM()) and avoiding the generation of temporaries helps a lot as
> the ME has difficulties to optimize those way while the FE knows the
> language constraints and has a more high-level view which facilitates
> certain optimizations.

I just wonder if there is not yet any way to tell the middle-end that it 
is allowed to optimize function calls away (like marking the functions 
"pure" -- according to the c.l.f thread, this should be allowed for all 
Fortran functions (if I understood it correctly)).

I guess this is in principle something Fortran specific right now, but 
the general concept does not seem that specific to me (although it is 
not applicable to C or C++, I guess).

Yours,
Daniel

-- 
http://www.pro-vegan.info/
--
Done:  Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz
To go: Hea-Kni-Mon-Pri

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  8:21           ` Daniel Kraft
@ 2010-07-20  9:44             ` Toon Moene
  2010-07-20  9:58               ` Richard Guenther
  0 siblings, 1 reply; 22+ messages in thread
From: Toon Moene @ 2010-07-20  9:44 UTC (permalink / raw)
  To: Daniel Kraft
  Cc: Tobias Burnus, Jerry DeLisle, Thomas Koenig, fortran, gcc-patches

Daniel Kraft wrote:

> I just wonder if there is not yet any way to tell the middle-end that it 
> is allowed to optimize function calls away (like marking the functions 
> "pure" -- according to the c.l.f thread, this should be allowed for all 
> Fortran functions (if I understood it correctly)).

No, that's not sufficient, as I argued in my 2007 GCC Summit paper (see 
paragraph 6.3 - you also have to get rid of the temporaries that are 
allocated to hold the function results, which can be quite large (i.e., 
when eliding MATMUL calls).

It is hard to see how the middle end could do this.

-- 
Toon Moene - e-mail: toon@moene.org - phone: +31 346 214290
Saturnushof 14, 3738 XG  Maartensdijk, The Netherlands
At home: http://moene.org/~toon/; weather: http://moene.org/~hirlam/
Progress of GNU Fortran: http://gcc.gnu.org/gcc-4.5/changes.html#Fortran

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  9:44             ` Toon Moene
@ 2010-07-20  9:58               ` Richard Guenther
  2010-07-20 22:01                 ` Thomas Koenig
  0 siblings, 1 reply; 22+ messages in thread
From: Richard Guenther @ 2010-07-20  9:58 UTC (permalink / raw)
  To: Toon Moene
  Cc: Daniel Kraft, Tobias Burnus, Jerry DeLisle, Thomas Koenig,
	fortran, gcc-patches

On Tue, Jul 20, 2010 at 11:44 AM, Toon Moene <toon@moene.org> wrote:
> Daniel Kraft wrote:
>
>> I just wonder if there is not yet any way to tell the middle-end that it
>> is allowed to optimize function calls away (like marking the functions
>> "pure" -- according to the c.l.f thread, this should be allowed for all
>> Fortran functions (if I understood it correctly)).
>
> No, that's not sufficient, as I argued in my 2007 GCC Summit paper (see
> paragraph 6.3 - you also have to get rid of the temporaries that are
> allocated to hold the function results, which can be quite large (i.e., when
> eliding MATMUL calls).
>
> It is hard to see how the middle end could do this.

It generally can't if it doesn't know that MATMUL is MATMUL.
Middle-end arrays would help, but they keep being below the top
of my TODO list ;)

Richard.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20  9:58               ` Richard Guenther
@ 2010-07-20 22:01                 ` Thomas Koenig
  2010-07-25 15:52                   ` Tobias Burnus
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Koenig @ 2010-07-20 22:01 UTC (permalink / raw)
  To: fortran; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 769 bytes --]

Well, here is an updated version of the patch.

I have called the new file (mostly unchanged) frontend-passes.c, because
my gdb gets confused about having two files called passes.c.

I have also changed the place where the gfc_run_passes is called to
resolve.c, as pault had suggested on IRC.

Regression-tested, only allocate_with_typespec.f90 failed (which I also
saw on gcc-testresults).

OK?

	Thomas


2010-07-20  Thomas Koenig  <tkoenig@gcc.gnu.org>

	* Make-lang.in:  Add fortran/frontend-passes.o.
	* gfortran.h:  Add prototype for gfc_run_passes.
	* resolve.c (gfc_resolve):  Call gfc_run_passes.
	* frontend-passes.c:  New file.

2010-0717  Thomas Koenig  <tkoenig@gcc.gnu.org>

	* trim_optimize_1.f90:  New test.
	* character_comparision_1.f90:  New test.
 

[-- Attachment #2: opt-2.diff --]
[-- Type: text/x-patch, Size: 1150 bytes --]

Index: Make-lang.in
===================================================================
--- Make-lang.in	(Revision 162346)
+++ Make-lang.in	(Arbeitskopie)
@@ -66,7 +66,7 @@
     fortran/trans.o fortran/trans-array.o fortran/trans-common.o \
     fortran/trans-const.o fortran/trans-decl.o fortran/trans-expr.o \
     fortran/trans-intrinsic.o fortran/trans-io.o fortran/trans-openmp.o \
-    fortran/trans-stmt.o fortran/trans-types.o
+    fortran/trans-stmt.o fortran/trans-types.o fortran/frontend-passes.o
 
 fortran_OBJS = $(F95_OBJS) gfortranspec.o
 
Index: gfortran.h
===================================================================
--- gfortran.h	(Revision 162346)
+++ gfortran.h	(Arbeitskopie)
@@ -2831,4 +2831,8 @@
 
 #define CLASS_DATA(sym) sym->ts.u.derived->components
 
+/* passes.c */
+
+void gfc_run_passes (gfc_namespace *);
+
 #endif /* GCC_GFORTRAN_H  */
Index: resolve.c
===================================================================
--- resolve.c	(Revision 162346)
+++ resolve.c	(Arbeitskopie)
@@ -13068,4 +13068,6 @@
   gfc_current_ns = old_ns;
   cs_base = old_cs_base;
   ns->resolved = 1;
+
+  gfc_run_passes (ns);
 }

[-- Attachment #3: trim_optimize_1.f90 --]
[-- Type: text/x-fortran, Size: 410 bytes --]

! { dg-do run }
! { dg-options "-O -fdump-tree-original" }
! PR 40628 - optimize unnecessary TRIMs on assignment
program main
  character(len=3) :: a
  character(len=4) :: b,c
  b = 'abcd'
  a = trim(b)
  c = trim(trim(a))
  if (a /= 'abc') call abort
  if (c /= 'abc') call abort
end program main

! { dg-final { scan-tree-dump-times "memmove" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

[-- Attachment #4: character_comparison_1.f90 --]
[-- Type: text/x-fortran, Size: 825 bytes --]

! { dg-do run }
! { dg-options "-O -fdump-tree-original" }
program main
  implicit none
  character(len=4) :: c
  integer :: n
  integer :: i
  common /foo/ i

  n = 0
  i = 0
  c = 'abcd'
  n = n + 1 ; if (c == c) call yes
  n = n + 1 ; if (c >= c) call yes
  n = n + 1 ; if (c <= c) call yes
  n = n + 1 ; if (c .eq. c) call yes
  n = n + 1 ; if (c .ge. c) call yes
  n = n + 1 ; if (c .le. c) call yes
  if (c /= c) call abort
  if (c > c) call abort
  if (c < c) call abort
  if (c .ne. c) call abort
  if (c .gt. c) call abort
  if (c .lt. c) call abort
  if (n /= i) call abort
end program main

subroutine yes
  implicit none
  common /foo/ i
  integer :: i
  i = i + 1
end subroutine yes

! { dg-final { scan-tree-dump-times "gfortran_compare_string" 0 "original" } }
! { dg-final { cleanup-tree-dump "original" } }


[-- Attachment #5: frontend-passes.c --]
[-- Type: text/x-csrc, Size: 9199 bytes --]

/* Pass manager for Fortran front end.
   Copyright (C) 2010 Free Software Foundation, Inc.
   Contributed by Thomas König.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

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/>.  */

#include "config.h"
#include "system.h"
#include "gfortran.h"
#include "arith.h"
#include "flags.h"

/* Forward declarations.  */

static void strip_function_call (gfc_expr *);
static void optimize_assignment (gfc_code *);
static void optimize_expr_0 (gfc_expr *);
static bool optimize_expr (gfc_expr *);
static bool optimize_op (gfc_expr *);
static bool optimize_equality (gfc_expr *, bool);
static void optimize_code (gfc_code *);
static void optimize_code_node (gfc_code *);
static void optimize_actual_arglist (gfc_actual_arglist *);

/* Entry point - run all passes for a namespace.  So far, only an
   optimization pass is run.  */

void
gfc_run_passes (gfc_namespace * ns)
{
  if (optimize)
    optimize_code (ns->code);
}

static void
optimize_code (gfc_code *c)
{
  for (; c; c = c->next)
    optimize_code_node (c);
}


/* Do the optimizations for a code node.  */

static void
optimize_code_node (gfc_code *c)
{

  gfc_forall_iterator *fa;
  gfc_code *d;
  gfc_alloc *a;

  switch (c->op)
    {
    case EXEC_ASSIGN:
      optimize_assignment (c);
      break;

    case EXEC_CALL:
    case EXEC_ASSIGN_CALL:
    case EXEC_CALL_PPC:
      optimize_actual_arglist (c->ext.actual);
      break;

    case EXEC_ARITHMETIC_IF:
      optimize_expr_0 (c->expr1);
      break;

    case EXEC_PAUSE:
    case EXEC_RETURN:
    case EXEC_ERROR_STOP:
    case EXEC_STOP:
    case EXEC_COMPCALL:
      optimize_expr_0 (c->expr1);
      break;

    case EXEC_SYNC_ALL:
    case EXEC_SYNC_MEMORY:
    case EXEC_SYNC_IMAGES:
      optimize_expr_0 (c->expr2);
      break;

    case EXEC_IF:
      d = c->block;
      optimize_expr_0 (d->expr1);
      optimize_code (d->next);

      for (d = d->block; d; d = d->block)
	{
	  optimize_expr_0 (d->expr1);

	  optimize_code (d->next);
	}


      break;

    case EXEC_SELECT:
    case EXEC_SELECT_TYPE:
      d = c->block;

      optimize_expr_0 (c->expr1);

      for (; d; d = d->block)
	optimize_code (d->next);

      break;

    case EXEC_WHERE:
      d = c->block;
      optimize_expr_0 (d->expr1);
      optimize_code (d->next);

      for (d = d->block; d; d = d->block)
	{
	  optimize_expr_0 (d->expr1);
	  optimize_code (d->next);
	}
      break;

    case EXEC_FORALL:

      for (fa = c->ext.forall_iterator; fa; fa = fa->next)
	{
	  optimize_expr_0 (fa->start);
	  optimize_expr_0 (fa->end);
	  optimize_expr_0 (fa->stride);
	}

      if (c->expr1 != NULL)
	  optimize_expr_0 (c->expr1);

      optimize_code (c->block->next);

      break;

    case EXEC_CRITICAL:
      optimize_code (c->block->next);
      break;

    case EXEC_DO:
      optimize_expr_0 (c->ext.iterator->start);
      optimize_expr_0 (c->ext.iterator->end);
      optimize_expr_0 (c->ext.iterator->step);
      optimize_code (c->block->next);

      break;

    case EXEC_DO_WHILE:
      optimize_expr_0 (c->expr1);
      optimize_code (c->block->next);
      break;


    case EXEC_ALLOCATE:
      for (a = c->ext.alloc.list; a; a = a->next)
	  optimize_expr_0 (a->expr);
      break;

      /* Todo:  Some of these may need to be optimized, as well.  */
    case EXEC_WRITE:
    case EXEC_READ:
    case EXEC_OPEN:
    case EXEC_INQUIRE:
    case EXEC_REWIND:
    case EXEC_ENDFILE:
    case EXEC_BACKSPACE:
    case EXEC_CLOSE:
    case EXEC_WAIT:
    case EXEC_TRANSFER:
    case EXEC_FLUSH:
    case EXEC_IOLENGTH:
    case EXEC_END_PROCEDURE:
    case EXEC_NOP:
    case EXEC_CONTINUE:
    case EXEC_ENTRY:
    case EXEC_INIT_ASSIGN:
    case EXEC_LABEL_ASSIGN:
    case EXEC_POINTER_ASSIGN:
    case EXEC_GOTO:
    case EXEC_CYCLE:
    case EXEC_EXIT:
    case EXEC_BLOCK:
    case EXEC_END_BLOCK:
    case EXEC_OMP_ATOMIC:
    case EXEC_OMP_BARRIER:
    case EXEC_OMP_CRITICAL:
    case EXEC_OMP_FLUSH:
    case EXEC_OMP_DO:
    case EXEC_OMP_MASTER:
    case EXEC_OMP_ORDERED:
    case EXEC_OMP_PARALLEL:
    case EXEC_OMP_PARALLEL_DO:
    case EXEC_OMP_PARALLEL_SECTIONS:
    case EXEC_OMP_PARALLEL_WORKSHARE:
    case EXEC_OMP_SECTIONS:
    case EXEC_OMP_SINGLE:
    case EXEC_OMP_TASK:
    case EXEC_OMP_TASKWAIT:
    case EXEC_OMP_WORKSHARE:
    case EXEC_DEALLOCATE:
      
      break;

    default:
      gcc_unreachable ();

    }
}

/* Optimizations for an assignment.  */

static void
optimize_assignment (gfc_code * c)
{
  gfc_expr *lhs, *rhs;

  lhs = c->expr1;
  rhs = c->expr2;

  /* Optimize away a = trim(b), where a is a character variable.  */

  if (lhs->ts.type == BT_CHARACTER)
    {
      if (rhs->expr_type == EXPR_FUNCTION &&
	  rhs->value.function.isym &&
	  rhs->value.function.isym->id == GFC_ISYM_TRIM)
	{
	  strip_function_call (rhs);
	  optimize_assignment (c);
	  return;
	}
    }

  /* All direct optimizations have been done.  Now it's time
     to optimize the rhs.  */

  optimize_expr_0 (rhs);
}


/* Remove an unneeded function call, modifying the expression.
   This replaces the function call with the value of its
   first argument.  The rest of the argument list is freed.  */

static void
strip_function_call (gfc_expr *e)
{
  gfc_expr *e1;
  gfc_actual_arglist *a;

  a = e->value.function.actual;

  /* We should have at least one argument.  */
  gcc_assert (a->expr != NULL);

  e1 = a->expr;

  /* Free the remaining arglist, if any.  */
  if (a->next)
    gfc_free_actual_arglist (a->next);

  /* Graft the argument expression onto the original function.  */
  *e = *e1;
  gfc_free (e1);

}

/* Top-level optimization of expressions.  Calls gfc_simplify_expr if
   optimize_expr succeeds in doing something.
   TODO: Optimization of multiple function occurrence to come here.  */

static void
optimize_expr_0 (gfc_expr * e)
{
  if (optimize_expr (e))
    gfc_simplify_expr (e, 0);

  return;
}

/* Recursive optimization of expressions.
 TODO:  Make this handle many more things.  */

static bool
optimize_expr (gfc_expr *e)
{
  bool ret;

  if (e == NULL)
    return false;

  ret = false;

  switch (e->expr_type)
    {
    case EXPR_OP:
      return optimize_op (e);
      break;

    case EXPR_FUNCTION:
      optimize_actual_arglist (e->value.function.actual);
      break;

    default:
      break;
    }

  return ret;
}

/* Recursive optimization of operators.  */

static bool
optimize_op (gfc_expr *e)
{

  gfc_intrinsic_op op;

  op = e->value.op.op;

  switch (op)
    {
    case INTRINSIC_EQ:
    case INTRINSIC_EQ_OS:
    case INTRINSIC_GE:
    case INTRINSIC_GE_OS:
    case INTRINSIC_LE:
    case INTRINSIC_LE_OS:
      return optimize_equality (e, true);
      break;

    case INTRINSIC_NE:
    case INTRINSIC_NE_OS:
    case INTRINSIC_GT:
    case INTRINSIC_GT_OS:
    case INTRINSIC_LT:
    case INTRINSIC_LT_OS:
      return optimize_equality (e, false);
      break;

    default:
      break;
    }

  return false;
}

/* Optimize expressions for equality.  */

static bool
optimize_equality (gfc_expr *e, bool equal)
{

  gfc_expr *op1, *op2;
  bool change;

  op1 = e->value.op.op1;
  op2 = e->value.op.op2;

  /* Strip off unneeded TRIM calls from string comparisons.  */

  change = false;

  if (op1->expr_type == EXPR_FUNCTION 
      && op1->value.function.isym
      && op1->value.function.isym->id == GFC_ISYM_TRIM)
    {
      strip_function_call (op1);
      change = true;
    }

  if (op2->expr_type == EXPR_FUNCTION 
      && op2->value.function.isym
      && op2->value.function.isym->id == GFC_ISYM_TRIM)
    {
      strip_function_call (op2);
      change = true;
    }

  if (change)
    {
      optimize_equality (e, equal);
      return true;
    }

  /* Check for direct comparison between identical variables.
     TODO: Handle cases with identical refs.  */
  if (op1->expr_type == EXPR_VARIABLE
      && op2->expr_type == EXPR_VARIABLE
      && op1->symtree == op2->symtree
      && op1->ref == NULL && op2->ref == NULL
      && op1->ts.type != BT_REAL && op2->ts.type != BT_REAL
      && op1->ts.type != BT_COMPLEX && op2->ts.type !=BT_COMPLEX)
    {
      /* Replace the expression by a constant expression.  The typespec
	 and where remains the way it is.  */
      gfc_free (op1);
      gfc_free (op2);
      e->expr_type = EXPR_CONSTANT;
      e->value.logical = equal;
      return true;
    }
  return false;
}

/* Optimize a call list.  Right now, this just goes through the actual
   arg list and optimizes each expression in turn.  */

static void
optimize_actual_arglist (gfc_actual_arglist *a)
{

  for (; a; a = a->next)
    {
      if (a->expr != NULL)
	optimize_expr_0 (a->expr);
    }
  
  return;
}

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-20 22:01                 ` Thomas Koenig
@ 2010-07-25 15:52                   ` Tobias Burnus
  2010-07-25 19:35                     ` Thomas Koenig
  0 siblings, 1 reply; 22+ messages in thread
From: Tobias Burnus @ 2010-07-25 15:52 UTC (permalink / raw)
  To: Thomas Koenig; +Cc: fortran, gcc-patches

Thomas Koenig wrote:
> Well, here is an updated version of the patch.
>
> I have also changed the place where the gfc_run_passes is called to
> resolve.c, as pault had suggested on IRC.
>
> Regression-tested, only allocate_with_typespec.f90 failed (which I also
> saw on gcc-testresults).
> OK?
>   
OK. Thanks for the patch - and sorry for the late review.

Nits:

Index: gfortran.h
+/* passes.c */
+
+void gfc_run_passes (gfc_namespace *);


Update the filename in the comment.

! { dg-final { scan-tree-dump-times "memmove" 2 "original" } }

Can you add:
! { dg-final { scan-tree-dump-times "string_trim" 0 "original" } }


  /* Check for direct comparison between identical variables.
     TODO: Handle cases with identical refs.  */
  if (op1->expr_type == EXPR_VARIABLE
      && op2->expr_type == EXPR_VARIABLE
      && op1->symtree == op2->symtree
      && op1->ref == NULL && op2->ref == NULL
      && op1->ts.type != BT_REAL && op2->ts.type != BT_REAL
      && op1->ts.type != BT_COMPLEX && op2->ts.type !=BT_COMPLEX)


Is there a reason that you do not include REAL and COMPLEX variables,
but everything else? (characters, derived types, polymorphic types
(class), integer, Hollerith, ...). Especially, as derived types can also
contains real/complex variables ;-)

It seems to be save to do this comparison also for REAL and COMPLEX.

Tobias

> 2010-07-20  Thomas Koenig  <tkoenig@gcc.gnu.org>
>
> 	* Make-lang.in:  Add fortran/frontend-passes.o.
> 	* gfortran.h:  Add prototype for gfc_run_passes.
> 	* resolve.c (gfc_resolve):  Call gfc_run_passes.
> 	* frontend-passes.c:  New file.
>
> 2010-0717  Thomas Koenig  <tkoenig@gcc.gnu.org>
>
> 	* trim_optimize_1.f90:  New test.
> 	* character_comparision_1.f90:  New test.
>   

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-25 15:52                   ` Tobias Burnus
@ 2010-07-25 19:35                     ` Thomas Koenig
  2010-07-25 21:15                       ` Paolo Bonzini
  0 siblings, 1 reply; 22+ messages in thread
From: Thomas Koenig @ 2010-07-25 19:35 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: fortran, gcc-patches

Tobias Burnus wrote:
> Thomas Koenig wrote:
> > Well, here is an updated version of the patch.
> >
> > I have also changed the place where the gfc_run_passes is called to
> > resolve.c, as pault had suggested on IRC.
> >
> > Regression-tested, only allocate_with_typespec.f90 failed (which I also
> > saw on gcc-testresults).
> > OK?
> >   
> OK. Thanks for the patch - and sorry for the late review.

Thanks a lot!

> Nits:
> 
> Index: gfortran.h
> +/* passes.c */
> +
> +void gfc_run_passes (gfc_namespace *);
> 
> 
> Update the filename in the comment.

Done.

> ! { dg-final { scan-tree-dump-times "memmove" 2 "original" } }
> 
> Can you add:
> ! { dg-final { scan-tree-dump-times "string_trim" 0 "original" } }

Done.
> 
>   /* Check for direct comparison between identical variables.
>      TODO: Handle cases with identical refs.  */
>   if (op1->expr_type == EXPR_VARIABLE
>       && op2->expr_type == EXPR_VARIABLE
>       && op1->symtree == op2->symtree
>       && op1->ref == NULL && op2->ref == NULL
>       && op1->ts.type != BT_REAL && op2->ts.type != BT_REAL
>       && op1->ts.type != BT_COMPLEX && op2->ts.type !=BT_COMPLEX)

> Is there a reason that you do not include REAL and COMPLEX variables,
> but everything else? (characters, derived types, polymorphic types
> (class), integer, Hollerith, ...). Especially, as derived types can also
> contains real/complex variables ;-)

The main reason is that I don't want to invalidate the

  if (a /= a)

idiom for checking for NANs.  This would also cause a few testsuite
failures, where we do exactly this.

Again, thanks for the review!

Ãœbertrage Daten ........
Revision 162519 übertragen.

	Thomas

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-25 19:35                     ` Thomas Koenig
@ 2010-07-25 21:15                       ` Paolo Bonzini
  2010-07-26 19:24                         ` Thomas Koenig
  0 siblings, 1 reply; 22+ messages in thread
From: Paolo Bonzini @ 2010-07-25 21:15 UTC (permalink / raw)
  To: Thomas Koenig; +Cc: Tobias Burnus, fortran, gcc-patches

On 07/25/2010 09:35 PM, Thomas Koenig wrote:
>>    /* Check for direct comparison between identical variables.
>>       TODO: Handle cases with identical refs.  */
>>    if (op1->expr_type == EXPR_VARIABLE
>>        &&  op2->expr_type == EXPR_VARIABLE
>>        &&  op1->symtree == op2->symtree
>>        &&  op1->ref == NULL&&  op2->ref == NULL
>>        &&  op1->ts.type != BT_REAL&&  op2->ts.type != BT_REAL
>>        &&  op1->ts.type != BT_COMPLEX&&  op2->ts.type !=BT_COMPLEX)
>
>> Is there a reason that you do not include REAL and COMPLEX variables,
>> but everything else? (characters, derived types, polymorphic types
>> (class), integer, Hollerith, ...). Especially, as derived types can also
>> contains real/complex variables ;-)
>
> The main reason is that I don't want to invalidate the
>
>    if (a /= a)
>
> idiom for checking for NANs.  This would also cause a few testsuite
> failures, where we do exactly this.

You could test HONOR_NANS for that, though I don't know whether modes 
are already available in the Fortran front-end (failing that, there is 
flag_finite_math_only).

What is the default definition of equality for derived types, if any? 
Would "if (d /= d)" change meaning if d contains a single real?

Paolo

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [patch, fortran] PR 40628, front-end optimization pass
  2010-07-25 21:15                       ` Paolo Bonzini
@ 2010-07-26 19:24                         ` Thomas Koenig
  0 siblings, 0 replies; 22+ messages in thread
From: Thomas Koenig @ 2010-07-26 19:24 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: fortran, gcc-patches

Paolo Bonzini wrote:

> You could test HONOR_NANS for that, though I don't know whether modes 
> are already available in the Fortran front-end (failing that, there
> is 
> flag_finite_math_only).

That's right, I'll probably do this in a future patch.

> What is the default definition of equality for derived types, if any? 

There is no intrinsic equality operator for derived types.  You can
define your own, but this will end up as the function actually being
invoked in the gfc_* structures.

	Thomas

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2010-07-26 17:14 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-17 18:38 [patch, fortran] PR 40628, front-end optimization pass Thomas Koenig
2010-07-18  8:41 ` Daniel Kraft
2010-07-18 10:18   ` Thomas Koenig
2010-07-19 18:59     ` Toon Moene
2010-07-19 19:11       ` Thomas Koenig
2010-07-19  4:12   ` Jerry DeLisle
2010-07-19 18:21     ` Richard Henderson
2010-07-19 19:06     ` Jakub Jelinek
2010-07-19 22:31     ` Thomas Koenig
2010-07-20  1:19       ` Jerry DeLisle
2010-07-20  2:08         ` Steve Kargl
2010-07-20  2:39         ` Diego Novillo
2010-07-20  2:54           ` Jerry DeLisle
2010-07-20  8:05         ` Tobias Burnus
2010-07-20  8:21           ` Daniel Kraft
2010-07-20  9:44             ` Toon Moene
2010-07-20  9:58               ` Richard Guenther
2010-07-20 22:01                 ` Thomas Koenig
2010-07-25 15:52                   ` Tobias Burnus
2010-07-25 19:35                     ` Thomas Koenig
2010-07-25 21:15                       ` Paolo Bonzini
2010-07-26 19:24                         ` Thomas Koenig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).