Commit b01e2f88 by Roger Sayle Committed by Roger Sayle

dependency.c (gfc_full_array_ref_p): Check that ref->next is NULL, i.e.


	* dependency.c (gfc_full_array_ref_p): Check that ref->next is NULL,
	i.e. that the ARRAY_REF doesn't mention components.
	* trans-array.c (gfc_constant_array_constructor_p): Export external
	function renamed from constant_array_constructor_p.
	(gfc_build_constant_array_constructor): Export.
	(gfc_trans_array_constructor): Update call to the renamed function
	constant_array_constructor_p.
	* trans-array.h (gfc_constant_array_constructor_p): Prototype here.
	(gfc_build_constant_array_constructor): Likewise.
	* trans-expr.c (gfc_build_memcpy_call): New helper function split
	out from gfc_trans_array_copy.
	(gfc_trans_array_copy): Use gfc_build_memcpy_call.
	(gfc_trans_array_constructor_copy): New function to optimize
	assigning an entire array from a constant array constructor.
	(gfc_trans_assignment): Call gfc_trans_array_constructor_copy
	when appropriate.

	* gfortran.dg/array_memcpy_3.f90: New test case.
	* gfortran.dg/vect/vect-5.f90: Update vectorized loop count.

From-SVN: r121010
parent 0eadc091
2007-01-20 Roger Sayle <roger@eyesopen.com> 2007-01-20 Roger Sayle <roger@eyesopen.com>
* dependency.c (gfc_full_array_ref_p): Check that ref->next is NULL,
i.e. that the ARRAY_REF doesn't mention components.
* trans-array.c (gfc_constant_array_constructor_p): Export external
function renamed from constant_array_constructor_p.
(gfc_build_constant_array_constructor): Export.
(gfc_trans_array_constructor): Update call to the renamed function
constant_array_constructor_p.
* trans-array.h (gfc_constant_array_constructor_p): Prototype here.
(gfc_build_constant_array_constructor): Likewise.
* trans-expr.c (gfc_build_memcpy_call): New helper function split
out from gfc_trans_array_copy.
(gfc_trans_array_copy): Use gfc_build_memcpy_call.
(gfc_trans_array_constructor_copy): New function to optimize
assigning an entire array from a constant array constructor.
(gfc_trans_assignment): Call gfc_trans_array_constructor_copy
when appropriate.
2007-01-20 Roger Sayle <roger@eyesopen.com>
* trans-intrinsic.c (gfc_conv_intrinsic_sign): New branchless * trans-intrinsic.c (gfc_conv_intrinsic_sign): New branchless
implementation for the SIGN intrinsic with integral operands. implementation for the SIGN intrinsic with integral operands.
(gfc_conv_intrinsic_minmax): Fix whitespace. (gfc_conv_intrinsic_minmax): Fix whitespace.
......
...@@ -1109,6 +1109,8 @@ gfc_full_array_ref_p (gfc_ref *ref) ...@@ -1109,6 +1109,8 @@ gfc_full_array_ref_p (gfc_ref *ref)
return true; return true;
if (ref->u.ar.type != AR_SECTION) if (ref->u.ar.type != AR_SECTION)
return false; return false;
if (ref->next)
return false;
for (i = 0; i < ref->u.ar.dimen; i++) for (i = 0; i < ref->u.ar.dimen; i++)
{ {
......
...@@ -1467,8 +1467,8 @@ get_array_ctor_strlen (gfc_constructor * c, tree * len) ...@@ -1467,8 +1467,8 @@ get_array_ctor_strlen (gfc_constructor * c, tree * len)
elements, and if so returns the number of those elements, otherwise elements, and if so returns the number of those elements, otherwise
return zero. Note, an empty or NULL array constructor returns zero. */ return zero. Note, an empty or NULL array constructor returns zero. */
static unsigned HOST_WIDE_INT unsigned HOST_WIDE_INT
constant_array_constructor_p (gfc_constructor * c) gfc_constant_array_constructor_p (gfc_constructor * c)
{ {
unsigned HOST_WIDE_INT nelem = 0; unsigned HOST_WIDE_INT nelem = 0;
...@@ -1489,7 +1489,7 @@ constant_array_constructor_p (gfc_constructor * c) ...@@ -1489,7 +1489,7 @@ constant_array_constructor_p (gfc_constructor * c)
and the tree type of it's elements, TYPE, return a static constant and the tree type of it's elements, TYPE, return a static constant
variable that is compile-time initialized. */ variable that is compile-time initialized. */
static tree tree
gfc_build_constant_array_constructor (gfc_expr * expr, tree type) gfc_build_constant_array_constructor (gfc_expr * expr, tree type)
{ {
tree tmptype, list, init, tmp; tree tmptype, list, init, tmp;
...@@ -1633,7 +1633,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss) ...@@ -1633,7 +1633,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
&& INTEGER_CST_P (loop->from[0]) && INTEGER_CST_P (loop->from[0])
&& INTEGER_CST_P (loop->to[0])) && INTEGER_CST_P (loop->to[0]))
{ {
unsigned HOST_WIDE_INT nelem = constant_array_constructor_p (c); unsigned HOST_WIDE_INT nelem = gfc_constant_array_constructor_p (c);
if (nelem > 0) if (nelem > 0)
{ {
tree diff = fold_build2 (MINUS_EXPR, gfc_array_index_type, tree diff = fold_build2 (MINUS_EXPR, gfc_array_index_type,
......
...@@ -133,3 +133,7 @@ tree gfc_conv_descriptor_ubound (tree, tree); ...@@ -133,3 +133,7 @@ tree gfc_conv_descriptor_ubound (tree, tree);
/* Add pre-loop scalarization code for intrinsic functions which require /* Add pre-loop scalarization code for intrinsic functions which require
special handling. */ special handling. */
void gfc_add_intrinsic_ss_code (gfc_loopinfo *, gfc_ss *); void gfc_add_intrinsic_ss_code (gfc_loopinfo *, gfc_ss *);
/* Functions for constant array constructor processing. */
unsigned HOST_WIDE_INT gfc_constant_array_constructor_p (gfc_constructor *);
tree gfc_build_constant_array_constructor (gfc_expr *, tree);
...@@ -3579,6 +3579,37 @@ gfc_trans_zero_assign (gfc_expr * expr) ...@@ -3579,6 +3579,37 @@ gfc_trans_zero_assign (gfc_expr * expr)
return fold_convert (void_type_node, tmp); return fold_convert (void_type_node, tmp);
} }
/* Helper for gfc_trans_array_copy and gfc_trans_array_constructor_copy
that constructs the call to __builtin_memcpy. */
static tree
gfc_build_memcpy_call (tree dst, tree src, tree len)
{
tree tmp, args;
/* Convert arguments to the correct types. */
if (!POINTER_TYPE_P (TREE_TYPE (dst)))
dst = gfc_build_addr_expr (pvoid_type_node, dst);
else
dst = fold_convert (pvoid_type_node, dst);
if (!POINTER_TYPE_P (TREE_TYPE (src)))
src = gfc_build_addr_expr (pvoid_type_node, src);
else
src = fold_convert (pvoid_type_node, src);
len = fold_convert (size_type_node, len);
/* Construct call to __builtin_memcpy. */
args = build_tree_list (NULL_TREE, len);
args = tree_cons (NULL_TREE, src, args);
args = tree_cons (NULL_TREE, dst, args);
tmp = build_function_call_expr (built_in_decls[BUILT_IN_MEMCPY], args);
return fold_convert (void_type_node, tmp);
}
/* Try to efficiently translate dst(:) = src(:). Return NULL if this /* Try to efficiently translate dst(:) = src(:). Return NULL if this
can't be done. EXPR1 is the destination/lhs and EXPR2 is the can't be done. EXPR1 is the destination/lhs and EXPR2 is the
source/rhs, both are gfc_full_array_ref_p which have been checked for source/rhs, both are gfc_full_array_ref_p which have been checked for
...@@ -3589,7 +3620,6 @@ gfc_trans_array_copy (gfc_expr * expr1, gfc_expr * expr2) ...@@ -3589,7 +3620,6 @@ gfc_trans_array_copy (gfc_expr * expr1, gfc_expr * expr2)
{ {
tree dst, dlen, dtype; tree dst, dlen, dtype;
tree src, slen, stype; tree src, slen, stype;
tree tmp, args;
dst = gfc_get_symbol_decl (expr1->symtree->n.sym); dst = gfc_get_symbol_decl (expr1->symtree->n.sym);
src = gfc_get_symbol_decl (expr2->symtree->n.sym); src = gfc_get_symbol_decl (expr2->symtree->n.sym);
...@@ -3622,25 +3652,53 @@ gfc_trans_array_copy (gfc_expr * expr1, gfc_expr * expr2) ...@@ -3622,25 +3652,53 @@ gfc_trans_array_copy (gfc_expr * expr1, gfc_expr * expr2)
if (!tree_int_cst_equal (slen, dlen)) if (!tree_int_cst_equal (slen, dlen))
return NULL_TREE; return NULL_TREE;
/* Convert arguments to the correct types. */ return gfc_build_memcpy_call (dst, src, dlen);
if (!POINTER_TYPE_P (TREE_TYPE (dst))) }
dst = gfc_build_addr_expr (pvoid_type_node, dst);
else
dst = fold_convert (pvoid_type_node, dst);
if (!POINTER_TYPE_P (TREE_TYPE (src)))
src = gfc_build_addr_expr (pvoid_type_node, src);
else
src = fold_convert (pvoid_type_node, src);
dlen = fold_convert (size_type_node, dlen); /* Try to efficiently translate array(:) = (/ ... /). Return NULL if
this can't be done. EXPR1 is the destination/lhs for which
gfc_full_array_ref_p is true, and EXPR2 is the source/rhs. */
/* Construct call to __builtin_memcpy. */ static tree
args = build_tree_list (NULL_TREE, dlen); gfc_trans_array_constructor_copy (gfc_expr * expr1, gfc_expr * expr2)
args = tree_cons (NULL_TREE, src, args); {
args = tree_cons (NULL_TREE, dst, args); unsigned HOST_WIDE_INT nelem;
tmp = build_function_call_expr (built_in_decls[BUILT_IN_MEMCPY], args); tree dst, dtype;
return fold_convert (void_type_node, tmp); tree src, stype;
tree len;
nelem = gfc_constant_array_constructor_p (expr2->value.constructor);
if (nelem == 0)
return NULL_TREE;
dst = gfc_get_symbol_decl (expr1->symtree->n.sym);
dtype = TREE_TYPE (dst);
if (POINTER_TYPE_P (dtype))
dtype = TREE_TYPE (dtype);
if (!GFC_ARRAY_TYPE_P (dtype))
return NULL_TREE;
/* Determine the lengths of the array. */
len = GFC_TYPE_ARRAY_SIZE (dtype);
if (!len || TREE_CODE (len) != INTEGER_CST)
return NULL_TREE;
/* Confirm that the constructor is the same size. */
if (compare_tree_int (len, nelem) != 0)
return NULL_TREE;
len = fold_build2 (MULT_EXPR, gfc_array_index_type, len,
TYPE_SIZE_UNIT (gfc_get_element_type (dtype)));
stype = gfc_typenode_for_spec (&expr2->ts);
src = gfc_build_constant_array_constructor (expr2, stype);
stype = TREE_TYPE (src);
if (POINTER_TYPE_P (stype))
stype = TREE_TYPE (stype);
return gfc_build_memcpy_call (dst, src, len);
} }
...@@ -3870,6 +3928,18 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag) ...@@ -3870,6 +3928,18 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
return tmp; return tmp;
} }
/* Special case initializing an array from a constant array constructor. */
if (expr1->expr_type == EXPR_VARIABLE
&& copyable_array_p (expr1)
&& gfc_full_array_ref_p (expr1->ref)
&& expr2->expr_type == EXPR_ARRAY
&& gfc_compare_types (&expr1->ts, &expr2->ts))
{
tmp = gfc_trans_array_constructor_copy (expr1, expr2);
if (tmp)
return tmp;
}
/* Fallback to the scalarizer to generate explicit loops. */ /* Fallback to the scalarizer to generate explicit loops. */
return gfc_trans_assignment_1 (expr1, expr2, init_flag); return gfc_trans_assignment_1 (expr1, expr2, init_flag);
} }
......
2007-01-20 Roger Sayle <roger@eyesopen.com> 2007-01-20 Roger Sayle <roger@eyesopen.com>
* gfortran.dg/array_memcpy_3.f90: New test case.
* gfortran.dg/vect/vect-5.f90: Update vectorized loop count.
2007-01-20 Roger Sayle <roger@eyesopen.com>
Brooks Moses <brooks.moses@codesourcery.com> Brooks Moses <brooks.moses@codesourcery.com>
Francois-Xavier Coudert <coudert@clipper.ens.fr> Francois-Xavier Coudert <coudert@clipper.ens.fr>
! { 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 "memcpy" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } }
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
stop stop
end end
! { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } ! { dg-final { scan-tree-dump-times "vectorized 1 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 "Alignment of access forced using peeling" 1 "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 "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 } } } } ! { dg-final { scan-tree-dump-times "Alignment of access forced using versioning." 3 "vect" { target { ilp32 && vect_no_align } } } }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment