From patchwork Fri Sep 3 22:58:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [fortran] Fix PR 36931, more array dependencies Date: Fri, 03 Sep 2010 12:58:41 -0000 From: Thomas Koenig X-Patchwork-Id: 63732 Message-Id: <1283554721.4759.23.camel@linux-fd1f.site> To: fortran@gcc.gnu.org Cc: gcc-patches@gcc.gnu.org Hello world, here a few more temporary eliminations, for code like a = f() + b After unsuccessfully trying to understand how to do this in trans-*, I used a transformation of the front end trees, in the front end optimization pass. Regression-tested. OK for trunk? Thomas 2010-09-04 Thomas Koenig PR fortran/36931 * frontend-passes.c (optimize_binop_array_assignment): New function. (optimize_assignment): Call it. 2010-09-04 Thomas Koenig PR fortran/36931 * gfortran.dg/dependency_35.f90: New test. Index: frontend-passes.c =================================================================== --- frontend-passes.c (Revision 163846) +++ frontend-passes.c (Arbeitskopie) @@ -235,6 +235,77 @@ optimize_code_node (gfc_code *c) } } +/* Replace code like + a = matmul(b,c) + d + with + a = matmul(b,c) ; a = a + d + where the array function is not elemental and not allocatable + and does not depend on the left-hand side. +*/ + +static bool +optimize_binop_array_assignment (gfc_code *c, gfc_expr **rhs, bool seen_op) +{ + gfc_expr *e; + + e = *rhs; + if (e->expr_type == EXPR_OP) + { + switch (e->value.op.op) + { + /* Unary operators and exponentiation: Only look at a single + operand. */ + case INTRINSIC_NOT: + case INTRINSIC_UPLUS: + case INTRINSIC_UMINUS: + case INTRINSIC_PARENTHESES: + case INTRINSIC_POWER: + if (optimize_binop_array_assignment (c, &e->value.op.op1, seen_op)) + return true; + break; + + default: + /* Binary operators. */ + if (optimize_binop_array_assignment (c, &e->value.op.op1, true)) + return true; + + if (optimize_binop_array_assignment (c, &e->value.op.op2, true)) + return true; + + break; + } + } + else if (seen_op && e->expr_type == EXPR_FUNCTION && e->rank > 0 + && ! (e->value.function.esym + && (e->value.function.esym->attr.elemental + || e->value.function.esym->attr.allocatable)) + && ! (e->value.function.isym && e->value.function.isym->elemental)) + { + + gfc_code *n; + gfc_expr *new_expr; + + /* Insert a new assignment statement after the current one. */ + n = XCNEW (gfc_code); + n->op = EXEC_ASSIGN; + n->loc = c->loc; + n->next = c->next; + c->next = n; + + n->expr1 = gfc_copy_expr (c->expr1); + n->expr2 = c->expr2; + new_expr = gfc_copy_expr (c->expr1); + c->expr2 = e; + *rhs = new_expr; + + return true; + + } + + /* Nothing to optimize. */ + return false; +} + /* Optimizations for an assignment. */ static void @@ -259,6 +330,13 @@ optimize_assignment (gfc_code * c) } } + if (lhs->rank > 0 && gfc_check_dependency (lhs, rhs, true) == 0) + optimize_binop_array_assignment (c, &rhs, false); + + /* If we insert a statement after the current one, the surrounding loop in + optimize_code will call optimize_assignment on the inserted statement + anyway, so there is no need to call optimize_assignment again. */ + /* All direct optimizations have been done. Now it's time to optimize the rhs. */