]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
trans-array.c (constant_array_constructor_p): New function to determine whether an...
authorRoger Sayle <roger@eyesopen.com>
Mon, 8 Jan 2007 17:56:37 +0000 (17:56 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Mon, 8 Jan 2007 17:56:37 +0000 (17:56 +0000)
* 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.

From-SVN: r120584

gcc/fortran/ChangeLog
gcc/fortran/trans-array.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/array_constructor_14.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/vect/vect-5.f90

index f47c17205cada62942dfbe7948387e241c8c9017..5ec612c06ab33adbd9320f3680f50bfd0226f4bf 100644 (file)
@@ -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.
index b924a414d8a90b2dae93bd009eb688d88e31ae96..7eb56afa7ea8aadc30c47f9b0d51571ca37f19cf 100644 (file)
@@ -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);
index 22e47180e5bb84dac69f298861d27ad87de571b3..8da20bc382a0ab5bf2a355f1cf22136efb4ed469 100644 (file)
@@ -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 (file)
index 0000000..f2f89cd
--- /dev/null
@@ -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" } }
index ff71b8a3be79e81aad3e8818f0992d416ef4cf33..90b0f3257750bce4a895989cbae8deac3ecec1eb 100644 (file)
@@ -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