summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/fortran/ChangeLog7
-rw-r--r--gcc/fortran/frontend-passes.c80
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gfortran.dg/do_while_1.f9010
4 files changed, 102 insertions, 0 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 96af79e04f8..836967d7a4b 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,10 @@
+2011-09-11 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/50327
+ * frontend-passes.c (dummy_expr_callback): New function.
+ (convert_do_while): New function.
+ (optimize_namespace): Call code walker to convert do while loops.
+
2011-09-11 Janus Weil <janus@gcc.gnu.org>
PR fortran/35831
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index ab8e9e0607b..16053e0742a 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -407,6 +407,85 @@ cfe_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
return 0;
}
+/* Dummy function for expression call back, for use when we
+ really don't want to do any walking. */
+
+static int
+dummy_expr_callback (gfc_expr **e ATTRIBUTE_UNUSED, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
+{
+ *walk_subtrees = 0;
+ return 0;
+}
+
+/* Code callback function for converting
+ do while(a)
+ end do
+ into the equivalent
+ do
+ if (.not. a) exit
+ end do
+ This is because common function elimination would otherwise place the
+ temporary variables outside the loop. */
+
+static int
+convert_do_while (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ gfc_code *co = *c;
+ gfc_code *c_if1, *c_if2, *c_exit;
+ gfc_code *loopblock;
+ gfc_expr *e_not, *e_cond;
+
+ if (co->op != EXEC_DO_WHILE)
+ return 0;
+
+ if (co->expr1 == NULL || co->expr1->expr_type == EXPR_CONSTANT)
+ return 0;
+
+ e_cond = co->expr1;
+
+ /* Generate the condition of the if statement, which is .not. the original
+ statement. */
+ e_not = gfc_get_expr ();
+ e_not->ts = e_cond->ts;
+ e_not->where = e_cond->where;
+ e_not->expr_type = EXPR_OP;
+ e_not->value.op.op = INTRINSIC_NOT;
+ e_not->value.op.op1 = e_cond;
+
+ /* Generate the EXIT statement. */
+ c_exit = XCNEW (gfc_code);
+ c_exit->op = EXEC_EXIT;
+ c_exit->ext.which_construct = co;
+ c_exit->loc = co->loc;
+
+ /* Generate the IF statement. */
+ c_if2 = XCNEW (gfc_code);
+ c_if2->op = EXEC_IF;
+ c_if2->expr1 = e_not;
+ c_if2->next = c_exit;
+ c_if2->loc = co->loc;
+
+ /* ... plus the one to chain it to. */
+ c_if1 = XCNEW (gfc_code);
+ c_if1->op = EXEC_IF;
+ c_if1->block = c_if2;
+ c_if1->loc = co->loc;
+
+ /* Make the DO WHILE loop into a DO block by replacing the condition
+ with a true constant. */
+ co->expr1 = gfc_get_logical_expr (gfc_default_integer_kind, &co->loc, true);
+
+ /* Hang the generated if statement into the loop body. */
+
+ loopblock = co->block->next;
+ co->block->next = c_if1;
+ c_if1->next = loopblock;
+
+ return 0;
+}
+
/* Optimize a namespace, including all contained namespaces. */
static void
@@ -415,6 +494,7 @@ optimize_namespace (gfc_namespace *ns)
current_ns = ns;
+ gfc_code_walker (&ns->code, convert_do_while, dummy_expr_callback, NULL);
gfc_code_walker (&ns->code, cfe_code, cfe_expr_0, NULL);
gfc_code_walker (&ns->code, optimize_code, optimize_expr, NULL);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 2a5096970bc..f3cb48705ac 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-09-11 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/50327
+ * gfortran.dg/do_while_1.f90: New test.
+
2011-09-11 Janus Weil <janus@gcc.gnu.org>
PR fortran/35831
diff --git a/gcc/testsuite/gfortran.dg/do_while_1.f90 b/gcc/testsuite/gfortran.dg/do_while_1.f90
new file mode 100644
index 00000000000..0a22ff37cf0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/do_while_1.f90
@@ -0,0 +1,10 @@
+! { dg-do run }
+! PR 50327 - this used to cause an endless loop because
+! of wrong fron-end optimization.
+program main
+ real :: tmp
+ tmp = 0.
+ do while (abs(tmp) < 10. .and. abs(tmp) < 20.)
+ tmp = tmp + 1.
+ end do
+end program main