aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2010-12-31 11:32:16 +0000
committerThomas Koenig <tkoenig@gcc.gnu.org>2010-12-31 11:32:16 +0000
commit4afeb65c3248e4ece2720ea616d9333bdedaf5ff (patch)
treedce0054aa68fea712fe3f1b5b0444415fe2541ad
parent7c1a49fa1b2535dcce600d03887e2c72a463cc2c (diff)
downloadgcc-4afeb65c3248e4ece2720ea616d9333bdedaf5ff.zip
gcc-4afeb65c3248e4ece2720ea616d9333bdedaf5ff.tar.gz
gcc-4afeb65c3248e4ece2720ea616d9333bdedaf5ff.tar.bz2
re PR fortran/47065 (Replace trim(a) by a(1:len_trim(a)))
2010-12-31 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-31 Thomas Koenig <tkoenig@gcc.gnu.org> PR fortran/47065 * gfortran.dg/trim_optimize_3.f90: New test. * gfortran.dg/trim_optimize_4.f90: New test. From-SVN: r168367
-rw-r--r--gcc/fortran/ChangeLog10
-rw-r--r--gcc/fortran/frontend-passes.c105
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gfortran.dg/trim_optimize_3.f9016
-rw-r--r--gcc/testsuite/gfortran.dg/trim_optimize_4.f9025
5 files changed, 161 insertions, 1 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index c210331..e25d4e3 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,15 @@
2010-12-31 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-31 Thomas Koenig <tkoenig@gcc.gnu.org>
+
PR fortran/45338
* resolve.c (resolve_operator): Mark function for user-defined
operator as referenced.
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 339458e..0777dba 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -34,6 +34,11 @@ 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 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 \
{ \
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4e4601d..8295963 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,11 @@
2010-12-31 Thomas Koenig <tkoenig@gcc.gnu.org>
+ PR fortran/47065
+ * gfortran.dg/trim_optimize_3.f90: New test.
+ * gfortran.dg/trim_optimize_4.f90: New test.
+
+2010-12-31 Thomas Koenig <tkoenig@gcc.gnu.org>
+
PR fortran/45338
* gfortran.dg/userdef_operator_2.f90: New test case.
diff --git a/gcc/testsuite/gfortran.dg/trim_optimize_3.f90 b/gcc/testsuite/gfortran.dg/trim_optimize_3.f90
new file mode 100644
index 0000000..33cf8b2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/trim_optimize_3.f90
@@ -0,0 +1,16 @@
+! { dg-do run }
+! { dg-options "-O -fdump-tree-original" }
+! PR 47065 - replace trim with substring expressions.
+program main
+ character(len=10) :: a, b
+ character(kind=4,len=10) :: a4, b4
+ character(len=100) :: line
+ a = 'bcd'
+ b = trim(a) // 'x'
+ if (b /= 'bcdx') call abort
+ a4 = 4_"bcd"
+ b4 = trim(a4) // 4_'x'
+ if (b4 /= 4_'bcdx') call abort
+end
+! { dg-final { scan-tree-dump-times "string_len_trim" 2 "original" } }
+! { dg-final { cleanup-tree-dump "original" } }
diff --git a/gcc/testsuite/gfortran.dg/trim_optimize_4.f90 b/gcc/testsuite/gfortran.dg/trim_optimize_4.f90
new file mode 100644
index 0000000..41c65b1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/trim_optimize_4.f90
@@ -0,0 +1,25 @@
+! { dg-do run }
+! PR 47065 - make sure that trim optimization does not lead to
+! wrong-code with aliasing.
+! Test case provided by Tobias Burnus.
+program main
+ character(len=12) :: str
+ str = '1234567890'
+ call sub(trim(str), str)
+ ! Should print '12345 '
+ if (str /= '12345 ') call abort
+ call two(trim(str))
+ if (str /= '123 ') call abort
+contains
+ subroutine sub(a,b)
+ character(len=*), intent(in) :: a
+ character(len=*), intent(out) :: b
+ b = ''
+ b = a(1:5)
+ end subroutine sub
+ subroutine two(a)
+ character(len=*), intent(in) :: a
+ str = ''
+ str(1:3) = a(1:3)
+ end subroutine two
+end program main