Patchwork [fortran] PR 46065 - optimize trim

login
register
mail settings
Submitter Thomas Koenig
Date Dec. 29, 2010, 4:29 p.m.
Message ID <1293640171.4756.60.camel@linux-fd1f.site>
Download mbox | patch
Permalink /patch/76928/
State New
Headers show

Comments

Thomas Koenig - Dec. 29, 2010, 4:29 p.m.
Hello Tobias,

> However, I worry that 
> the following program is mishandled, "sub" is the obvious case while 
> "two" is a special case, cf. PR 46896.

The attached version of the patch fixes your concern by never applying
this optimization within an argument list.  I have also added your test
case.

Regression-tested.  OK for trunk?

	Thomas

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

	PR fortran/47065
	* frontend-passes.c (count_arglist):  Static variable to
	count the nesting of argument lists.
	(optimize_code):  Set count_arglist to 1 if within a call
	statement, to 0 otherwise.
	(optimize_trim):  New function.
	(optimize_expr):  Adjust count_arglist.  Call optimize_trim.

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

	PR fortran/47065
	* gfortran.dg/optimize_trim_3.f90:  New test.
	* gfortran.dg/optimize_trim_4.f90:  New test.
Tobias Burnus - Dec. 31, 2010, 11:13 a.m.
Hello Thomas,

Thomas Koenig wrote:
>> However, I worry that
>> the following program is mishandled, "sub" is the obvious case while
>> "two" is a special case, cf. PR 46896.
> The attached version of the patch fixes your concern by never applying
> this optimization within an argument list.  I have also added your test
> case.

The patch is OK. One could relax that argument-list restriction and 
allow it for PURE procedures, which is the trivial case - but that can 
(like the ref part) be deferred.

Thanks!

Tobias

> 2010-12-29  Thomas Koenig<tkoenig@gcc.gnu.org>
>
> 	PR fortran/47065
> 	* frontend-passes.c (count_arglist):  Static variable to
> 	count the nesting of argument lists.
> 	(optimize_code):  Set count_arglist to 1 if within a call
> 	statement, to 0 otherwise.
> 	(optimize_trim):  New function.
> 	(optimize_expr):  Adjust count_arglist.  Call optimize_trim.
>
> 2010-12-29  Thomas Koenig<tkoenig@gcc.gnu.org>
>
> 	PR fortran/47065
> 	* gfortran.dg/optimize_trim_3.f90:  New test.
> 	* gfortran.dg/optimize_trim_4.f90:  New test.
Thomas Koenig - Dec. 31, 2010, 11:33 a.m.
Am Freitag, den 31.12.2010, 12:13 +0100 schrieb Tobias Burnus:
> Hello Thomas,
> 
> Thomas Koenig wrote:
> >> However, I worry that
> >> the following program is mishandled, "sub" is the obvious case while
> >> "two" is a special case, cf. PR 46896.
> > The attached version of the patch fixes your concern by never applying
> > this optimization within an argument list.  I have also added your test
> > case.
> 
> The patch is OK. One could relax that argument-list restriction and 
> allow it for PURE procedures, which is the trivial case - but that can 
> (like the ref part) be deferred.

Sende          fortran/ChangeLog
Sende          fortran/frontend-passes.c
Sende          testsuite/ChangeLog
Hinzufügen     testsuite/gfortran.dg/trim_optimize_3.f90
Hinzufügen     testsuite/gfortran.dg/trim_optimize_4.f90
Übertrage Daten .....
Revision 168367 übertragen.

Thanks for the review!

I will update the PR with the comments of what can still be added.

	Thomas

Patch

Index: frontend-passes.c
===================================================================
--- frontend-passes.c	(Revision 168320)
+++ frontend-passes.c	(Arbeitskopie)
@@ -34,7 +34,12 @@  static void optimize_namespace (gfc_namespace *);
 static void optimize_assignment (gfc_code *);
 static bool optimize_op (gfc_expr *);
 static bool optimize_comparison (gfc_expr *, gfc_intrinsic_op);
+static bool optimize_trim (gfc_expr *);
 
+/* How deep we are inside an argument list.  */
+
+static int count_arglist;
+
 /* Entry point - run all passes for a namespace.  So far, only an
    optimization pass is run.  */
 
@@ -56,7 +61,18 @@  static int
 optimize_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
 	       void *data ATTRIBUTE_UNUSED)
 {
-  if ((*c)->op == EXEC_ASSIGN)
+
+  gfc_exec_op op;
+
+  op = (*c)->op;
+
+  if (op == EXEC_CALL || op == EXEC_COMPCALL || op == EXEC_ASSIGN_CALL
+      || op == EXEC_CALL_PPC)
+    count_arglist = 1;
+  else
+    count_arglist = 0;
+
+  if (op == EXEC_ASSIGN)
     optimize_assignment (*c);
   return 0;
 }
@@ -68,8 +84,25 @@  static int
 optimize_expr (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
 	       void *data ATTRIBUTE_UNUSED)
 {
+  bool function_expr;
+
+  if ((*e)->expr_type == EXPR_FUNCTION)
+    {
+      count_arglist ++;
+      function_expr = true;
+    }
+  else
+    function_expr = false;
+
+  if (optimize_trim (*e))
+    gfc_simplify_expr (*e, 0);
+
   if ((*e)->expr_type == EXPR_OP && optimize_op (*e))
     gfc_simplify_expr (*e, 0);
+
+  if (function_expr)
+    count_arglist --;
+
   return 0;
 }
 
@@ -395,6 +428,76 @@  optimize_comparison (gfc_expr *e, gfc_intrinsic_op
   return false;
 }
 
+/* Optimize a trim function by replacing it with an equivalent substring
+   involving a call to len_trim.  This only works for expressions where
+   variables are trimmed.  Return true if anything was modified.  */
+
+static bool
+optimize_trim (gfc_expr *e)
+{
+  gfc_expr *a;
+  gfc_ref *ref;
+  gfc_expr *fcn;
+  gfc_actual_arglist *actual_arglist, *next;
+
+  /* Don't do this optimization within an argument list, because
+     otherwise aliasing issues may occur.  */
+
+  if (count_arglist != 1)
+    return false;
+
+  if (e->ts.type != BT_CHARACTER || e->expr_type != EXPR_FUNCTION
+      || e->value.function.isym == NULL
+      || e->value.function.isym->id != GFC_ISYM_TRIM)
+    return false;
+
+  a = e->value.function.actual->expr;
+
+  if (a->expr_type != EXPR_VARIABLE)
+    return false;
+
+  if (a->ref)
+    {
+      /* FIXME - also handle substring references, by modifying the
+	 reference itself.  Make sure not to evaluate functions in
+	 the references twice.  */
+      return false;
+    }
+  else
+    {
+      strip_function_call (e);
+
+      /* Create the reference.  */
+
+      ref = gfc_get_ref ();
+      ref->type = REF_SUBSTRING;
+
+      /* Set the start of the reference.  */
+
+      ref->u.ss.start = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1);
+
+      /* Build the function call to len_trim(x, gfc_defaul_integer_kind).  */
+
+      fcn = gfc_get_expr ();
+      fcn->expr_type = EXPR_FUNCTION;
+      fcn->value.function.isym =
+	gfc_intrinsic_function_by_id (GFC_ISYM_LEN_TRIM);
+      actual_arglist = gfc_get_actual_arglist ();
+      actual_arglist->expr = gfc_copy_expr (e);
+      next = gfc_get_actual_arglist ();
+      next->expr = gfc_get_int_expr (gfc_default_integer_kind, NULL,
+				     gfc_default_integer_kind);
+      actual_arglist->next = next;
+      fcn->value.function.actual = actual_arglist;
+
+      /* Set the end of the reference to the call to len_trim.  */
+
+      ref->u.ss.end = fcn;
+      e->ref = ref;
+      return true;
+    }
+}
+
 #define WALK_SUBEXPR(NODE) \
   do							\
     {							\