File fortran-matmul.patch of Package gcc41

gcc/fortran/
        * Make-lang.in (fortran/trans-resolve.o): Depend on
        fortran/dependency.h.
        * gfortran.h (gfc_expr): Add an "inline_noncopying_intrinsic" flag.
        * dependency.h (gfc_get_noncopying_intrinsic_argument): Declare.
        (gfc_check_fncall_dependency): Change prototype.
        * dependency.c (gfc_get_noncopying_intrinsic_argument): New function.
        (gfc_check_argument_var_dependency): New function, split from
        gfc_check_fncall_dependency.
        (gfc_check_argument_dependency): New function.
        (gfc_check_fncall_dependency): Replace the expression parameter with
        separate symbol and argument list parameters.  Generalize the function
        to handle dependencies for any type of expression, not just variables.
        Accept a further argument giving the intent of the expression being
        tested.  Ignore intent(in) arguments if that expression is also
        intent(in).
        * resolve.c: Include dependency.h.
        (find_noncopying_intrinsics): New function.
        (resolve_function, resolve_call): Call it on success.
        * trans-array.h (gfc_conv_array_transpose): Declare.
        (gfc_check_fncall_dependency): Remove prototype.
        * trans-array.c (gfc_conv_array_transpose): New function.
        * trans-intrinsic.c (gfc_conv_intrinsic_function): Don't use the
        libcall handling if the expression is to be evaluated inline.
        Add a case for handling inline transpose()s.
        * trans-expr.c (gfc_trans_arrayfunc_assign): Adjust for the new
        interface provided by gfc_check_fncall_dependency.

libgfortran/
        * m4/matmul.m4: Use a different order in the special case of a
        transposed first argument.
        * generated/matmul_c4.c, generated/matmul_c8.c, generated/matmul_c10.c,
        * generated/matmul_c16.c, generated/matmul_i4.c, generated/matmul_i8.c,
        * generated/matmul_i10.c, generated/matmul_r4.c, generated/matmul_r8.c
        * generated/matmul_r10.c, generated/matmul_r16.c: Regenerated.

Index: gcc/fortran/trans-array.c
===================================================================
*** gcc/fortran/trans-array.c.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/trans-array.c	2009-05-13 14:54:41.000000000 +0200
*************** gfc_trans_allocate_temp_array (stmtblock
*** 726,731 ****
--- 726,820 ----
  }
  
  
+ /* Generate code to tranpose array EXPR by creating a new descriptor
+    in which the dimension specifications have been reversed.  */
+ 
+ void
+ gfc_conv_array_transpose (gfc_se * se, gfc_expr * expr)
+ {
+   tree dest, src, dest_index, src_index;
+   gfc_loopinfo *loop;
+   gfc_ss_info *dest_info, *src_info;
+   gfc_ss *dest_ss, *src_ss;
+   gfc_se src_se;
+   int n;
+ 
+   loop = se->loop;
+ 
+   src_ss = gfc_walk_expr (expr);
+   dest_ss = se->ss;
+ 
+   src_info = &src_ss->data.info;
+   dest_info = &dest_ss->data.info;
+   gcc_assert (dest_info->dimen == 2);
+   gcc_assert (src_info->dimen == 2);
+ 
+   /* Get a descriptor for EXPR.  */
+   gfc_init_se (&src_se, NULL);
+   gfc_conv_expr_descriptor (&src_se, expr, src_ss);
+   gfc_add_block_to_block (&se->pre, &src_se.pre);
+   gfc_add_block_to_block (&se->post, &src_se.post);
+   src = src_se.expr;
+ 
+   /* Allocate a new descriptor for the return value.  */
+   dest = gfc_create_var (TREE_TYPE (src), "atmp");
+   dest_info->descriptor = dest;
+   se->expr = dest;
+ 
+   /* Copy across the dtype field.  */
+   gfc_add_modify_expr (&se->pre,
+ 		       gfc_conv_descriptor_dtype (dest),
+ 		       gfc_conv_descriptor_dtype (src));
+ 
+   /* Copy the dimension information, renumbering dimension 1 to 0 and
+      0 to 1.  */
+   for (n = 0; n < 2; n++)
+     {
+       dest_info->delta[n] = integer_zero_node;
+       dest_info->start[n] = integer_zero_node;
+       dest_info->stride[n] = integer_one_node;
+       dest_info->dim[n] = n;
+ 
+       dest_index = gfc_rank_cst[n];
+       src_index = gfc_rank_cst[1 - n];
+ 
+       gfc_add_modify_expr (&se->pre,
+ 			   gfc_conv_descriptor_stride (dest, dest_index),
+ 			   gfc_conv_descriptor_stride (src, src_index));
+ 
+       gfc_add_modify_expr (&se->pre,
+ 			   gfc_conv_descriptor_lbound (dest, dest_index),
+ 			   gfc_conv_descriptor_lbound (src, src_index));
+ 
+       gfc_add_modify_expr (&se->pre,
+ 			   gfc_conv_descriptor_ubound (dest, dest_index),
+ 			   gfc_conv_descriptor_ubound (src, src_index));
+ 
+       if (!loop->to[n])
+         {
+ 	  gcc_assert (integer_zerop (loop->from[n]));
+ 	  loop->to[n] = build2 (MINUS_EXPR, gfc_array_index_type,
+ 				gfc_conv_descriptor_ubound (dest, dest_index),
+ 				gfc_conv_descriptor_lbound (dest, dest_index));
+         }
+     }
+ 
+   /* Copy the data pointer.  */
+   dest_info->data = gfc_conv_descriptor_data_get (src);
+   gfc_conv_descriptor_data_set (&se->pre, dest, dest_info->data);
+ 
+   /* Copy the offset.  This is not changed by transposition: the top-left
+      element is still at the same offset as before.  */
+   dest_info->offset = gfc_conv_descriptor_offset (src);
+   gfc_add_modify_expr (&se->pre,
+ 		       gfc_conv_descriptor_offset (dest),
+ 		       dest_info->offset);
+ 
+   if (dest_info->dimen > loop->temp_dim)
+     loop->temp_dim = dest_info->dimen;
+ }
+ 
+ 
  /* Return the number of iterations in a loop that starts at START,
     ends at END, and has step STEP.  */
  
Index: gcc/fortran/trans-expr.c
===================================================================
*** gcc/fortran/trans-expr.c.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/trans-expr.c	2009-05-13 14:33:26.000000000 +0200
*************** gfc_trans_arrayfunc_assign (gfc_expr * e
*** 3092,3098 ****
      }
  
    /* Check for a dependency.  */
!   if (gfc_check_fncall_dependency (expr1, expr2))
      return NULL;
  
    /* The frontend doesn't seem to bother filling in expr->symtree for intrinsic
--- 3092,3100 ----
      }
  
    /* Check for a dependency.  */
!   if (gfc_check_fncall_dependency (expr1, INTENT_OUT,
! 				   expr2->value.function.esym,
! 				   expr2->value.function.actual))
      return NULL;
  
    /* The frontend doesn't seem to bother filling in expr->symtree for intrinsic
Index: gcc/fortran/trans-array.h
===================================================================
*** gcc/fortran/trans-array.h.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/trans-array.h	2009-05-13 14:33:26.000000000 +0200
*************** void gfc_conv_tmp_ref (gfc_se *);
*** 95,100 ****
--- 95,102 ----
  void gfc_conv_expr_descriptor (gfc_se *, gfc_expr *, gfc_ss *);
  /* Convert an array for passing as an actual function parameter.  */
  void gfc_conv_array_parameter (gfc_se *, gfc_expr *, gfc_ss *, int);
+ /* Evaluate and transpose a matrix expression.  */
+ void gfc_conv_array_transpose (gfc_se *, gfc_expr *);
  
  /* These work with both descriptors and descriptorless arrays.  */
  tree gfc_conv_array_data (tree);
*************** tree gfc_conv_descriptor_ubound (tree, t
*** 116,123 ****
  
  /* Dependency checking for WHERE and FORALL.  */
  int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int);
- /* Dependency checking for function calls.  */
- int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *);
  
  /* Add pre-loop scalarization code for intrinsic functions which require
     special handling.  */
--- 118,123 ----
Index: gcc/fortran/resolve.c
===================================================================
*** gcc/fortran/resolve.c.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/resolve.c	2009-05-13 14:33:26.000000000 +0200
*************** Software Foundation, 51 Franklin Street,
*** 26,31 ****
--- 26,32 ----
  #include "flags.h"
  #include "gfortran.h"
  #include "arith.h"  /* For gfc_compare_expr().  */
+ #include "dependency.h"
  
  /* Types used in equivalence statements.  */
  
*************** resolve_global_procedure (gfc_symbol *sy
*** 1102,1107 ****
--- 1103,1126 ----
    gsym->used = 1;
  }
  
+ /* Go through each actual argument in ACTUAL and see if it can be
+    implemented as an inlined, non-copying intrinsic.  FNSYM is the
+    function being called, or NULL if not known.  */
+ 
+ static void
+ find_noncopying_intrinsics (gfc_symbol * fnsym, gfc_actual_arglist * actual)
+ {
+   gfc_actual_arglist *ap;
+   gfc_expr *expr;
+ 
+   for (ap = actual; ap; ap = ap->next)
+     if (ap->expr
+ 	&& (expr = gfc_get_noncopying_intrinsic_argument (ap->expr))
+ 	&& !gfc_check_fncall_dependency (expr, INTENT_IN, fnsym, actual))
+       ap->expr->inline_noncopying_intrinsic = 1;
+ }
+ 
+ 
  /************* Function resolution *************/
  
  /* Resolve a function call known to be generic.
*************** resolve_function (gfc_expr * expr)
*** 1541,1546 ****
--- 1560,1569 ----
        gfc_expr_set_symbols_referenced (expr->ts.cl->length);
      }
  
+   if (t == SUCCESS)
+     find_noncopying_intrinsics (expr->value.function.esym,
+ 				expr->value.function.actual);
+ 
    return t;
  }
  
*************** resolve_call (gfc_code * c)
*** 1812,1842 ****
    /* Resume assumed_size checking. */
    need_full_assumed_size--;
  
-   if (c->resolved_sym != NULL)
-     return SUCCESS;
  
!   switch (procedure_kind (c->symtree->n.sym))
!     {
!     case PTYPE_GENERIC:
!       t = resolve_generic_s (c);
!       break;
  
!     case PTYPE_SPECIFIC:
!       t = resolve_specific_s (c);
!       break;
  
!     case PTYPE_UNKNOWN:
!       t = resolve_unknown_s (c);
!       break;
  
!     default:
!       gfc_internal_error ("resolve_subroutine(): bad function type");
!     }
  
    /* Some checks of elemental subroutine actual arguments.  */
    if (resolve_elemental_actual (NULL, c) == FAILURE)
      return FAILURE;
  
    return t;
  }
  
--- 1835,1867 ----
    /* Resume assumed_size checking. */
    need_full_assumed_size--;
  
  
!   t = SUCCESS;
!   if (c->resolved_sym == NULL)
!     switch (procedure_kind (c->symtree->n.sym))
!       {
!       case PTYPE_GENERIC:
! 	t = resolve_generic_s (c);
! 	break;
  
!       case PTYPE_SPECIFIC:
! 	t = resolve_specific_s (c);
! 	break;
  
!       case PTYPE_UNKNOWN:
! 	t = resolve_unknown_s (c);
! 	break;
  
!       default:
! 	gfc_internal_error ("resolve_subroutine(): bad function type");
!       }
  
    /* Some checks of elemental subroutine actual arguments.  */
    if (resolve_elemental_actual (NULL, c) == FAILURE)
      return FAILURE;
  
+   if (t == SUCCESS)
+     find_noncopying_intrinsics (c->resolved_sym, c->ext.actual);
    return t;
  }
  
Index: gcc/fortran/Make-lang.in
===================================================================
*** gcc/fortran/Make-lang.in.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/Make-lang.in	2009-05-13 14:33:26.000000000 +0200
*************** fortran/trans-intrinsic.o: $(GFORTRAN_TR
*** 295,298 ****
--- 295,299 ----
    gt-fortran-trans-intrinsic.h
  fortran/dependency.o: $(GFORTRAN_TRANS_DEPS) fortran/dependency.h
  fortran/trans-common.o: $(GFORTRAN_TRANS_DEPS)
+ fortran/resolve.o: fortran/dependency.h
  
Index: gcc/fortran/gfortran.h
===================================================================
*** gcc/fortran/gfortran.h.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/gfortran.h	2009-05-13 14:33:26.000000000 +0200
*************** typedef struct gfc_expr
*** 1164,1169 ****
--- 1164,1172 ----
  
    /* True if it is converted from Hollerith constant.  */
    unsigned int from_H : 1;
+   /* True if the expression is a call to a function that returns an array,
+      and if we have decided not to allocate temporary data for that array.  */
+   unsigned int inline_noncopying_intrinsic : 1;
  
    union
    {
Index: gcc/fortran/dependency.c
===================================================================
*** gcc/fortran/dependency.c.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/dependency.c	2009-05-13 14:33:26.000000000 +0200
*************** gfc_is_same_range (gfc_array_ref * ar1,
*** 175,180 ****
--- 175,206 ----
  }
  
  
+ /* Some array-returning intrinsics can be implemented by reusing the
+    data from one of the array arguments.  For example, TRANPOSE does
+    not necessarily need to allocate new data: it can be implemented
+    by copying the original array's descriptor and simply swapping the
+    two dimension specifications.
+ 
+    If EXPR is a call to such an intrinsic, return the argument
+    whose data can be reused, otherwise return NULL.  */
+ 
+ gfc_expr *
+ gfc_get_noncopying_intrinsic_argument (gfc_expr * expr)
+ {
+   if (expr->expr_type != EXPR_FUNCTION || !expr->value.function.isym)
+     return NULL;
+ 
+   switch (expr->value.function.isym->generic_id)
+     {
+     case GFC_ISYM_TRANSPOSE:
+       return expr->value.function.actual->expr;
+ 
+     default:
+       return NULL;
+     }
+ }
+ 
+ 
  /* Return true if the result of reference REF can only be constructed
     using a temporary array.  */
  
*************** gfc_ref_needs_temporary_p (gfc_ref *ref)
*** 214,236 ****
  }
  
  
! /* Dependency checking for direct function return by reference.
!    Returns true if the arguments of the function depend on the
!    destination.  This is considerably less conservative than other
!    dependencies because many function arguments will already be
!    copied into a temporary.  */
  
  int
! gfc_check_fncall_dependency (gfc_expr * dest, gfc_expr * fncall)
  {
!   gfc_actual_arglist *actual;
    gfc_expr *expr;
  
!   gcc_assert (dest->expr_type == EXPR_VARIABLE
! 	  && fncall->expr_type == EXPR_FUNCTION);
!   gcc_assert (fncall->rank > 0);
! 
!   for (actual = fncall->value.function.actual; actual; actual = actual->next)
      {
        expr = actual->expr;
  
--- 240,321 ----
  }
  
  
! /* Return true if array variable VAR could be passed to the same function
!    as argument EXPR without interfering with EXPR.  INTENT is the intent
!    of VAR.
! 
!    This is considerably less conservative than other dependencies
!    because many function arguments will already be copied into a
!    temporary.  */
! 
! static int
! gfc_check_argument_var_dependency (gfc_expr * var, sym_intent intent,
! 				   gfc_expr * expr)
! {
!   gcc_assert (var->expr_type == EXPR_VARIABLE);
!   gcc_assert (var->rank > 0);
! 
!   switch (expr->expr_type)
!     {
!     case EXPR_VARIABLE:
!       return (gfc_ref_needs_temporary_p (expr->ref)
! 	      || gfc_check_dependency (var, expr, NULL, 0));
! 
!     case EXPR_ARRAY:
!       return gfc_check_dependency (var, expr, NULL, 0);
! 
!     case EXPR_FUNCTION:
!       if (intent != INTENT_IN && expr->inline_noncopying_intrinsic)
! 	{
! 	  expr = gfc_get_noncopying_intrinsic_argument (expr);
! 	  return gfc_check_argument_var_dependency (var, intent, expr);
! 	}
!       return 0;
! 
!     default:
!       return 0;
!     }
! }
!   
!   
! /* Like gfc_check_argument_var_dependency, but extended to any
!    array expression OTHER, not just variables.  */
! 
! static int
! gfc_check_argument_dependency (gfc_expr * other, sym_intent intent,
! 			       gfc_expr * expr)
! {
!   switch (other->expr_type)
!     {
!     case EXPR_VARIABLE:
!       return gfc_check_argument_var_dependency (other, intent, expr);
! 
!     case EXPR_FUNCTION:
!       if (other->inline_noncopying_intrinsic)
! 	{
! 	  other = gfc_get_noncopying_intrinsic_argument (other);
! 	  return gfc_check_argument_dependency (other, INTENT_IN, expr);
! 	}
!       return 0;
! 
!     default:
!       return 0;
!     }
! }
! 
! 
! /* Like gfc_check_argument_dependency, but check all the arguments in ACTUAL.
!    FNSYM is the function being called, or NULL if not known.  */
  
  int
! gfc_check_fncall_dependency (gfc_expr * other, sym_intent intent,
! 			     gfc_symbol * fnsym, gfc_actual_arglist * actual)
  {
!   gfc_formal_arglist *formal;
    gfc_expr *expr;
  
!   formal = fnsym ? fnsym->formal : NULL;
!   for (; actual; actual = actual->next, formal = formal ? formal->next : NULL)
      {
        expr = actual->expr;
  
*************** gfc_check_fncall_dependency (gfc_expr *
*** 238,260 ****
        if (!expr)
  	continue;
  
!       /* Non-variable expressions will be allocated temporaries anyway.  */
!       switch (expr->expr_type)
! 	{
! 	case EXPR_VARIABLE:
! 	  if (!gfc_ref_needs_temporary_p (expr->ref)
! 	      && gfc_check_dependency (dest, expr, NULL, 0))
! 	    return 1;
! 	  break;
! 
! 	case EXPR_ARRAY:
! 	  if (gfc_check_dependency (dest, expr, NULL, 0))
! 	    return 1;
! 	  break;
  
! 	default:
! 	  break;
! 	}
      }
  
    return 0;
--- 323,336 ----
        if (!expr)
  	continue;
  
!       /* Skip intent(in) arguments if OTHER itself is intent(in).  */
!       if (formal
! 	  && intent == INTENT_IN
! 	  && formal->sym->attr.intent == INTENT_IN)
! 	continue;
  
!       if (gfc_check_argument_dependency (other, intent, expr))
! 	return 1;
      }
  
    return 0;
Index: gcc/fortran/dependency.h
===================================================================
*** gcc/fortran/dependency.h.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/dependency.h	2009-05-13 14:33:26.000000000 +0200
*************** Software Foundation, 51 Franklin Street,
*** 22,28 ****
  
  
  bool gfc_ref_needs_temporary_p (gfc_ref *);
! int gfc_check_fncall_dependency (gfc_expr *, gfc_expr *);
  int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int);
  int gfc_is_same_range (gfc_array_ref *, gfc_array_ref *, int, int);
  int gfc_expr_is_one (gfc_expr *, int);
--- 22,30 ----
  
  
  bool gfc_ref_needs_temporary_p (gfc_ref *);
! gfc_expr *gfc_get_noncopying_intrinsic_argument (gfc_expr *);
! int gfc_check_fncall_dependency (gfc_expr *, sym_intent, gfc_symbol *,
! 				 gfc_actual_arglist *);
  int gfc_check_dependency (gfc_expr *, gfc_expr *, gfc_expr **, int);
  int gfc_is_same_range (gfc_array_ref *, gfc_array_ref *, int, int);
  int gfc_expr_is_one (gfc_expr *, int);
Index: gcc/fortran/trans-intrinsic.c
===================================================================
*** gcc/fortran/trans-intrinsic.c.orig	2009-05-13 14:27:36.000000000 +0200
--- gcc/fortran/trans-intrinsic.c	2009-05-13 14:33:26.000000000 +0200
*************** gfc_conv_intrinsic_function (gfc_se * se
*** 3538,3544 ****
  
    name = &expr->value.function.name[2];
  
!   if (expr->rank > 0)
      {
        lib = gfc_is_intrinsic_libcall (expr);
        if (lib != 0)
--- 3538,3544 ----
  
    name = &expr->value.function.name[2];
  
!   if (expr->rank > 0 && !expr->inline_noncopying_intrinsic)
      {
        lib = gfc_is_intrinsic_libcall (expr);
        if (lib != 0)
*************** gfc_conv_intrinsic_function (gfc_se * se
*** 3767,3772 ****
--- 3767,3782 ----
        gfc_conv_intrinsic_bound (se, expr, 0);
        break;
  
+     case GFC_ISYM_TRANSPOSE:
+       if (se->ss && se->ss->useflags)
+ 	{
+ 	  gfc_conv_tmp_array_ref (se);
+ 	  gfc_advance_se_ss_chain (se);
+ 	}
+       else
+ 	gfc_conv_array_transpose (se, expr->value.function.actual->expr);
+       break;
+ 
      case GFC_ISYM_LEN:
        gfc_conv_intrinsic_len (se, expr);
        break;
openSUSE Build Service is sponsored by