From f5bfd4fa511a29233c6476adbf928f996cf95065 Mon Sep 17 00:00:00 2001
From: sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Mon, 8 Jan 2007 17:56:37 +0000
Subject: [PATCH] 	* trans-array.c (constant_array_constructor_p): New
 function to 	determine whether an array constructor consists only of
 constant 	elements, and if so return it's size. 
 (gfc_build_constant_array_constructor): Construct a statically 
 initialized gfortran array for a given EXPR_ARRAY. 
 (gfc_trans_constant_array_constructor): Efficiently scalarize 	a constant
 array constructor. 	(gfc_trans_array_constructor):  Tidy up use of
 CONST_STRING. 	Special case scalarization of constant array constructors, all
 of 	whose elements are specified, using constant_array_constructor_p 
 and gfc_trans_constant_array_constructor. 
 (gfc_conv_scalarized_array_ref): Check whetger info->offset is zero 	before
 adding it to index, to avoid creating a NON_LVALUE_EXPR.

	* gfortran.dg/array_constructor_14.f90: New test case.
	* gfortran.dg/vect/vect-5.f90: Update test for improved alignment.



git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@120584 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/fortran/ChangeLog                         |  16 ++
 gcc/fortran/trans-array.c                     | 143 +++++++++++++++++-
 gcc/testsuite/ChangeLog                       |   5 +
 .../gfortran.dg/array_constructor_14.f90      |  15 ++
 gcc/testsuite/gfortran.dg/vect/vect-5.f90     |   2 +-
 5 files changed, 173 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/array_constructor_14.f90

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index f47c17205cad..5ec612c06ab3 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,19 @@
+2007-01-08  Roger Sayle  <roger@eyesopen.com>
+
+	* trans-array.c (constant_array_constructor_p): New function to
+	determine whether an array constructor consists only of constant
+	elements, and if so return it's size.
+	(gfc_build_constant_array_constructor): Construct a statically
+	initialized gfortran array for a given EXPR_ARRAY.
+	(gfc_trans_constant_array_constructor): Efficiently scalarize
+	a constant array constructor.
+	(gfc_trans_array_constructor):  Tidy up use of CONST_STRING.
+	Special case scalarization of constant array constructors, all of
+	whose elements are specified, using constant_array_constructor_p 
+	and gfc_trans_constant_array_constructor.
+	(gfc_conv_scalarized_array_ref): Check whetger info->offset is zero
+	before adding it to index, to avoid creating a NON_LVALUE_EXPR.
+
 2007-01-08  Kazu Hirata  <kazu@codesourcery.com>
 
 	gfortran.texi: Fix typos.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index b924a414d8a9..7eb56afa7ea8 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -1463,6 +1463,119 @@ get_array_ctor_strlen (gfc_constructor * c, tree * len)
   return is_const;
 }
 
+/* Check whether the array constructor C consists entirely of constant
+   elements, and if so returns the number of those elements, otherwise
+   return zero.  Note, an empty or NULL array constructor returns zero.  */
+
+static unsigned HOST_WIDE_INT
+constant_array_constructor_p (gfc_constructor * c)
+{
+  unsigned HOST_WIDE_INT nelem = 0;
+
+  while (c)
+    {
+      if (c->iterator
+	  || c->expr->rank > 0
+	  || c->expr->expr_type != EXPR_CONSTANT)
+	return 0;
+      c = c->next;
+      nelem++;
+    }
+  return nelem;
+}
+
+
+/* Given EXPR, the constant array constructor specified by an EXPR_ARRAY,
+   and the tree type of it's elements, TYPE, return a static constant
+   variable that is compile-time initialized.  */
+
+static tree
+gfc_build_constant_array_constructor (gfc_expr * expr, tree type)
+{
+  tree tmptype, list, init, tmp;
+  HOST_WIDE_INT nelem;
+  gfc_constructor *c;
+  gfc_array_spec as;
+  gfc_se se;
+
+
+  /* First traverse the constructor list, converting the constants
+     to tree to build an initializer.  */
+  nelem = 0;
+  list = NULL_TREE;
+  c = expr->value.constructor;
+  while (c)
+    {
+      gfc_init_se (&se, NULL);
+      gfc_conv_constant (&se, c->expr);
+      if (c->expr->ts.type == BT_CHARACTER
+	  && POINTER_TYPE_P (type))
+	se.expr = gfc_build_addr_expr (pchar_type_node, se.expr);
+      list = tree_cons (NULL_TREE, se.expr, list);
+      c = c->next;
+      nelem++;
+    }
+
+  /* Next detemine the tree type for the array.  We use the gfortran
+     front-end's gfc_get_nodesc_array_type in order to create a suitable
+     GFC_ARRAY_TYPE_P that may be used by the scalarizer.  */
+
+  memset (&as, 0, sizeof (gfc_array_spec));
+
+  as.rank = 1;
+  as.type = AS_EXPLICIT;
+  as.lower[0] = gfc_int_expr (0);
+  as.upper[0] = gfc_int_expr (nelem - 1);
+  tmptype = gfc_get_nodesc_array_type (type, &as, 3);
+
+  init = build_constructor_from_list (tmptype, nreverse (list));
+
+  TREE_CONSTANT (init) = 1;
+  TREE_INVARIANT (init) = 1;
+  TREE_STATIC (init) = 1;
+
+  tmp = gfc_create_var (tmptype, "A");
+  TREE_STATIC (tmp) = 1;
+  TREE_CONSTANT (tmp) = 1;
+  TREE_INVARIANT (tmp) = 1;
+  TREE_READONLY (tmp) = 1;
+  DECL_INITIAL (tmp) = init;
+
+  return tmp;
+}
+
+
+/* Translate a constant EXPR_ARRAY array constructor for the scalarizer.
+   This mostly initializes the scalarizer state info structure with the
+   appropriate values to directly use the array created by the function
+   gfc_build_constant_array_constructor.  */
+
+static void
+gfc_trans_constant_array_constructor (gfc_loopinfo * loop,
+				      gfc_ss * ss, tree type)
+{
+  gfc_ss_info *info;
+  tree tmp;
+
+  tmp = gfc_build_constant_array_constructor (ss->expr, type);
+
+  info = &ss->data.info;
+
+  info->descriptor = tmp;
+  info->data = build_fold_addr_expr (tmp);
+  info->offset = fold_build1 (NEGATE_EXPR, gfc_array_index_type,
+			      loop->from[0]);
+
+  info->delta[0] = gfc_index_zero_node;
+  info->start[0] = gfc_index_zero_node;
+  info->end[0] = gfc_index_zero_node;
+  info->stride[0] = gfc_index_one_node;
+  info->dim[0] = 0;
+
+  if (info->dimen > loop->temp_dim)
+    loop->temp_dim = info->dimen;
+}
+
 
 /* Array constructors are handled by constructing a temporary, then using that
    within the scalarization loop.  This is not optimal, but seems by far the
@@ -1476,7 +1589,6 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
   tree offsetvar;
   tree desc;
   tree type;
-  bool const_string;
   bool dynamic;
 
   ss->data.info.dimen = loop->dimen;
@@ -1484,7 +1596,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
   c = ss->expr->value.constructor;
   if (ss->expr->ts.type == BT_CHARACTER)
     {
-      const_string = get_array_ctor_strlen (c, &ss->string_length);
+      bool const_string = get_array_ctor_strlen (c, &ss->string_length);
       if (!ss->string_length)
 	gfc_todo_error ("complex character array constructors");
 
@@ -1493,10 +1605,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
 	type = build_pointer_type (type);
     }
   else
-    {
-      const_string = TRUE;
-      type = gfc_typenode_for_spec (&ss->expr->ts);
-    }
+    type = gfc_typenode_for_spec (&ss->expr->ts);
 
   /* See if the constructor determines the loop bounds.  */
   dynamic = false;
@@ -1518,6 +1627,25 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
       mpz_clear (size);
     }
 
+  /* Special case constant array constructors.  */
+  if (!dynamic
+      && loop->dimen == 1
+      && INTEGER_CST_P (loop->from[0])
+      && INTEGER_CST_P (loop->to[0]))
+    {
+      unsigned HOST_WIDE_INT nelem = constant_array_constructor_p (c);
+      if (nelem > 0)
+	{
+	  tree diff = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+				   loop->to[0], loop->from[0]);
+	  if (compare_tree_int (diff, nelem - 1) == 0)
+	    {
+	      gfc_trans_constant_array_constructor (loop, ss, type);
+	      return;
+	    }
+	}
+    }
+
   gfc_trans_create_temp_array (&loop->pre, &loop->post, loop, &ss->data.info,
 			       type, dynamic, true, false, false);
 
@@ -2045,7 +2173,8 @@ gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar)
 				       info->stride0);
   /* Add the offset for this dimension to the stored offset for all other
      dimensions.  */
-  index = fold_build2 (PLUS_EXPR, gfc_array_index_type, index, info->offset);
+  if (!integer_zerop (info->offset))
+    index = fold_build2 (PLUS_EXPR, gfc_array_index_type, index, info->offset);
 
   tmp = build_fold_indirect_ref (info->data);
   se->expr = gfc_build_array_ref (tmp, index);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 22e47180e5bb..8da20bc382a0 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-01-08  Roger Sayle  <roger@eyesopen.com>
+
+	* gfortran.dg/array_constructor_14.f90: New test case.
+	* gfortran.dg/vect/vect-5.f90: Update test for improved alignment.
+
 2007-01-08  Richard Guenther  <rguenther@suse.de>
 
 	PR tree-optimization/23603
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_14.f90 b/gcc/testsuite/gfortran.dg/array_constructor_14.f90
new file mode 100644
index 000000000000..f2f89cd04307
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/array_constructor_14.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-O2 -fdump-tree-original" }
+
+subroutine foo(x)
+  integer :: x(4)
+  x(:) = (/ 3, 1, 4, 1 /)
+end subroutine
+
+subroutine bar(x)
+  integer :: x(4)
+  x = (/ 3, 1, 4, 1 /)
+end subroutine
+
+! { dg-final { scan-tree-dump-times "data" 0 "original" } }
+! { dg-final { cleanup-tree-dump "original" } }
diff --git a/gcc/testsuite/gfortran.dg/vect/vect-5.f90 b/gcc/testsuite/gfortran.dg/vect/vect-5.f90
index ff71b8a3be79..90b0f3257750 100644
--- a/gcc/testsuite/gfortran.dg/vect/vect-5.f90
+++ b/gcc/testsuite/gfortran.dg/vect/vect-5.f90
@@ -37,7 +37,7 @@
 
 ! { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect"  } }
 ! { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 1 "vect" { xfail { vect_no_align } } } }
-! { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 2 "vect" { xfail { vect_no_align } } } }
+! { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" { xfail { vect_no_align } } } }
 ! { dg-final { scan-tree-dump-times "Alignment of access forced using versioning." 3 "vect" { target { ilp32 && vect_no_align } } } }
 
 ! We also expect to vectorize one loop for lp64 targets that support 
-- 
GitLab