OSDN Git Service

2011-01-13 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / frontend-passes.c
index 6cea263..7c55767 100644 (file)
@@ -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                                                   \
     {                                                  \
@@ -524,9 +627,12 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
       int result = codefn (c, &walk_subtrees, data);
       if (result)
        return result;
+
       if (walk_subtrees)
        {
          gfc_code *b;
+         gfc_actual_arglist *a;
+
          switch ((*c)->op)
            {
            case EXEC_DO:
@@ -535,12 +641,25 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR ((*c)->ext.iterator->end);
              WALK_SUBEXPR ((*c)->ext.iterator->step);
              break;
+
+           case EXEC_CALL:
+           case EXEC_ASSIGN_CALL:
+             for (a = (*c)->ext.actual; a; a = a->next)
+               WALK_SUBEXPR (a->expr);
+             break;
+
+           case EXEC_CALL_PPC:
+             WALK_SUBEXPR ((*c)->expr1);
+             for (a = (*c)->ext.actual; a; a = a->next)
+               WALK_SUBEXPR (a->expr);
+             break;
+
            case EXEC_SELECT:
              WALK_SUBEXPR ((*c)->expr1);
              for (b = (*c)->block; b; b = b->block)
                {
                  gfc_case *cp;
-                 for (cp = b->ext.case_list; cp; cp = cp->next)
+                 for (cp = b->ext.block.case_list; cp; cp = cp->next)
                    {
                      WALK_SUBEXPR (cp->low);
                      WALK_SUBEXPR (cp->high);
@@ -548,6 +667,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
                  WALK_SUBCODE (b->next);
                }
              continue;
+
            case EXEC_ALLOCATE:
            case EXEC_DEALLOCATE:
              {
@@ -556,6 +676,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
                  WALK_SUBEXPR (a->expr);
                break;
              }
+
            case EXEC_FORALL:
              {
                gfc_forall_iterator *fa;
@@ -568,6 +689,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
                  }
                break;
              }
+
            case EXEC_OPEN:
              WALK_SUBEXPR ((*c)->ext.open->unit);
              WALK_SUBEXPR ((*c)->ext.open->file);
@@ -591,12 +713,14 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR ((*c)->ext.open->id);
              WALK_SUBEXPR ((*c)->ext.open->newunit);
              break;
+
            case EXEC_CLOSE:
              WALK_SUBEXPR ((*c)->ext.close->unit);
              WALK_SUBEXPR ((*c)->ext.close->status);
              WALK_SUBEXPR ((*c)->ext.close->iostat);
              WALK_SUBEXPR ((*c)->ext.close->iomsg);
              break;
+
            case EXEC_BACKSPACE:
            case EXEC_ENDFILE:
            case EXEC_REWIND:
@@ -605,6 +729,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR ((*c)->ext.filepos->iostat);
              WALK_SUBEXPR ((*c)->ext.filepos->iomsg);
              break;
+
            case EXEC_INQUIRE:
              WALK_SUBEXPR ((*c)->ext.inquire->unit);
              WALK_SUBEXPR ((*c)->ext.inquire->file);
@@ -643,12 +768,14 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR ((*c)->ext.inquire->size);
              WALK_SUBEXPR ((*c)->ext.inquire->round);
              break;
+
            case EXEC_WAIT:
              WALK_SUBEXPR ((*c)->ext.wait->unit);
              WALK_SUBEXPR ((*c)->ext.wait->iostat);
              WALK_SUBEXPR ((*c)->ext.wait->iomsg);
              WALK_SUBEXPR ((*c)->ext.wait->id);
              break;
+
            case EXEC_READ:
            case EXEC_WRITE:
              WALK_SUBEXPR ((*c)->ext.dt->io_unit);
@@ -669,6 +796,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
              WALK_SUBEXPR ((*c)->ext.dt->sign);
              WALK_SUBEXPR ((*c)->ext.dt->extra_comma);
              break;
+
            case EXEC_OMP_DO:
            case EXEC_OMP_PARALLEL:
            case EXEC_OMP_PARALLEL_DO:
@@ -689,6 +817,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
            default:
              break;
            }
+
          WALK_SUBEXPR ((*c)->expr1);
          WALK_SUBEXPR ((*c)->expr2);
          WALK_SUBEXPR ((*c)->expr3);