This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch, fortran, 4.9] Improve efficiency of array constructor operators


Hello world,

this patch finally makes the idiom

if (any([a,b,c] < eps)) then

equivalent to

if (a<eps .or. b<eps .or. c<eps) then

so that there is no loss in efficiency through generating
temporary arrays.

OK for trunk?

Thomas

2013-03-17 Thomas Koenig <tkoenig@gcc.gnu.org>

        PR fortran/55806
        * frontend-passes.c (optimize_code):  Keep track of
        current code to make code insertion possible.
        (combine_array_constructor):  New function.
        (optimize_op):  Call it.

2013-03-17 Thomas Koenig <tkoenig@gcc.gnu.org>

        PR fortran/55806
        * gfortran.dg/array_constructor_43.f90:  New test.
Index: frontend-passes.c
===================================================================
--- frontend-passes.c	(Revision 195319)
+++ frontend-passes.c	(Arbeitskopie)
@@ -135,6 +135,10 @@ optimize_code (gfc_code **c, int *walk_subtrees AT
   else
     count_arglist = 0;
 
+  current_code = c;
+  inserted_block = NULL;
+  changed_statement = NULL;
+
   if (op == EXEC_ASSIGN)
     optimize_assignment (*c);
   return 0;
@@ -991,13 +995,92 @@ optimize_lexical_comparison (gfc_expr *e)
   return false;
 }
 
+/* Combine stuff like [a]>b into [a>b], for easier optimization later.  Do not
+   do CHARACTER because of possible pessimization involving character lengths.  */
+
+static bool
+combine_array_constructor (gfc_expr *e)
+{
+
+  gfc_expr *op1, *op2; /* Shut up warnings.  */
+  gfc_expr *scalar;
+  gfc_expr *new_expr;
+  gfc_constructor *c;
+  gfc_constructor_base oldbase, newbase;
+  bool scalar_first;
+
+  /* Array constructors have rank one.  */
+  if (e->rank != 1)
+    return false;
+
+  op1 = e->value.op.op1;
+  op2 = e->value.op.op2;
+
+  if (op1->expr_type == EXPR_ARRAY && op2->rank == 0)
+    scalar_first = false;
+  else if (op2->expr_type == EXPR_ARRAY && op1->rank == 0)
+    {
+      scalar_first = true;
+      op1 = e->value.op.op2;
+      op2 = e->value.op.op1;
+    }
+  else
+    return false;
+
+  if (op2->ts.type == BT_CHARACTER)
+    return false;
+
+  if (op2->expr_type == EXPR_CONSTANT)
+    scalar = gfc_copy_expr (op2);
+  else
+    scalar = create_var (gfc_copy_expr (op2));
+
+  oldbase = op1->value.constructor;
+  newbase = NULL;
+  e->expr_type = EXPR_ARRAY;
+
+  for (c = gfc_constructor_first (oldbase); c;
+       c = gfc_constructor_next (c))
+    {
+      new_expr = gfc_get_expr ();
+      new_expr->ts = e->ts;
+      new_expr->expr_type = EXPR_OP;
+      new_expr->rank = c->expr->rank;
+      new_expr->where = c->where;
+      new_expr->value.op.op = e->value.op.op;
+
+      if (scalar_first)
+	{
+	  new_expr->value.op.op1 = gfc_copy_expr (scalar);
+	  new_expr->value.op.op2 = gfc_copy_expr (c->expr);
+	}
+      else
+	{
+	  new_expr->value.op.op1 = gfc_copy_expr (c->expr);
+	  new_expr->value.op.op2 = gfc_copy_expr (scalar);
+	}
+
+      gfc_constructor_append_expr (&newbase, new_expr, &(e->where));
+    }
+
+  gfc_free_expr (op1);
+  gfc_free_expr (op2);
+
+  e->value.constructor = newbase;
+  return true;
+}
+
 /* Recursive optimization of operators.  */
 
 static bool
 optimize_op (gfc_expr *e)
 {
+  bool changed;
+
   gfc_intrinsic_op op = e->value.op.op;
 
+  changed = false;
+
   /* Only use new-style comparisons.  */
   switch(op)
     {
@@ -1037,8 +1120,16 @@ optimize_op (gfc_expr *e)
     case INTRINSIC_NE:
     case INTRINSIC_GT:
     case INTRINSIC_LT:
-      return optimize_comparison (e, op);
+      changed = optimize_comparison (e, op);
 
+      /* Fall through */
+      /* Look at array constructors.  */
+    case INTRINSIC_PLUS:
+    case INTRINSIC_MINUS:
+    case INTRINSIC_TIMES:
+    case INTRINSIC_DIVIDE:
+      return combine_array_constructor (e) || changed;
+
     default:
       break;
     }
! { dg-do compile }
! { dg-options "-ffrontend-optimize -fdump-tree-original" }
program main
  implicit none
  real :: a,b,c,d
  call random_number(a)
  call random_number(b)
  call random_number(c)
  call random_number(d)
  if (any ([a,b,c,d] < 0.2)) print *,"foo"
end program main
! { dg-final { scan-tree-dump-times "\\\|\\\|" 3 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]