This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Middle-end arrays, forward-ported to trunk (again)


This forward-ports the middle-end array patch.  Patch status is the
same as with the last forward-port from 2009 - the scalarizer cannot
deal with control flow and it cannot insert temporaries when
required (so it operates in a mode that requires the frontend to
insert those that are necessary).

Expected FAILs of the C/C++ frontend-hack testcases are

FAIL: g++.dg/tree-ssa/mea-1.C (test for excess errors)
FAIL: gcc.dg/mea-1.c (test for excess errors)

the gimplifier isn't able to properly translate the C/C++ builtin hack

FAIL: g++.dg/tree-ssa/mea-10.C (internal compiler error)
FAIL: g++.dg/tree-ssa/mea-10.C (test for excess errors)
FAIL: gcc.dg/mea-15.c (internal compiler error)
FAIL: gcc.dg/mea-15.c (test for excess errors)

aforementioned case of not handling control flow (both testcases
simulating U(:) = WHERE (U(:) < 0, 0) which would be handled
if the scalarizer sees an if-converted COND_EXPR).

Not further tested (I'll try bootstrapping now).  I didn't touch
the ChangeLog.

Disclaimer: During the London Gathering we discussed how to eventually
move forward with respect to Fortran using middle-end arrays.  This is
step1, forward-port the existing patch.

Hints on where I could lower simple fortran array expressions from
the frontend are appreciated.  Simple first example:

  subroutine copy (dst, src, ni, nj)
    integer, intent(in) :: ni, nj
    double precision, intent(out) :: dst(ni, nj)
    double precision, intent(in)  :: src(ni, nj)
    dst = src
  end subroutine copy

If I have a first Fortran bit working I will probably disentangle
the C/C++ frontend hacks and put the rest on a branch.

Thanks,
Richard.

2008-04-11  Richard Guenther  <rguenther@suse.de>

	* builtin-attrs.def (ATTR_COVARIANTRETURN): Add.
	(ATTR_NOTHROW_TYPEGENERIC): Likewise.
	(ATTR_NOTHROW_TYPEGENERIC_COVARIANTRETURN): Likewise.
	* builtins.def (BUILT_IN_ARRAY_SELECT): New builtin function.
	(BUILT_IN_ARRAY_STORE): Likewise.
	(BUILT_IN_ARRAY_IDX): Likewise.
	(BUILT_IN_ARRAY_RIDX): Likewise.
	(BUILT_IN_ARRAY_DELTA): Likewise.
	* gimplify.c (internal_get_tmp_var): Mark array temporaries
	as gimple register.
	(gimple_add_tmp_var): Do not require constant size for array
	temporaries.
	(maybe_with_size_expr): Do not wrap VLA_VIEW_EXPR or VLA_RIDX_EXPR
	inside WITH_SIZE_EXPR.
	(get_array_arg_type): New helper function.
	(vla_to_vla_view_expr): Likewise.
	(lower_builtin_array_expr): Helper for gimplifying array builtins
	to VLA tree expressions.
	(gimplify_call_expr): Call it.
	(gimplify_modify_expr): Do not wrap copies of array temporaries
	inside WITH_SIZE_EXPR.  Do not lower copies of array temporaries
	to memcpy calls.
	(gimplify_expr): Handle VLA_VIEW_EXPR, VLA_IDX_EXPR, VLA_RIDX_EXPR
	and VLA_DELTA_EXPR.
	* tree-gimple.c (is_gimple_formal_tmp_rhs): Allow VLA_IDX_EXPR,
	VLA_RIDX_EXPR and VLA_DELTA_EXPR.
	(is_gimple_lvalue): Allow VLA_VIEW_EXPR.
	(is_gimple_reg_type): Allow arrays.
	(is_gimple_reg): Likewise.
	* cfgexpand.c (estimated_stack_frame_size): Gimple registers do
	not consume stack space.
	* tree-cfg.c (verify_gimple_expr): Handle WITH_SIZE_EXPR,
	VLA_VIEW_EXPR, VLA_IDX_EXPR, VLA_RIDX_EXPR and VLA_DELTA_EXPR.
	* tree-inline.c (estimate_num_insns_1): Handle VLA_IDX_EXPR
	and VLA_RIDX_EXPR.  Treat VLA_VIEW_EXPR and VLA_DELTA_EXPR
	as expensive as OMP stuff.
	* tree-pretty-print.c (dump_generic_node): Handle VLA_VIEW_EXPR,
	VLA_IDX_EXPR, VLA_RIDX_EXPR and VLA_DELTA_EXPR.
	* tree.def (VLA_VIEW_EXPR): New tree code.
	(VLA_IDX_EXPR): Likewise.
	(VLA_RIDX_EXPR): Likewise.
	(VLA_DELTA_EXPR): Likewise.
	* tree-ssa-operands.c (get_expr_operands): Handle them all.
	* tree-ssa-sccvn.c (visit_use): Handle only calls like calls.
	* tree-ssa-sink.c (is_hidden_global_store): VLA_VIEW_EXPR is one.
	* ipa-pure-const.c (check_tree): Look int VLA_VIEW_EXPRs VLA
	argument.
	* tree-dfa.c (refs_may_alias_p): Allow VLA_VIEW_EXPR.
	* tree-sra.c (maybe_lookup_element_for_expr): Make sure to
	not scalarize arrays used in VLA_VIEW_EXPR.
	(sra_walk_expr): Likewise.

	* Makefile.in (OBJS-common): Add tree-lower-arrays.o.
	(tree-lower-arrays.o): New target.
	* tree-lower-arrays.c: New file.
	* passes.c (init_optimization_passes): Schedule pass_arrlower
	before loop header copying.
	* timevar.def (TV_TREE_ARRLOWER): Add.
	* tree-pass.h (pass_arrlower): Declare.

	* c-common.c (handle_covariant_return_attribute): New function.
	(c_common_attributes): Add covariant return attribute.
	* c-typeck.c (convert_arguments): Allow any argument if the
	function is type generic.
	(convert_for_assignment): Allow assignments from functions
	with covariant return type.

	cp/
	* call.c (resolve_args): Allow arguments from functions with
	covariant return type.
	* typeck.c (convert_for_assignment): Allow assignments from
	functions with covariant return type.

	* gcc.dg/mea-*.c: New testcases.
	* g++.dg/tree-ssa/mea-*.C: Likewise.

Index: trunk/gcc/builtins.def
===================================================================
*** trunk.orig/gcc/builtins.def	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/builtins.def	2011-06-21 13:15:05.000000000 +0200
*************** DEF_EXT_LIB_BUILTIN    (BUILT_IN_PRINTF_
*** 742,747 ****
--- 742,754 ----
  DEF_EXT_LIB_BUILTIN    (BUILT_IN_VFPRINTF_CHK, "__vfprintf_chk", BT_FN_INT_FILEPTR_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_3_0)
  DEF_EXT_LIB_BUILTIN    (BUILT_IN_VPRINTF_CHK, "__vprintf_chk", BT_FN_INT_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_2_0)
  
+ /* Array expressions.  */
+ DEF_GCC_BUILTIN (BUILT_IN_ARRAY_SELECT, "array_select", BT_FN_PTR_VAR, ATTR_NOTHROW_TYPEGENERIC)
+ DEF_GCC_BUILTIN (BUILT_IN_ARRAY_STORE, "array_store", BT_FN_VOID_VAR, ATTR_NOTHROW_TYPEGENERIC)
+ DEF_GCC_BUILTIN (BUILT_IN_ARRAY_IDX, "array_idx", BT_FN_VOID_VAR, ATTR_NOTHROW_TYPEGENERIC_COVARIANTRETURN)
+ DEF_GCC_BUILTIN (BUILT_IN_ARRAY_RIDX, "array_ridx", BT_FN_VOID_VAR, ATTR_NOTHROW_TYPEGENERIC_COVARIANTRETURN)
+ DEF_GCC_BUILTIN (BUILT_IN_ARRAY_DELTA, "array_delta", BT_FN_VOID_VAR, ATTR_NOTHROW_TYPEGENERIC_COVARIANTRETURN)
+ 
  /* Profiling hooks.  */
  DEF_BUILTIN (BUILT_IN_PROFILE_FUNC_ENTER, "__cyg_profile_func_enter", BUILT_IN_NORMAL, BT_FN_VOID_PTR_PTR, BT_LAST,
  	     false, false, false, ATTR_NULL, true, true)
Index: trunk/gcc/gimplify.c
===================================================================
*** trunk.orig/gcc/gimplify.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/gimplify.c	2011-06-21 13:39:18.000000000 +0200
*************** internal_get_tmp_var (tree val, gimple_s
*** 583,589 ****
  
    if (is_formal
        && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
! 	  || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE))
      DECL_GIMPLE_REG_P (t) = 1;
  
    mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
--- 583,591 ----
  
    if (is_formal
        && (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
! 	  || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE
! 	  || TREE_CODE (val) == VLA_RIDX_EXPR
! 	  || TREE_CODE (val) == VLA_VIEW_EXPR))
      DECL_GIMPLE_REG_P (t) = 1;
  
    mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
*************** gimple_add_tmp_var (tree tmp)
*** 706,712 ****
    /* Later processing assumes that the object size is constant, which might
       not be true at this point.  Force the use of a constant upper bound in
       this case.  */
!   if (!host_integerp (DECL_SIZE_UNIT (tmp), 1))
      force_constant_size (tmp);
  
    DECL_CONTEXT (tmp) = current_function_decl;
--- 708,715 ----
    /* Later processing assumes that the object size is constant, which might
       not be true at this point.  Force the use of a constant upper bound in
       this case.  */
!   if (!host_integerp (DECL_SIZE_UNIT (tmp), 1)
!       && TREE_CODE (TREE_TYPE (tmp)) != ARRAY_TYPE)
      force_constant_size (tmp);
  
    DECL_CONTEXT (tmp) = current_function_decl;
*************** maybe_with_size_expr (tree *expr_p)
*** 2227,2232 ****
--- 2230,2241 ----
        || type == error_mark_node)
      return;
  
+   /* If this is already wrapped in a VLA_VIEW_EXPR, we don't need another
+      WITH_SIZE_EXPR here.  */
+   if (TREE_CODE (expr) == VLA_VIEW_EXPR
+       || TREE_CODE (expr) == VLA_RIDX_EXPR)
+     return;
+ 
    /* If the size isn't known or is a constant, we have nothing to do.  */
    size = TYPE_SIZE_UNIT (type);
    if (!size || TREE_CODE (size) == INTEGER_CST)
*************** gimplify_arg (tree *arg_p, gimple_seq *p
*** 2283,2288 ****
--- 2292,2635 ----
    return gimplify_expr (arg_p, pre_p, NULL, test, fb);
  }
  
+ static bool
+ is_gimple_reg_or_invariant_rhs (tree t)
+ {
+   return is_gimple_reg (t) || is_gimple_min_invariant (t);
+ }
+ 
+ /* Get the innermost type in the sequence of conversions and offsetting.  */
+ 
+ static tree
+ get_array_arg_type (tree arg)
+ {
+   if ((TREE_CODE (arg) == NOP_EXPR
+        || TREE_CODE (arg) == CONVERT_EXPR)
+       && (!POINTER_TYPE_P (TREE_TYPE (arg))
+ 	  || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != ARRAY_TYPE))
+     return get_array_arg_type (TREE_OPERAND (arg, 0));
+ 
+   if (TREE_CODE (arg) == POINTER_PLUS_EXPR
+       || TREE_CODE (arg) == ARRAY_REF)
+     return get_array_arg_type (TREE_OPERAND (arg, 0));
+ 
+   if (TREE_CODE (arg) == ADDR_EXPR)
+     {
+       tree type = get_array_arg_type (TREE_OPERAND (arg, 0));
+       return build_pointer_type (type);
+     }
+ 
+   return TREE_TYPE (arg);
+ }
+ 
+ /* Build a VLA_VIEW_EXPR from a VLA array object, making strides and
+    extents exposed via operands of that expression.  */
+ 
+ static tree
+ vla_to_vla_view_expr (tree vla)
+ {
+   tree elt_type, type, atypes[16];
+   tree expr, stride;
+   unsigned dim = 0, i;
+ 
+   type = TREE_TYPE (vla);
+   while (TREE_CODE (type) == ARRAY_TYPE)
+     {
+       atypes[dim] = type;
+       type = TREE_TYPE (type);
+       ++dim;
+     }
+   elt_type = type;
+ 
+   expr = build_vl_exp (VLA_VIEW_EXPR, 2 + 2 * dim);
+   TREE_TYPE (expr) = TREE_TYPE (vla);
+   TREE_OPERAND (expr, 1) = vla;
+ 
+   /* Now extract stride and extent information.  */
+   stride = size_one_node;
+   for (i = 0; i < dim; ++i)
+     {
+       tree extent, maxi, mini;
+       type = atypes[dim - i - 1];
+       mini = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
+       maxi = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+       extent = fold_build2 (MINUS_EXPR, TREE_TYPE (maxi), maxi, mini);
+       extent = fold_build2 (PLUS_EXPR, TREE_TYPE (extent), extent,
+ 			    build_int_cst (TREE_TYPE (extent), 1));
+       TREE_OPERAND (expr, 2 + 2 * i) = extent;
+       TREE_OPERAND (expr, 3 + 2 * i) = stride;
+ 
+       stride = size_binop (MULT_EXPR, stride,
+ 			   size_binop (EXACT_DIV_EXPR,
+ 				       TYPE_SIZE_UNIT (atypes[dim - i - 1]),
+ 				       TYPE_SIZE_UNIT (elt_type)));
+     }
+ 
+   return expr;
+ }
+ 
+ /* Lower the CALL_EXPR node pointed to by EXPR_P.  PRE_P points to the
+    list where side effects that must happen before *EXPR_P should be stored.
+    WANT_VALUE is true if the result of the call is desired.  */
+ 
+ static enum gimplify_status
+ lower_builtin_array_expr (tree *expr_p, gimple_seq *pre_p,
+ 			  bool want_value ATTRIBUTE_UNUSED)
+ {
+   tree decl = get_callee_fndecl (*expr_p);
+   enum gimplify_status ret = GS_OK;
+   int i, nargs = call_expr_nargs (*expr_p);
+   tree arg0, arg0type, arg1, arg1type, arg2, arg2type;
+ 
+   /* Convert arguments back to their natural pointer type.  */
+   for (i = 0; i < nargs; ++i)
+     {
+       tree *argp = &CALL_EXPR_ARG (*expr_p, i);
+       if (POINTER_TYPE_P (TREE_TYPE (*argp)))
+ 	*argp = fold_convert (get_array_arg_type (*argp), *argp);
+     }
+ 
+   /* Gimplify the function arguments.  */
+   for (i = (PUSH_ARGS_REVERSED ? nargs - 1 : 0);
+        PUSH_ARGS_REVERSED ? i >= 0 : i < nargs;
+        PUSH_ARGS_REVERSED ? i-- : i++)
+     {
+       enum gimplify_status t;
+ 
+       t = gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p,
+ 			EXPR_LOCATION (*expr_p));
+ 
+       if (t == GS_ERROR)
+ 	ret = GS_ERROR;
+     }
+ 
+   if (nargs >= 1)
+     {
+       arg0 = CALL_EXPR_ARG (*expr_p, 0);
+       arg0type = TREE_TYPE (arg0);
+       if (POINTER_TYPE_P (TREE_TYPE (arg0)))
+ 	arg0type = get_array_arg_type (arg0);
+     }
+   if (nargs >= 2)
+     {
+       arg1 = CALL_EXPR_ARG (*expr_p, 1);
+       arg1type = TREE_TYPE (arg1);
+       if (POINTER_TYPE_P (TREE_TYPE (arg1)))
+ 	arg1type = get_array_arg_type (arg1);
+     }
+   if (nargs >= 3)
+     {
+       arg2 = CALL_EXPR_ARG (*expr_p, 2);
+       arg2type = TREE_TYPE (arg2);
+       if (POINTER_TYPE_P (TREE_TYPE (arg2)))
+ 	arg2type = get_array_arg_type (arg2);
+     }
+ 
+   switch (DECL_FUNCTION_CODE (decl))
+     {
+       case BUILT_IN_ARRAY_SELECT:
+ 	{
+ 	  tree source, type, view;
+ 
+ 	  /* Extract the element type.  */
+ 	  type = arg0type;
+ 	  if (POINTER_TYPE_P (type))
+ 	    type = TREE_TYPE (type);
+ 	  while (TREE_CODE (type) == ARRAY_TYPE)
+ 	    type = TREE_TYPE (type);
+ 
+ 	  if (!FLOAT_TYPE_P (type)
+ 	      && !INTEGRAL_TYPE_P (type))
+ 	    error ("array element types must be floating point or integral");
+ 
+ 	  if (POINTER_TYPE_P (arg0type))
+ 	    source = build_fold_indirect_ref (fold_convert (arg0type, arg0));
+ 	  else
+ 	    source = arg0;
+ 	  view = build_vl_exp (VLA_VIEW_EXPR, nargs + 1);
+ 
+ 	  /* The type of the result is specified by the extent arguments,
+ 	     the actual shape is encoded in both extent and stride arguments
+ 	     and will be transfered to the VLA_VIEW_EXPR constructed.  */
+ 	  for (i = 1; i < nargs; i += 2)
+ 	    {
+ 	      tree extent, maxi, stride;
+ 	      tree arg = CALL_EXPR_ARG (*expr_p, i);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		error ("integral type required for extent argument of "
+ 		       "__builtin_array_select");
+ 	      extent = fold_convert (sizetype, arg);
+ 	      maxi = size_binop (MINUS_EXPR, extent, size_one_node);
+ 	      arg = CALL_EXPR_ARG (*expr_p, i+1);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		error ("integral type required for stride argument of "
+ 		       "__builtin_array_select");
+ 	      stride = fold_convert (ssizetype, arg);
+ 	      type = build_array_type (type, build_index_type (maxi));
+ 	      TREE_OPERAND (view, i + 1) = extent;
+ 	      TREE_OPERAND (view, i + 2) = stride;
+ 	    }
+ 
+ 	  TREE_TYPE (view) = type;
+ 	  TREE_OPERAND (view, 1) = source;
+ 	  *expr_p = view;
+ 
+ 	  break;
+ 	}
+ 
+       case BUILT_IN_ARRAY_STORE:
+ 	{
+ 	  tree dest, source;
+ 
+ 	  if (!POINTER_TYPE_P (arg0type)
+ 	      || TREE_CODE (TREE_TYPE (arg0type)) != ARRAY_TYPE)
+ 	    error ("pointer to array required as first argument to "
+ 		   "__builtin_array_store");
+ 
+ 	  if (nargs == 2)
+ 	    dest = vla_to_vla_view_expr
+ 		     (build_fold_indirect_ref (fold_convert (arg0type, arg0)));
+ 	  else
+ 	    {
+ 	      tree view = build_vl_exp (VLA_VIEW_EXPR, nargs);
+ 	      tree elt_type, type;
+ 
+ 	      /* Extract the element type.  */
+ 	      elt_type = TREE_TYPE (arg0type);
+ 	      while (TREE_CODE (elt_type) == ARRAY_TYPE)
+ 		elt_type = TREE_TYPE (elt_type);
+ 
+ 	      /* The type of the result is specified by the extent arguments,
+ 		 the actual shape is encoded in both extent and stride arguments
+ 		 and will be transfered to the VLA_VIEW_EXPR constructed.  */
+ 	      type = elt_type;
+ 	      for (i = 2; i < nargs; i += 2)
+ 		{
+ 		  tree extent, maxi, stride;
+ 		  tree arg;
+ 		  arg = CALL_EXPR_ARG (*expr_p, i);
+ 		  if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		    error ("integral type required for extent argument of "
+ 			   "__builtin_array_store");
+ 		  extent = fold_convert (sizetype, arg);
+ 		  maxi = size_binop (MINUS_EXPR, extent, size_one_node);
+ 		  arg = CALL_EXPR_ARG (*expr_p, i+1);
+ 		  if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		    error ("integral type required for stride argument of "
+ 			   "__builtin_array_store");
+ 		  stride = fold_convert (ssizetype, arg);
+ 		  type = build_array_type (type, build_index_type (maxi));
+ 		  TREE_OPERAND (view, i) = extent;
+ 		  TREE_OPERAND (view, i + 1) = stride;
+ 		}
+ 
+ 	      TREE_TYPE (view) = type;
+ 	      TREE_OPERAND (view, 1)
+ 		= build2 (MEM_REF, type, arg0,
+ 			  build_int_cst (build_pointer_type (elt_type), 0));
+ 	      dest = view;
+ 	    }
+ 
+ 	  if (POINTER_TYPE_P (arg1type))
+ 	    {
+ 	      source = build_fold_indirect_ref (fold_convert (arg1type, arg1));
+ 	      source = vla_to_vla_view_expr (source);
+ 	    }
+ 	  else
+ 	    {
+ 	      source = arg1;
+ 	      if (!is_gimple_reg_or_invariant_rhs (source))
+ 		DECL_GIMPLE_REG_P (source) = 1;
+ 	    }
+ 	  *expr_p = build2 (MODIFY_EXPR, void_type_node, dest, source);
+ 	  break;
+ 	}
+ 
+       case BUILT_IN_ARRAY_IDX:
+ 	{
+ 	  tree idx, type = arg0type;
+ 	  int i;
+ 	  while (TREE_CODE (type) == ARRAY_TYPE)
+ 	    type = TREE_TYPE (type);
+ 	  idx = build_vl_exp (VLA_IDX_EXPR, nargs + 1);
+ 	  TREE_TYPE (idx) = type;
+ 	  TREE_OPERAND (idx, 1) = CALL_EXPR_ARG (*expr_p, 0);
+ 	  if (!is_gimple_reg_or_invariant_rhs (TREE_OPERAND (idx, 1)))
+ 	    DECL_GIMPLE_REG_P (TREE_OPERAND (idx, 1)) = 1;
+ 	  for (i = 1; i < nargs; ++i)
+ 	    {
+ 	      tree arg = CALL_EXPR_ARG (*expr_p, i);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		error ("variable of integral type required for index "
+ 		       "argument of __builtin_array_idx");
+ 	      TREE_OPERAND (idx, i + 1) = CALL_EXPR_ARG (*expr_p, i);
+ 	    }
+ 	  *expr_p = idx;
+ 	}
+       break;
+ 
+       case BUILT_IN_ARRAY_RIDX:
+ 	{
+ 	  tree idx, type = arg0type;
+ 	  int i, j;
+ 	  idx = build_vl_exp (VLA_RIDX_EXPR, (nargs + 1)/2 + 1);
+ 	  TREE_OPERAND (idx, 1) = CALL_EXPR_ARG (*expr_p, 0);
+ 	  for (i = 1; i < nargs; i += 2)
+ 	    {
+ 	      tree extent, maxi;
+ 	      tree arg = CALL_EXPR_ARG (*expr_p, i + 1);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg)))
+ 		error ("integral type required for extent argument of "
+ 		       "__builtin_array_ridx");
+ 	      extent = fold_convert (sizetype, arg);
+ 	      maxi = size_binop (MINUS_EXPR, extent, size_one_node);
+ 	      arg = CALL_EXPR_ARG (*expr_p, i);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg))
+ 		  || !DECL_P (arg))
+ 		error ("variable of integral type required for index "
+ 		       "argument of __builtin_array_ridx");
+ 	      for (j = 1; j < i; j += 2)
+ 		if (CALL_EXPR_ARG (*expr_p, j) == arg)
+ 		  error ("index variable may only appear once in "
+ 			 " __builtin_array_ridx");
+ 	      TREE_OPERAND (idx, (i + 1)/2 + 1) = arg;
+ 	      type = build_array_type (type, build_index_type (maxi));
+ 	    }
+ 	  TREE_TYPE (idx) = type;
+ 	  *expr_p = idx;
+ 	}
+       break;
+ 
+       case BUILT_IN_ARRAY_DELTA:
+ 	{
+ 	  tree idx;
+ 	  int i;
+ 	  idx = build_vl_exp (VLA_DELTA_EXPR, nargs + 1);
+ 	  TREE_TYPE (idx) = arg0type;
+ 	  TREE_OPERAND (idx, 1) = CALL_EXPR_ARG (*expr_p, 0);
+ 	  if (!is_gimple_reg_or_invariant_rhs (TREE_OPERAND (idx, 1)))
+ 	    DECL_GIMPLE_REG_P (TREE_OPERAND (idx, 1)) = 1;
+ 	  TREE_OPERAND (idx, 2) = CALL_EXPR_ARG (*expr_p, 1);
+ 	  for (i = 2; i < nargs; ++i)
+ 	    {
+ 	      tree arg = CALL_EXPR_ARG (*expr_p, i);
+ 	      if (!INTEGRAL_TYPE_P (TREE_TYPE (arg))
+ 		  || !DECL_P (arg))
+ 		error ("variable of integral type required for index "
+ 		       "argument of __builtin_array_delta");
+ 	      TREE_OPERAND (idx, i + 1) = arg;
+ 	    }
+ 	  *expr_p = idx;
+ 	}
+       break;
+ 
+       default:
+         gcc_unreachable ();
+     }
+ 
+   return ret;
+ }
+ 
  /* Gimplify the CALL_EXPR node *EXPR_P into the GIMPLE sequence PRE_P.
     WANT_VALUE is true if the result of the call is desired.  */
  
*************** gimplify_call_expr (tree *expr_p, gimple
*** 2329,2334 ****
--- 2676,2690 ----
  	  return GS_OK;
  	}
  
+       /* Array operation builtins have to be lowered properly.  */
+       if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ 	  && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ARRAY_SELECT
+ 	      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ARRAY_STORE
+ 	      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ARRAY_IDX
+ 	      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ARRAY_RIDX
+ 	      || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ARRAY_DELTA))
+ 	return lower_builtin_array_expr (expr_p, pre_p, want_value);
+ 
        if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
  	  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_VA_START)
          {
*************** gimplify_init_ctor_eval (tree object, VE
*** 3585,3591 ****
  gimple_predicate
  rhs_predicate_for (tree lhs)
  {
!   if (is_gimple_reg (lhs))
      return is_gimple_reg_rhs_or_call;
    else
      return is_gimple_mem_rhs_or_call;
--- 3941,3949 ----
  gimple_predicate
  rhs_predicate_for (tree lhs)
  {
!   if (TREE_CODE (lhs) == VLA_VIEW_EXPR)
!     return is_gimple_reg_or_invariant_rhs;
!   else if (is_gimple_reg (lhs))
      return is_gimple_reg_rhs_or_call;
    else
      return is_gimple_mem_rhs_or_call;
*************** gimplify_modify_expr (tree *expr_p, gimp
*** 4536,4542 ****
       PLACEHOLDER_EXPRs in the size.  Also note that the RTL expander uses
       the size of the expression to be copied, not of the destination, so
       that is what we must do here.  */
!   maybe_with_size_expr (from_p);
  
    ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
    if (ret == GS_ERROR)
--- 4894,4901 ----
       PLACEHOLDER_EXPRs in the size.  Also note that the RTL expander uses
       the size of the expression to be copied, not of the destination, so
       that is what we must do here.  */
!   if (TREE_CODE (*to_p) != VLA_VIEW_EXPR)
!     maybe_with_size_expr (from_p);
  
    ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
    if (ret == GS_ERROR)
*************** gimplify_modify_expr (tree *expr_p, gimp
*** 4573,4582 ****
        tree from = TREE_OPERAND (*from_p, 0);
        tree size = TREE_OPERAND (*from_p, 1);
  
!       if (TREE_CODE (from) == CONSTRUCTOR)
  	return gimplify_modify_expr_to_memset (expr_p, size, want_value, pre_p);
  
!       if (is_gimple_addressable (from))
  	{
  	  *from_p = from;
  	  return gimplify_modify_expr_to_memcpy (expr_p, size, want_value,
--- 4932,4943 ----
        tree from = TREE_OPERAND (*from_p, 0);
        tree size = TREE_OPERAND (*from_p, 1);
  
!       if (DECL_P (*to_p) && DECL_GIMPLE_REG_P (*to_p))
! 	;
!       else if (TREE_CODE (from) == CONSTRUCTOR)
  	return gimplify_modify_expr_to_memset (expr_p, size, want_value, pre_p);
  
!       else if (is_gimple_addressable (from))
  	{
  	  *from_p = from;
  	  return gimplify_modify_expr_to_memcpy (expr_p, size, want_value,
*************** gimplify_expr (tree *expr_p, gimple_seq
*** 6592,6598 ****
             || gimple_test_f == is_gimple_reg_rhs
             || gimple_test_f == is_gimple_reg_rhs_or_call
             || gimple_test_f == is_gimple_asm_val
! 	   || gimple_test_f == is_gimple_mem_ref_addr)
      gcc_assert (fallback & fb_rvalue);
    else if (gimple_test_f == is_gimple_min_lval
  	   || gimple_test_f == is_gimple_lvalue)
--- 6953,6960 ----
             || gimple_test_f == is_gimple_reg_rhs
             || gimple_test_f == is_gimple_reg_rhs_or_call
             || gimple_test_f == is_gimple_asm_val
! 	   || gimple_test_f == is_gimple_mem_ref_addr
! 	   || gimple_test_f == is_gimple_reg_or_invariant_rhs)
      gcc_assert (fallback & fb_rvalue);
    else if (gimple_test_f == is_gimple_min_lval
  	   || gimple_test_f == is_gimple_lvalue)
*************** gimplify_expr (tree *expr_p, gimple_seq
*** 7140,7145 ****
--- 7502,7539 ----
  	  ret = GS_ALL_DONE;
  	  break;
  
+ 	case VLA_VIEW_EXPR:
+           {
+ 	    int i;
+ 	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+ 				 is_gimple_lvalue, fb_lvalue);
+ 	    for (i = 2; i < VL_EXP_OPERAND_LENGTH (*expr_p); ++i)
+ 	      {
+ 		enum gimplify_status tret;
+ 		tret = gimplify_expr (&TREE_OPERAND (*expr_p, i), pre_p, post_p,
+ 				      is_gimple_val, fb_rvalue);
+ 		ret = MIN (ret, tret);
+ 	      }
+ 	    break;
+ 	  }
+ 
+ 	case VLA_IDX_EXPR:
+ 	case VLA_RIDX_EXPR:
+ 	case VLA_DELTA_EXPR:
+ 	  {
+ 	    int i;
+ 	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+ 				 is_gimple_reg_or_invariant_rhs, fb_rvalue);
+ 	    for (i = 2; i < VL_EXP_OPERAND_LENGTH (*expr_p); ++i)
+ 	      {
+ 		enum gimplify_status tret;
+ 		tret = gimplify_expr (&TREE_OPERAND (*expr_p, i), pre_p, post_p,
+ 				      is_gimple_val, fb_rvalue);
+ 		ret = MIN (ret, tret);
+ 	      }
+ 	    break;
+ 	  }
+ 
  	case OMP_PARALLEL:
  	  gimplify_omp_parallel (expr_p, pre_p);
  	  ret = GS_ALL_DONE;
Index: trunk/gcc/testsuite/gcc.dg/mea-1.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-1.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,46 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ void __attribute__((noinline))
+ test(int *A_, int *B_)
+ {
+   int (* A)[8][16] = (int (*)[8][16])A_;
+   int (* B)[4][4] = (int (*)[4][4])B_;
+   int x, y, i, j;
+   x = __builtin_array_idx (__builtin_array_select (&(*A)[0][8], 4, 1, 4, 16), i, j);
+   y = __builtin_array_idx (__builtin_array_select (B, 4, 1, 4, 4), i, j);
+   __builtin_array_store (&(*A)[0][8], __builtin_array_ridx (x + y, i, 4, j, 4), 4, 1, 4, 16);
+ }
+ 
+ extern void abort (void);
+ 
+ int
+ main()
+ {
+   int A[8][16];
+   int B[4][4];
+   int i, j;
+   for (i=0; i<8; ++i)
+     for (j=0; j<16; ++j)
+       A[i][j] = 1;
+   for (i=0; i<4; ++i)
+     for (j=0; j<4; ++j)
+       B[i][j] = 2;
+   test(&A[0][0], &B[0][0]);
+   for (i=0; i<4; ++i)
+     for (j=8; j<12; ++j)
+       {
+         if (A[i][j] != 3)
+ 	  abort ();
+ 	A[i][j] = 1;
+       }
+   for (i=0; i<8; ++i)
+     for (j=0; j<16; ++j)
+       if (A[i][j] != 1)
+ 	abort ();
+   for (i=0; i<4; ++i)
+     for (j=0; j<4; ++j)
+       if (B[i][j] != 2)
+ 	abort ();
+   return 0;
+ }
Index: trunk/gcc/Makefile.in
===================================================================
*** trunk.orig/gcc/Makefile.in	2011-06-21 13:06:17.000000000 +0200
--- trunk/gcc/Makefile.in	2011-06-21 13:15:05.000000000 +0200
*************** OBJS = \
*** 1423,1428 ****
--- 1423,1429 ----
  	tree-into-ssa.o \
  	tree-iterator.o \
  	tree-loop-distribution.o \
+ 	tree-lower-arrays.o \
  	tree-nested.o \
  	tree-nomudflap.o \
  	tree-nrv.o \
*************** tree-ssa-forwprop.o : tree-ssa-forwprop.
*** 2476,2481 ****
--- 2477,2486 ----
     $(TM_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
     $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
     langhooks.h $(FLAGS_H) $(GIMPLE_H) tree-pretty-print.h $(EXPR_H)
+ tree-lower-arrays.o : tree-lower-arrays.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+    $(TM_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
+    $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
+    langhooks.h $(FLAGS_H) $(GIMPLE_H) tree-pretty-print.h $(EXPR_H)
  tree-ssa-phiprop.o : tree-ssa-phiprop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
     $(TM_H) $(TREE_H) $(TM_P_H) $(BASIC_BLOCK_H) \
     $(TREE_FLOW_H) $(TREE_PASS_H) $(TREE_DUMP_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
Index: trunk/gcc/passes.c
===================================================================
*** trunk.orig/gcc/passes.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/passes.c	2011-06-21 13:15:05.000000000 +0200
*************** init_optimization_passes (void)
*** 1289,1294 ****
--- 1289,1295 ----
        NEXT_PASS (pass_tree_ifcombine);
        NEXT_PASS (pass_phiopt);
        NEXT_PASS (pass_tail_recursion);
+       NEXT_PASS (pass_arrlower);
        NEXT_PASS (pass_ch);
        NEXT_PASS (pass_stdarg);
        NEXT_PASS (pass_lower_complex);
Index: trunk/gcc/timevar.def
===================================================================
*** trunk.orig/gcc/timevar.def	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/timevar.def	2011-06-21 13:15:05.000000000 +0200
*************** DEFTIMEVAR (TV_TREE_IFCOMBINE        , "
*** 250,255 ****
--- 250,256 ----
  DEFTIMEVAR (TV_TREE_UNINIT           , "uninit var analysis")
  DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
  DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
+ DEFTIMEVAR (TV_TREE_ARRLOWER         , "array expression lowering")
  
  /* Everything else in rest_of_compilation not included above.  */
  DEFTIMEVAR (TV_EARLY_LOCAL	     , "early local passes")
Index: trunk/gcc/tree-lower-arrays.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/tree-lower-arrays.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,661 ----
+ /* Lowering of expressions on arrays to loops.
+    Copyright (C) 2008 Free Software Foundation, Inc.
+    Contributed by Richard Guenther <rguenther@suse.de>
+ 
+ This file is part of GCC.
+ 
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+ 
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GCC; see the file COPYING3.  If not see
+ <http://www.gnu.org/licenses/>.  */
+ 
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
+ #include "tm.h"
+ #include "ggc.h"
+ #include "tree.h"
+ #include "rtl.h"
+ #include "tm_p.h"
+ #include "basic-block.h"
+ #include "timevar.h"
+ #include "diagnostic.h"
+ #include "tree-flow.h"
+ #include "tree-pass.h"
+ #include "tree-dump.h"
+ #include "gimple-pretty-print.h"
+ #include "langhooks.h"
+ #include "flags.h"
+ 
+ 
+ /* Recursively walk NAMEs defs marking all defining statements that
+    need lowering (and thus are not loop invariant) in the bitmap
+    of SSA name versions NAMES.  */
+ 
+ static bool
+ need_lowering (tree name, bitmap names, bitmap indices)
+ {
+   gimple stmt = SSA_NAME_DEF_STMT (name);
+   ssa_op_iter iter;
+   use_operand_p op_p;
+   tree rhs;
+   bool res = false;
+ 
+   if (bitmap_bit_p (indices, SSA_NAME_VERSION (name)))
+     return true;
+ 
+   if (gimple_nop_p (stmt))
+     return false;
+ 
+   FOR_EACH_PHI_OR_STMT_USE (op_p, stmt, iter, SSA_OP_USE)
+     {
+       tree op = USE_FROM_PTR (op_p);
+       if (TREE_CODE (op) == SSA_NAME)
+ 	res |= need_lowering (op, names, indices);
+     }
+   if (res)
+     {
+       bitmap_set_bit (names, SSA_NAME_VERSION (name));
+       return true;
+     }
+ 
+   if (!gimple_assign_single_p (stmt))
+     return false;
+ 
+   rhs = gimple_assign_rhs1 (stmt);
+ 
+   /* Collect indices.  They need to be introduced via RIDX or DELTA
+      before they can be used in expressions or IDX.  */
+   if (TREE_CODE (rhs) == VLA_RIDX_EXPR)
+     {
+       int i;
+       for (i = 2; i < tree_operand_length (rhs); ++i)
+ 	bitmap_set_bit (indices, SSA_NAME_VERSION (TREE_OPERAND (rhs, i)));
+     }
+   else if (TREE_CODE (rhs) == VLA_DELTA_EXPR)
+     {
+       int i;
+       for (i = 3; i < tree_operand_length (rhs); ++i)
+ 	bitmap_set_bit (indices, SSA_NAME_VERSION (TREE_OPERAND (rhs, i)));
+     }
+ 
+   if (TREE_CODE (rhs) == VLA_VIEW_EXPR
+       || TREE_CODE (rhs) == VLA_IDX_EXPR
+       || TREE_CODE (rhs) == VLA_RIDX_EXPR
+       || TREE_CODE (rhs) == VLA_DELTA_EXPR)
+     {
+       bitmap_set_bit (names, SSA_NAME_VERSION (name));
+       return true;
+     }
+ 
+   return false;
+ }
+ 
+ /* Check if NAME is (indirectly) used in a VLA_RIDX_EXPR.  */
+ 
+ static bool
+ used_in_ridx_p (tree name)
+ {
+   imm_use_iterator iter;
+   gimple use_stmt;
+ 
+   if (TREE_CODE (name) != SSA_NAME)
+     return false;
+ 
+   FOR_EACH_IMM_USE_STMT (use_stmt, iter, name)
+     {
+       if (!gimple_has_lhs (use_stmt))
+ 	continue;
+ 
+       if ((gimple_assign_single_p (use_stmt)
+ 	   && (gimple_assign_rhs_code (use_stmt) == VLA_RIDX_EXPR
+ 	       || gimple_assign_rhs_code (use_stmt) == VLA_DELTA_EXPR))
+ 	  || used_in_ridx_p (gimple_get_lhs (use_stmt)))
+ 	{
+ 	  end_imm_use_stmt_traverse (&iter);
+ 	  return true;
+ 	}
+     }
+ 
+   return false;
+ }
+ 
+ /* Lower the single statement that defines NAME prepending newly
+    created statements at BSI and adjusting TARGETs rhs to the lowered
+    value.  */
+ 
+ static void
+ lower_def (gimple_stmt_iterator *gsi, tree name, tree *target,
+ 	   VEC (tree, heap) *ivs, bitmap names, tree iv, tree *idx_map,
+ 	   bitmap indices)
+ {
+   gimple def_stmt = SSA_NAME_DEF_STMT (name);
+   gimple stmt;
+   tree rhs;
+   unsigned i;
+ 
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       tree idx;
+       fprintf (dump_file, "lowering ");
+       print_gimple_stmt (dump_file, def_stmt, 0, 0);
+       fprintf (dump_file, "\n  with ivs[] ");
+       for (i = 0; VEC_iterate (tree, ivs, i, idx); ++i)
+ 	{
+ 	  print_generic_expr (dump_file, idx, 0);
+ 	  fprintf (dump_file, " ");
+ 	}
+       fprintf (dump_file, "\n");
+     }
+ 
+   /* Lower bare indices to their associated induction variable.  */
+   if (idx_map[SSA_NAME_VERSION (name)])
+     {
+       *target = idx_map[SSA_NAME_VERSION (name)];
+       return;
+     }
+ 
+   /* Control flow handling is not implemented.  */
+   gcc_assert (gimple_code (def_stmt) != GIMPLE_PHI);
+ 
+   rhs = gimple_assign_rhs1 (def_stmt);
+ 
+   if (TREE_CODE (rhs) == VLA_VIEW_EXPR)
+     {
+       tree ref = unshare_expr (TREE_OPERAND (rhs, 1));
+       tree atype = TREE_TYPE (rhs);
+       int i;
+       int n = (tree_operand_length (rhs) - 2) / 2;
+       for (i = n - 1; i >= 0; --i)
+ 	{
+ 	  ref = build4 (ARRAY_REF, TREE_TYPE (atype),
+ 			ref, VEC_index (tree, ivs, i), NULL_TREE,
+ 			TREE_OPERAND (rhs, 2 + 2 * i + 1));
+ 	  atype = TREE_TYPE (atype);
+ 	}
+       *target = ref;
+       return;
+     }
+   else if (TREE_CODE (rhs) == VLA_IDX_EXPR)
+     {
+       int i, n = tree_operand_length (rhs) - 2;
+       VEC (tree, heap) *ivs2 = VEC_alloc (tree, heap, n);
+       for (i = 2; i < tree_operand_length (rhs); ++i)
+ 	{
+ 	  tree idx = TREE_OPERAND (rhs, i);
+ 	  if (TREE_CODE (idx) == SSA_NAME
+ 	      && !bitmap_bit_p (indices, SSA_NAME_VERSION (idx)))
+ 	    {
+ 	      tree newidx, tmp2;
+ 	      gimple stmt;
+ 	      tmp2 = NULL_TREE;
+ 	      lower_def (gsi, idx, &tmp2, ivs, names, iv, idx_map, indices);
+ 	      stmt = gimple_build_assign_with_ops
+ 		       (useless_type_conversion_p (TREE_TYPE (idx),
+ 						   TREE_TYPE (tmp2))
+ 			? SSA_NAME : NOP_EXPR,
+ 			SSA_NAME_VAR (idx), tmp2, NULL_TREE);
+ 	      newidx = make_ssa_name (SSA_NAME_VAR (idx), stmt);
+ 	      gimple_assign_set_lhs (stmt, newidx);
+ 	      gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+ 	      idx_map[SSA_NAME_VERSION (idx)] = newidx;
+ 	    }
+ 	  if (dump_file && (dump_flags & TDF_DETAILS))
+ 	    {
+ 	      fprintf (dump_file, "  for ");
+ 	      print_generic_expr (dump_file, idx, 0);
+ 	      fprintf (dump_file, " we have ");
+ 	      if (TREE_CODE (idx) == SSA_NAME)
+ 	        print_generic_expr (dump_file, idx_map[SSA_NAME_VERSION (idx)], 0);
+ 	      else
+ 	        print_generic_expr (dump_file, idx, 0);
+ 	      fprintf (dump_file, "\n");
+ 	    }
+ 	  if (TREE_CODE (idx) == SSA_NAME)
+ 	    VEC_quick_push (tree, ivs2, idx_map[SSA_NAME_VERSION (idx)]);
+ 	  else
+ 	    VEC_quick_push (tree, ivs2, idx);
+ 	}
+       lower_def (gsi, TREE_OPERAND (rhs, 1), target, ivs2, names, iv, idx_map, indices);
+       VEC_free (tree, heap, ivs2);
+       return;
+     }
+   else if (TREE_CODE (rhs) == VLA_RIDX_EXPR)
+     {
+       tree *saved;
+       int i;
+       saved = XALLOCAVEC (tree, tree_operand_length (rhs) - 2);
+       for (i = 2; i < tree_operand_length (rhs); ++i)
+ 	{
+ 	  tree idx = TREE_OPERAND (rhs, i);
+ 	  tree ivname = VEC_index (tree, ivs, i - 2);
+ 	  saved[i - 2] = idx_map[SSA_NAME_VERSION (idx)];
+ 	  if (!useless_type_conversion_p (TREE_TYPE (idx), TREE_TYPE (ivname)))
+ 	    {
+ 	      stmt = gimple_build_assign_with_ops (NOP_EXPR, SSA_NAME_VAR (idx),
+ 						   ivname, NULL_TREE);
+ 	      gimple_assign_set_lhs (stmt,
+ 				     make_ssa_name (SSA_NAME_VAR (idx), stmt));
+ 	      gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+ 	      idx_map[SSA_NAME_VERSION (idx)] = gimple_assign_lhs (stmt);
+ 	    }
+ 	  else
+ 	    idx_map[SSA_NAME_VERSION (idx)] = ivname;
+ 	}
+       lower_def (gsi, TREE_OPERAND (rhs, 1), target, ivs, names, iv, idx_map, indices);
+       for (i = tree_operand_length (rhs) - 1; i >= 2; --i)
+ 	{
+ 	  tree idx = TREE_OPERAND (rhs, i);
+ 	  idx_map[SSA_NAME_VERSION (idx)] = saved[i - 2];
+ 	}
+       return;
+     }
+   else if (TREE_CODE (rhs) == VLA_DELTA_EXPR)
+     {
+       tree extent = fold_convert (sizetype, TREE_OPERAND (rhs, 2));
+       tree ivname, incrname;
+       gimple stmt, cond, phi, incr;
+       basic_block bb;
+       gimple_stmt_iterator gsi2;
+       edge e;
+       tree var, sum, *saved, tmp2 = NULL_TREE;
+       int i;
+ 
+       extent = force_gimple_operand_gsi (gsi, extent, true, NULL_TREE,
+ 					 true, GSI_SAME_STMT);
+ 
+       var = create_tmp_var (TREE_TYPE (rhs), "redtmp");
+ 
+       /* Create the loop.  */
+       stmt = gsi_stmt (*gsi);
+       if (stmt != gsi_stmt (gsi_after_labels (gimple_bb (stmt))))
+ 	{
+ 	  gsi2 = gsi_for_stmt (stmt);
+ 	  gsi_prev (&gsi2);
+ 	  split_block (gimple_bb (stmt), gsi_stmt (gsi2));
+ 	  *gsi = gsi_for_stmt (stmt);
+ 	}
+       bb = gimple_bb (gsi_stmt (*gsi));
+       phi = create_phi_node (iv, bb);
+       ivname = PHI_RESULT (phi);
+       add_phi_arg (phi, size_zero_node, single_pred_edge (bb), UNKNOWN_LOCATION);
+       phi = create_phi_node (var, bb);
+       sum = PHI_RESULT (phi);
+       add_phi_arg (phi, fold_convert (TREE_TYPE (sum), integer_zero_node),
+ 		   single_pred_edge (bb), UNKNOWN_LOCATION);
+       gsi2 = gsi_for_stmt (gsi_stmt (*gsi));
+       incr = gimple_build_assign_with_ops (PLUS_EXPR, iv,
+ 					   ivname, size_one_node);
+       incrname = make_ssa_name (iv, incr);
+       gimple_assign_set_lhs (incr, incrname);
+       gsi_insert_before (&gsi2, incr, GSI_NEW_STMT);
+       cond = gimple_build_cond (LT_EXPR, incrname, extent,
+ 				NULL_TREE, NULL_TREE);
+       gsi_insert_before (gsi, cond, GSI_SAME_STMT);
+       split_block (bb, cond);
+       e = single_succ_edge (bb);
+       e->flags &= ~EDGE_FALLTHRU;
+       e->flags |= EDGE_FALSE_VALUE;
+       e = make_edge (bb, bb, EDGE_TRUE_VALUE);
+       e->flags |= EDGE_DFS_BACK;
+       add_phi_arg (SSA_NAME_DEF_STMT (ivname), incrname, e, UNKNOWN_LOCATION);
+ 
+       /* Lower the reduction body.  */
+       saved = XALLOCAVEC (tree, tree_operand_length (rhs) - 3);
+       for (i = 3; i < tree_operand_length (rhs); ++i)
+ 	{
+ 	  tree idx = TREE_OPERAND (rhs, i);
+ 	  saved[i - 3] = idx_map[SSA_NAME_VERSION (idx)];
+ 	  if (!useless_type_conversion_p (TREE_TYPE (idx), TREE_TYPE (ivname)))
+ 	    {
+ 	      stmt = gimple_build_assign_with_ops (NOP_EXPR, SSA_NAME_VAR (idx),
+ 						   ivname, NULL_TREE);
+ 	      gimple_assign_set_lhs (stmt,
+ 				     make_ssa_name (SSA_NAME_VAR (idx), stmt));
+ 	      gsi_insert_before (&gsi2, stmt, GSI_SAME_STMT);
+ 	      idx_map[SSA_NAME_VERSION (idx)] = gimple_assign_lhs (stmt);
+ 	    }
+ 	  else
+ 	    idx_map[SSA_NAME_VERSION (idx)] = ivname;
+ 	}
+       tmp2 = NULL_TREE;
+       lower_def (&gsi2, TREE_OPERAND (rhs, 1), &tmp2, ivs, names, iv, idx_map, indices);
+       stmt = gimple_build_assign (var, tmp2);
+       gimple_assign_set_lhs (stmt, make_ssa_name (var, stmt));
+       gsi_insert_before (&gsi2, stmt, GSI_SAME_STMT);
+       mark_virtual_ops_for_renaming (stmt);
+       for (i = tree_operand_length (rhs) - 1; i >= 3; --i)
+ 	{
+ 	  tree idx = TREE_OPERAND (rhs, i);
+ 	  idx_map[SSA_NAME_VERSION (idx)] = saved[i - 3];
+ 	}
+       incr = gimple_build_assign_with_ops (PLUS_EXPR, var,
+ 					   sum, gimple_assign_lhs (stmt));
+       incrname = make_ssa_name (var, incr);
+       gimple_assign_set_lhs (incr, incrname);
+       gsi_insert_before (&gsi2, incr, GSI_SAME_STMT);
+       add_phi_arg (SSA_NAME_DEF_STMT (sum), incrname, e, UNKNOWN_LOCATION);
+       *target = incrname;
+ 
+       *gsi = gsi_for_stmt (gsi_stmt (*gsi));
+       return;
+     }
+ 
+   gcc_assert (is_gimple_assign (def_stmt) || is_gimple_call (def_stmt));
+ 
+   stmt = gimple_copy (def_stmt);
+   gimple_set_lhs (stmt, make_ssa_name (SSA_NAME_VAR (name), stmt));
+ 
+   /* Lower other stmts by copying them and replacing to be lowered
+      operands by their lowered values.  */
+   for (i = is_gimple_assign (stmt) ? 1 : 3;
+        i < gimple_num_ops (stmt);
+        ++i)
+     {
+       tree *op_p = gimple_op_ptr (stmt, i);
+       tree op = *op_p;
+ 
+       if (!op || TREE_CODE (op) != SSA_NAME)
+ 	continue;
+ 
+       if (idx_map[SSA_NAME_VERSION (op)])
+ 	*op_p = idx_map[SSA_NAME_VERSION (op)];
+       else if (bitmap_bit_p (names, SSA_NAME_VERSION (op)))
+ 	{
+ 	  gimple tmp;
+ 	  tree var, newop, tmp2 = NULL_TREE;
+ 	  var = SSA_NAME_VAR (op);
+ 	  tmp2 = NULL_TREE;
+ 	  lower_def (gsi, op, &tmp2, ivs, names, iv, idx_map, indices);
+ 	  tmp = gimple_build_assign (var, tmp2);
+ 	  newop = make_ssa_name (var, tmp);
+ 	  gimple_assign_set_lhs (tmp, newop);
+ 	  gsi_insert_before (gsi, tmp, GSI_SAME_STMT);
+ 	  mark_virtual_ops_for_renaming (tmp);
+ 	  *op_p = newop;
+ 
+ 	  /* Record the newly created name for re-use.  */
+ 	  idx_map[SSA_NAME_VERSION (op)] = newop;
+ 	}
+     }
+ 
+   gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
+   update_stmt (stmt);
+   *target = gimple_get_lhs (stmt);
+ }
+ 
+ /* Lower the array expression that manifests itself by the store of
+    the result at BSI.  */
+ 
+ static void
+ lower_array_expression (gimple stmt, tree *idx_map)
+ {
+   gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+   tree lhs, rhs;
+   int i, n;
+   VEC (tree, heap) *ivs = NULL, *extent = NULL;
+   basic_block bb, out;
+   edge e;
+   tree iv, elt_type, elt, eltname, ref, atype, tmp2;
+   bitmap names, indices;
+   gimple tmp;
+ 
+   /* All information we need for determining the dimensionality and the
+      extent of the index walk is contained in the VLA_VIEW_EXPR of the lhs of
+      the store of the result of the array expression.  */
+   lhs = gimple_assign_lhs (stmt);
+   rhs = gimple_assign_rhs1 (stmt);
+ 
+   /* Scan for to be lowered stmts.  */
+   names = BITMAP_ALLOC (NULL);
+   indices = BITMAP_ALLOC (NULL);
+   need_lowering (rhs, names, indices);
+ 
+   n = (VL_EXP_OPERAND_LENGTH (lhs) - 2) / 2;
+   VEC_safe_grow_cleared (tree, heap, ivs, n);
+   VEC_safe_grow_cleared (tree, heap, extent, n);
+   elt_type = TREE_TYPE (lhs);
+   while (TREE_CODE (elt_type) == ARRAY_TYPE)
+     elt_type = TREE_TYPE (elt_type);
+   for (i = 0; i < n; ++i)
+     VEC_replace (tree, extent, i, TREE_OPERAND (lhs, 2 + 2 * i));
+ 
+   /* We will now have to build a loop nest of depth n with iteration
+      space [0..extentN-1] operating on the element type type.  */
+ 
+   /* Create a new temporary from which we create SSA names for
+      induction variables.
+      ???  Forcing them to be sizetype is unnecessary.  */
+   iv = create_tmp_var (sizetype, "ivtmp");
+   add_referenced_var (iv);
+ 
+   /* We enter lowering with the array store at bsi at the end of its
+      basic-block with a single fallthrough edge.  */
+   out = single_succ (gimple_bb (gsi_stmt (gsi)));
+ 
+   /* Now build loop header copies.  Loops run from zero to extent - 1.  */
+   for (i = 0; i < n; ++i)
+     {
+       tree cond, x;
+       gimple cond_stmt;
+       edge e;
+       gimple_stmt_iterator gsi2;
+ 
+       /* If 0 < extent is true then we always enter the loop.  If it
+ 	 is false all of the loop nest is dead and we can stop lowering.  */
+       x = VEC_index (tree, extent, i);
+       cond = fold_build2 (LT_EXPR, boolean_type_node,
+ 			  build_int_cst (TREE_TYPE (x), 0), x);
+       if (integer_onep (cond))
+ 	continue;
+       else if (integer_zerop (cond))
+ 	return;
+ 
+       /* Otherwise split the block after the inserted condition and
+ 	 set up edges to after the loop nest and the next header copy.  */
+       cond_stmt = gimple_build_cond_from_tree (cond, NULL_TREE, NULL_TREE);
+       gsi2 = gsi_for_stmt (gsi_stmt (gsi));
+       gsi_insert_before (&gsi2, cond_stmt, GSI_NEW_STMT);
+       bb = gimple_bb (gsi_stmt (gsi2));
+       split_block (bb, gsi_stmt (gsi2));
+       e = single_succ_edge (bb);
+       e->flags &= ~EDGE_FALLTHRU;
+       e->flags |= EDGE_TRUE_VALUE;
+       e = make_edge (bb, out, EDGE_FALSE_VALUE);
+     }
+ 
+   /* Make sure stmt is in its own basic block, even if all of the
+      loop header copy tests were not emitted.  */
+   if (stmt != gsi_stmt (gsi_after_labels (gimple_bb (stmt))))
+     {
+       gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
+       gsi_prev (&gsi2);
+       split_block (gimple_bb (stmt), gsi_stmt (gsi2));
+     }
+ 
+   /* Now build the loop CFG nest.
+ 
+      loopN:
+        # j_2 = PHI <0(entry), j_3(loopN)>
+ 
+      loopN-1:
+        # i_2 = PHI <0(entry), i_3(loopN-1)>
+        ...
+        i_3 = i_2 + 1;
+        if (i_3 < iextent) goto loopN-1;
+ 
+      <tailN>
+        j_3 = j_2 + 1;
+        if (j_3 < jextent) goto loopN;
+ 
+      out:
+     */
+   bb = gimple_bb (gsi_stmt (gsi));
+   for (i = n - 1; i >= 0; --i)
+     {
+       tree incrname;
+       gimple phi, incr, cond;
+       gimple_stmt_iterator gsi2;
+       basic_block bb2, bb3;
+       e = single_pred_edge (bb);
+       bb3 = split_edge (e);
+       phi = create_phi_node (iv, bb3);
+       VEC_replace (tree, ivs, i, PHI_RESULT (phi));
+       add_phi_arg (phi, size_zero_node, single_pred_edge (bb3), UNKNOWN_LOCATION);
+       incr = gimple_build_assign_with_ops (PLUS_EXPR, iv,
+ 					   VEC_index (tree, ivs, i),
+ 					   size_one_node);
+       incrname = make_ssa_name (iv, incr);
+       gimple_assign_set_lhs (incr, incrname);
+       gsi2 = gsi_for_stmt (gsi_stmt (gsi));
+       gsi_insert_after (&gsi2, incr, GSI_NEW_STMT);
+       cond = gimple_build_cond (LT_EXPR, incrname, VEC_index (tree, extent, i),
+ 				NULL_TREE, NULL_TREE);
+       gsi_insert_after (&gsi2, cond, GSI_NEW_STMT);
+       bb2 = gimple_bb (gsi_stmt (gsi2));
+       if (gsi_stmt (gsi2) != last_stmt (bb2))
+ 	split_block (bb2, gsi_stmt (gsi2));
+       e = single_succ_edge (bb);
+       e->flags &= ~EDGE_FALLTHRU;
+       e->flags |= EDGE_FALSE_VALUE;
+       e = make_edge (bb2, bb3, EDGE_TRUE_VALUE);
+       e->flags |= EDGE_DFS_BACK;
+       add_phi_arg (SSA_NAME_DEF_STMT (VEC_index (tree, ivs, i)), incrname, e,
+ 		   UNKNOWN_LOCATION);
+     }
+ 
+   /* FIXME.  Now bb is where the real code(TM) is supposed to live.  */
+   elt = create_tmp_var (elt_type, "elttmp");
+   add_referenced_var (elt);
+ 
+   gsi = gsi_for_stmt (stmt);
+ 
+   /* Now walk the defs of the store stmt uses and build up the
+      lowered expression.  */
+   tmp2 = NULL_TREE;
+   lower_def (&gsi, rhs, &tmp2, ivs, names, iv, idx_map, indices);
+   tmp = gimple_build_assign (elt, tmp2);
+   eltname = make_ssa_name (elt, tmp);
+   gimple_assign_set_lhs (tmp, eltname);
+   gsi_insert_before (&gsi, tmp, GSI_SAME_STMT);
+ 
+   /* Build the final store instruction.  */
+   ref = TREE_OPERAND (lhs, 1);
+   atype = TREE_TYPE (lhs);
+   for (i = n - 1; i >= 0; --i)
+     {
+       ref = build4 (ARRAY_REF, TREE_TYPE (atype),
+ 		    ref, VEC_index (tree, ivs, i), NULL_TREE,
+ 		    TREE_OPERAND (lhs, 2 + 2 * i + 1));
+       atype = TREE_TYPE (atype);
+     }
+   tmp = gimple_build_assign (ref, eltname);
+   gsi_insert_before (&gsi, tmp, GSI_SAME_STMT);
+   update_stmt (tmp);
+   mark_virtual_ops_for_renaming (tmp);
+ 
+   BITMAP_FREE (names);
+   BITMAP_FREE (indices);
+   VEC_free (tree, heap, ivs);
+ }
+ 
+ /* Poor man's lowering of expressions on arrays to loop form.  */
+ 
+ static unsigned int
+ tree_lower_array_expressions (void)
+ {
+   basic_block bb;
+   gimple_stmt_iterator gsi;
+   int orig_num_ssa_names = num_ssa_names;
+   tree *idx_map = XCNEWVEC (tree, num_ssa_names);
+ 
+   FOR_EACH_BB (bb)
+     {
+       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+ 	{
+ 	  gimple stmt = gsi_stmt (gsi);
+ 
+ 	  /* The final array stores are where we build up our loops from.
+ 	     We split the block with the store after the store to make
+ 	     CFG manipulations easier for the lowering process.  */
+ 	  if (gimple_assign_single_p (stmt)
+ 	      && TREE_CODE (gimple_assign_lhs (stmt)) == VLA_VIEW_EXPR)
+ 	    {
+ 	      if (stmt != last_stmt (bb))
+ 	        split_block (bb, stmt);
+ 	      memset (idx_map, 0, sizeof (tree) * orig_num_ssa_names);
+ 	      lower_array_expression (stmt, idx_map);
+ 	      gsi = gsi_for_stmt (stmt);
+ 	      gsi_remove (&gsi, true);
+ 	      break;
+ 	    }
+ 	  else if (gimple_assign_single_p (stmt)
+ 	           && gimple_assign_rhs_code (stmt) == VLA_DELTA_EXPR
+ 		   && !used_in_ridx_p (gimple_assign_lhs (stmt)))
+ 	    {
+ 	      tree lhs, iv, rhs = NULL_TREE;
+ 	      bitmap names, indices;
+ 	      lhs = gimple_assign_lhs (stmt);
+ 	      names = BITMAP_ALLOC (NULL);
+ 	      indices = BITMAP_ALLOC (NULL);
+ 	      need_lowering (lhs, names, indices);
+ 	      iv = create_tmp_var (sizetype, "ivtmp");
+ 	      add_referenced_var (iv);
+ 	      memset (idx_map, 0, sizeof (tree) * orig_num_ssa_names);
+ 	      lower_def (&gsi, lhs, &rhs, NULL, names, iv, idx_map, indices);
+ 	      gimple_assign_set_rhs1 (stmt, rhs);
+ 	      update_stmt (stmt);
+ 	      gsi = gsi_for_stmt (stmt);
+ 	      BITMAP_FREE (names);
+ 	      BITMAP_FREE (indices);
+ 	      gsi_next (&gsi);
+ 	      break;
+ 	    }
+ 	  else
+ 	    gsi_next (&gsi);
+ 	}
+     }
+ 
+   free_dominance_info (CDI_DOMINATORS);
+   free_dominance_info (CDI_POST_DOMINATORS);
+ 
+   return 0;
+ }
+ 
+ static bool
+ gate_arrlower (void)
+ {
+   return 1;
+ }
+ 
+ struct gimple_opt_pass pass_arrlower =
+ {
+  {
+   GIMPLE_PASS,
+   "arrlower",			/* name */
+   gate_arrlower,		/* gate */
+   tree_lower_array_expressions,	/* execute */
+   NULL,				/* sub */
+   NULL,				/* next */
+   0,				/* static_pass_number */
+   TV_TREE_ARRLOWER,		/* tv_id */
+   PROP_cfg | PROP_ssa,		/* properties_required */
+   0,				/* properties_provided */
+   0,				/* properties_destroyed */
+   0,				/* todo_flags_start */
+   TODO_dump_func
+   | TODO_ggc_collect
+   | TODO_update_ssa
+   | TODO_verify_ssa		/* todo_flags_finish */
+  }
+ };
+ 
Index: trunk/gcc/tree-pass.h
===================================================================
*** trunk.orig/gcc/tree-pass.h	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-pass.h	2011-06-21 13:15:05.000000000 +0200
*************** extern struct gimple_opt_pass pass_trace
*** 446,451 ****
--- 446,452 ----
  extern struct gimple_opt_pass pass_warn_unused_result;
  extern struct gimple_opt_pass pass_split_functions;
  extern struct gimple_opt_pass pass_feedback_split_functions;
+ extern struct gimple_opt_pass pass_arrlower;
  
  /* IPA Passes */
  extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
Index: trunk/gcc/cfgexpand.c
===================================================================
*** trunk.orig/gcc/cfgexpand.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/cfgexpand.c	2011-06-21 13:15:05.000000000 +0200
*************** estimated_stack_frame_size (struct cgrap
*** 1333,1339 ****
  
    gcc_checking_assert (gimple_referenced_vars (fn));
    FOR_EACH_REFERENCED_VAR (fn, var, rvi)
!     size += expand_one_var (var, true, false);
  
    if (stack_vars_num > 0)
      {
--- 1333,1340 ----
  
    gcc_checking_assert (gimple_referenced_vars (fn));
    FOR_EACH_REFERENCED_VAR (fn, var, rvi)
!     if (!DECL_GIMPLE_REG_P (var))
!       size += expand_one_var (var, true, false);
  
    if (stack_vars_num > 0)
      {
*************** expand_debug_expr (tree exp)
*** 3286,3291 ****
--- 3287,3298 ----
      case FMA_EXPR:
        return simplify_gen_ternary (FMA, mode, inner_mode, op0, op1, op2);
  
+     case VLA_VIEW_EXPR:
+     case VLA_RIDX_EXPR:
+     case VLA_IDX_EXPR:
+     case VLA_DELTA_EXPR:
+       return NULL;
+ 
      default:
      flag_unsupported:
  #ifdef ENABLE_CHECKING
Index: trunk/gcc/testsuite/gcc.dg/mea-2.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-2.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ test(float *A_, float *B_)
+ {
+   float (* A)[8][16] = (float (*)[8][16])A_;
+   float (* B)[8][16] = (float (*)[8][16])B_;
+   __builtin_array_store (A, B);
+ }
+ 
+ void
+ test_r(float *A_, float *B_)
+ {
+   float (* A)[8][16] = (float (*)[8][16])A_;
+   float (* B)[8][16] = (float (*)[8][16])B_;
+   int i, j;
+   for (i = 0; i < 8; ++i)
+     for (j = 0; j < 16; ++j)
+       (*A)[i][j] = (*B)[i][j];
+ }
+ 
Index: trunk/gcc/tree-cfg.c
===================================================================
*** trunk.orig/gcc/tree-cfg.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-cfg.c	2011-06-21 13:15:05.000000000 +0200
*************** verify_gimple_assign_single (gimple stmt
*** 3906,3911 ****
--- 3906,3918 ----
        /* FIXME.  */
        return res;
  
+     case VLA_VIEW_EXPR:
+     case VLA_IDX_EXPR:
+     case VLA_RIDX_EXPR:
+     case VLA_DELTA_EXPR:
+       /* FIXME.  */
+       return false;
+ 
      default:;
      }
  
Index: trunk/gcc/tree-pretty-print.c
===================================================================
*** trunk.orig/gcc/tree-pretty-print.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-pretty-print.c	2011-06-21 13:15:05.000000000 +0200
*************** dump_generic_node (pretty_printer *buffe
*** 1217,1222 ****
--- 1217,1252 ----
        pp_string (buffer, ">");
        break;
  
+     case VLA_VIEW_EXPR:
+     case VLA_IDX_EXPR:
+     case VLA_RIDX_EXPR:
+     case VLA_DELTA_EXPR:
+       {
+ 	int n;
+ 	if (TREE_CODE (node) == VLA_VIEW_EXPR)
+ 	  pp_string (buffer, "VLA <");
+ 	else if (TREE_CODE (node) == VLA_IDX_EXPR)
+ 	  pp_string (buffer, "VLA_IDX <");
+ 	else if (TREE_CODE (node) == VLA_RIDX_EXPR)
+ 	  pp_string (buffer, "VLA_RIDX <");
+ 	else if (TREE_CODE (node) == VLA_DELTA_EXPR)
+ 	  pp_string (buffer, "VLA_DELTA <");
+ 	for (n = 2; n < VL_EXP_OPERAND_LENGTH (node) - 1; ++n)
+ 	  {
+ 	    dump_generic_node (buffer, TREE_OPERAND (node, n),
+ 			       spc, flags, false);
+ 	    pp_string (buffer, ", ");
+ 	  }
+ 	dump_generic_node (buffer,
+ 			   TREE_OPERAND (node,
+ 					 VL_EXP_OPERAND_LENGTH (node) - 1),
+ 			   spc, flags, false);
+ 	pp_string (buffer, "> (");
+ 	dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+ 	pp_string (buffer, ")");
+       }
+       break;
+ 
      case ARRAY_REF:
      case ARRAY_RANGE_REF:
        op0 = TREE_OPERAND (node, 0);
Index: trunk/gcc/tree.def
===================================================================
*** trunk.orig/gcc/tree.def	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree.def	2011-06-21 13:15:05.000000000 +0200
*************** DEFTREECODE (ARRAY_REF, "array_ref", tcc
*** 417,422 ****
--- 417,458 ----
     of the range is taken from the type of the expression.  */
  DEFTREECODE (ARRAY_RANGE_REF, "array_range_ref", tcc_reference, 4)
  
+ /* Variable-length array view operation on a piece of memory.
+    This returns a vla object starting at the base of operand zero.
+    The remaining arguments specify length and stride of each dimension.
+      VLA_VIEW_EXPR <object, extent0, stride0, ..., extentN, strideN>
+    The dimensionality is the vl operand length minus one.
+    The result type is the respective vla type.  */
+ DEFTREECODE (VLA_VIEW_EXPR, "vla_view_expr", tcc_vl_exp, 1)
+ 
+ /* Variable-length array indexing operation which creates a placeholder
+    for any element in the indexed array subject to variable indices.
+    The first operand is the array to be indexed and the following
+    operands are placeholders for indices or constants.  As many
+    extra operands as the array has dimensions have to be provided.
+      VLA_IDX_EXPR <array, index0, ..., indexN>
+    The result is of type of the array elements.  */
+ DEFTREECODE (VLA_IDX_EXPR, "vla_idx_expr", tcc_vl_exp, 1)
+ 
+ /* Variable-length array construction operation which creates an array
+    from a scalar that may be computed from a placeholder expression
+    The first operand is the scalar expression to be used to fill the
+    array elements indexed by the following operands that are
+    placeholders for indices.  As many extra operands as the array has
+    dimensions have to be provided.
+      VLA_RIDX_EXPR <scalar, index0, ..., indexN>
+    The result is of array type.  */
+ DEFTREECODE (VLA_RIDX_EXPR, "vla_ridx_expr", tcc_vl_exp, 1)
+ 
+ /* Variable-length array contraction operation.  This represents
+    a reduction loop contracting the indices specified by the third
+    and following operands of the first operand which is a scalar
+    computed by placeholder expressions.  The second operand is
+    the common extent of the dimensions the specified indices are used in.
+      VLA_DELTA_EXPR <scalar, extent, index0, ..., indexN>
+    The result is of scalar type.  */
+ DEFTREECODE (VLA_DELTA_EXPR, "vla_delta_expr", tcc_vl_exp, 1)
+ 
  /* C unary `*' or Pascal `^'.  One operand, an expression for a pointer.  */
  DEFTREECODE (INDIRECT_REF, "indirect_ref", tcc_reference, 1)
  
Index: trunk/gcc/tree-ssa-operands.c
===================================================================
*** trunk.orig/gcc/tree-ssa-operands.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-ssa-operands.c	2011-06-21 13:15:05.000000000 +0200
*************** get_expr_operands (gimple stmt, tree *ex
*** 948,953 ****
--- 948,973 ----
        get_expr_operands (stmt, &TREE_OPERAND (expr, 2), uflags);
        return;
  
+     case VLA_VIEW_EXPR:
+       {
+ 	int i;
+         get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags);
+ 	for (i = 2; i < VL_EXP_OPERAND_LENGTH (expr); ++i)
+ 	  get_expr_operands (stmt, &TREE_OPERAND (expr, i), opf_use);
+ 
+ 	return;
+       }
+     case VLA_IDX_EXPR:
+     case VLA_RIDX_EXPR:
+     case VLA_DELTA_EXPR:
+       {
+ 	int i;
+ 	for (i = 1; i < VL_EXP_OPERAND_LENGTH (expr); ++i)
+ 	  get_expr_operands (stmt, &TREE_OPERAND (expr, i), opf_use);
+ 
+ 	return;
+       }
+ 
      case CONSTRUCTOR:
        {
  	/* General aggregate CONSTRUCTORs have been decomposed, but they
Index: trunk/gcc/tree-ssa-sink.c
===================================================================
*** trunk.orig/gcc/tree-ssa-sink.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-ssa-sink.c	2011-06-21 13:15:05.000000000 +0200
*************** is_hidden_global_store (gimple stmt)
*** 194,199 ****
--- 194,202 ----
  	       || TREE_CODE (lhs) == MEM_REF
  	       || TREE_CODE (lhs) == TARGET_MEM_REF)
  	return ptr_deref_may_alias_global_p (TREE_OPERAND (lhs, 0));
+       else if (TREE_CODE (lhs) == VLA_VIEW_EXPR)
+ 	/* FIXME.  */
+ 	return true;
        else if (CONSTANT_CLASS_P (lhs))
  	return true;
        else
Index: trunk/gcc/testsuite/gcc.dg/mea-3.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-3.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ test(float *A_, float *B_, int n, int m)
+ {
+   float (* A)[n][m] = (float (*)[n][m])A_;
+   float (* B)[n][m] = (float (*)[n][m])B_;
+   __builtin_array_store (A, B);
+ }
+ 
+ void
+ test_r(float *A_, float *B_, int n, int m)
+ {
+   float (* A)[n][m] = (float (*)[n][m])A_;
+   float (* B)[n][m] = (float (*)[n][m])B_;
+   int i, j;
+   for (i = 0; i < n; ++i)
+     for (j = 0; j < m; ++j)
+       (*A)[i][j] = (*B)[i][j];
+ }
+ 
Index: trunk/gcc/builtin-attrs.def
===================================================================
*** trunk.orig/gcc/builtin-attrs.def	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/builtin-attrs.def	2011-06-21 13:15:05.000000000 +0200
*************** DEF_ATTR_IDENT (ATTR_SENTINEL, "sentinel
*** 96,101 ****
--- 96,102 ----
  DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
  DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
  DEF_ATTR_IDENT (ATTR_TYPEGENERIC, "type generic")
+ DEF_ATTR_IDENT (ATTR_COVARIANTRETURN, "covariant return")
  
  DEF_ATTR_TREE_LIST (ATTR_NOVOPS_LIST, ATTR_NOVOPS, ATTR_NULL, ATTR_NULL)
  
*************** DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_
*** 188,193 ****
--- 189,200 ----
  /* Nothrow malloc leaf functions whose pointer parameter(s) are all nonnull.  */
  DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_NONNULL_LEAF, ATTR_MALLOC, ATTR_NULL, \
  			ATTR_NOTHROW_NONNULL_LEAF)
+ /* Nothrow functions which are type-generic.  */
+ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_TYPEGENERIC, ATTR_TYPEGENERIC, ATTR_NULL, \
+ 			ATTR_NOTHROW_LIST)
+ /* Nothrow functions which have a convariant return type and are type-generic. */
+ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_TYPEGENERIC_COVARIANTRETURN, ATTR_COVARIANTRETURN, ATTR_NULL, \
+ 			ATTR_NOTHROW_TYPEGENERIC)
  
  /* Construct a tree for a format attribute.  */
  #define DEF_FORMAT_ATTRIBUTE(TYPE, FA, VALUES)				 \
Index: trunk/gcc/testsuite/gcc.dg/mea-4.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-4.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void __attribute__((noinline))
+ test(int *A_, int *B_)
+ {
+   int (* A)[4][4] = (int (*)[4][4])A_;
+   int (* B)[4][4] = (int (*)[4][4])B_;
+   int i, j, x;
+   x = __builtin_array_idx (__builtin_array_select (B, 4, 1, 4, 4), i, j);
+   x = x + 1;
+   x = x * i + j;
+   __builtin_array_store (A, __builtin_array_ridx (x, i, 4, j, 4));
+ }
+ 
Index: trunk/gcc/c-family/c-common.c
===================================================================
*** trunk.orig/gcc/c-family/c-common.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/c-family/c-common.c	2011-06-21 13:15:05.000000000 +0200
*************** static tree handle_warn_unused_result_at
*** 369,374 ****
--- 369,375 ----
  						 bool *);
  static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
  static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+ static tree handle_covariant_return_attribute (tree *, tree, tree, int, bool *);
  static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
  static tree handle_target_attribute (tree *, tree, tree, int, bool *);
  static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
*************** const struct attribute_spec c_common_att
*** 686,691 ****
--- 687,696 ----
       to prevent its usage in source code.  */
    { "type generic",           0, 0, false, true, true,
  			      handle_type_generic_attribute, false },
+   /* For internal use (marking of builtins) only.  The name contains space
+      to prevent its usage in source code.  */
+   { "covariant return",       0, 0, false, true, true,
+ 			      handle_covariant_return_attribute, false },
    { "alloc_size",	      1, 2, false, true, true,
  			      handle_alloc_size_attribute, false },
    { "cold",                   0, 0, true,  false, false,
*************** handle_no_split_stack_attribute (tree *n
*** 7963,7968 ****
--- 7968,7986 ----
  
    return NULL_TREE;
  }
+ 
+ /* Handle a "covariant return" attribute.  */
+ 
+ static tree
+ handle_covariant_return_attribute (tree *node, tree ARG_UNUSED (name),
+ 			       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+ 			       bool * ARG_UNUSED (no_add_attrs))
+ {
+   /* Ensure we have a function type.  */
+   gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+ 
+   return NULL_TREE;
+ }
  
  /* Check for valid arguments being passed to a function with FNTYPE.
     There are NARGS arguments in the array ARGARRAY.  */
Index: trunk/gcc/c-typeck.c
===================================================================
*** trunk.orig/gcc/c-typeck.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/c-typeck.c	2011-06-21 13:15:05.000000000 +0200
*************** convert_arguments (tree typelist, VEC(tr
*** 2955,2960 ****
--- 2955,2966 ----
        val = c_fully_fold (val, false, NULL);
        STRIP_TYPE_NOPS (val);
  
+       if (type_generic)
+ 	{
+ 	  VEC_replace (tree, values, parmnum, val);
+ 	  continue;
+ 	}
+ 
        val = require_complete_type (val);
  
        if (type != 0)
*************** convert_for_assignment (location_t locat
*** 5203,5208 ****
--- 5209,5224 ----
  
    if (coder == VOID_TYPE)
      {
+       /* If this is a builtin call with a covariant return type attribute just
+ 	 accept it as is.  */
+       if (TREE_CODE (rhs) == CALL_EXPR)
+ 	{
+ 	  tree fndecl = get_callee_fndecl (rhs);
+ 	  if (fndecl
+ 	      && lookup_attribute ("covariant return",
+ 				   TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
+ 	    return rhs;
+ 	}
        /* Except for passing an argument to an unprototyped function,
  	 this is a constraint violation.  When passing an argument to
  	 an unprototyped function, it is compile-time undefined;
Index: trunk/gcc/testsuite/gcc.dg/mea-5.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-5.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,43 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ void
+ matmul(float *w, float *u, float *v, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n][n] = (float (*)[n][n])w;
+   int i, j, k, l;
+   float Ukj, Vil, VUij;
+   Ukj = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, j);
+   Vil = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), i, l);
+   VUij = __builtin_array_delta (Vil * Ukj, m, k, l);
+   __builtin_array_store (W, __builtin_array_ridx (VUij, i, n, j, n), n, 1, n, n);
+ }
+ 
+ extern void abort (void);
+ 
+ int
+ main()
+ {
+   float U[2][4], V[4][2], W[2][2];
+   int i, j, k;
+   __builtin_memset (U, 0, sizeof (U));
+   __builtin_memset (V, 0, sizeof (V));
+   __builtin_memset (W, 0, sizeof (W));
+   U[0][0] = 1.0;
+   U[1][1] = 1.0;
+   V[0][0] = 1.0;
+   V[1][1] = 1.0;
+   matmul (&W[0][0], &U[0][0], &V[0][0], 2, 4);
+   for (i = 0; i < 2; ++i)
+     for (j = 0; j < 2; ++j)
+       {
+ 	float sum = 0.0;
+         for (k = 0; k < 4; ++k)
+ 	  sum += U[i][k]*V[k][j];
+ 	if (sum != W[i][j])
+ 	  abort ();
+       }
+   return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/mea-6.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-6.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,30 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ extern void abort (void);
+ 
+ float
+ scalarprod (float *u, float *v, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   float (*V)[n] = (float (*)[n])v;
+   float Ui, Vj, res;
+   int i, j;
+   Ui = __builtin_array_idx (__builtin_array_select (U, n, 1), i);
+   Vj = __builtin_array_idx (__builtin_array_select (V, n, 1), j);
+   res = __builtin_array_delta (Ui * Vj, n, i, j);
+   return res;
+ }
+ 
+ int main()
+ {
+   float U[3] = {1, 1, 1}, V[3] = {1, 1, 1}, W;
+   int i;
+   float res = scalarprod (U, V, 3);
+   float sum = 0.0;
+   for (i = 0; i < 3; ++i)
+     sum += U[i]*V[i];
+   if (sum != res)
+     abort ();
+   return 0;
+ }
Index: trunk/gcc/testsuite/gcc.dg/mea-7.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-7.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ idx1 (float *u, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   int i;
+   __builtin_array_store (U, __builtin_array_ridx ((float)i, i, n), n, 1);
+ }
+ 
+ void
+ idx2 (int *v, int n)
+ {
+   int (*V)[n] = (int (*)[n])v;
+   int i;
+   __builtin_array_store (V, __builtin_array_ridx (i, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-8.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-8.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* This implements matrix-vector multiplication with the matrix
+    resulting from a matrix-matrix multiplication.  */
+ 
+ void
+ fancy (float *res, float *u, float *v, float *w, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n] = (float (*)[n])w;
+   float (*R)[n] = (float (*)[n])res;
+   int i, j, k;
+   float Uki, Vjk, Wj, VUij, Ri;
+   Uki = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, i);
+   Vjk = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), j, k);
+   Wj = __builtin_array_idx (__builtin_array_select (W, n, 1), j);
+   VUij = __builtin_array_delta (Vjk * Uki, m, k, k);
+   Ri = __builtin_array_delta (VUij * Wj, n, j, j);
+   __builtin_array_store (R, __builtin_array_ridx (Ri, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-9.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-9.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* This implements a vector norm of a matrix-vector multiplication
+    result with the matrix resulting from a matrix-matrix multiplication.  */
+ 
+ float
+ more_fancy (float *u, float *v, float *w, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n] = (float (*)[n])w;
+   int i, j, k;
+   float Uki, Vjk, Wj, VUij, Ri, norm;
+   Uki = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, i);
+   Vjk = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), j, k);
+   Wj = __builtin_array_idx (__builtin_array_select (W, n, 1), j);
+   VUij = __builtin_array_delta (Vjk * Uki, m, k, k);
+   Ri = __builtin_array_delta (VUij * Wj, n, j, j);
+   Ri = Ri * Ri;
+   norm = __builtin_array_delta (Ri, n, i);
+   return __builtin_sqrtf (norm);
+ }
+ 
Index: trunk/gcc/cp/call.c
===================================================================
*** trunk.orig/gcc/cp/call.c	2011-06-21 13:06:09.000000000 +0200
--- trunk/gcc/cp/call.c	2011-06-21 13:15:05.000000000 +0200
*************** resolve_args (VEC(tree,gc) *args, tsubst
*** 3660,3665 ****
--- 3660,3675 ----
  	return NULL;
        else if (VOID_TYPE_P (TREE_TYPE (arg)))
  	{
+ 	  /* If this is a builtin call with a covariant return type attribute
+ 	     just accept it as is.  */
+ 	  if (TREE_CODE (arg) == CALL_EXPR)
+ 	    {
+ 	      tree fndecl = get_callee_fndecl (arg);
+ 	      if (fndecl
+ 		  && lookup_attribute ("covariant return",
+ 				       TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
+ 		continue;
+ 	    }
  	  if (complain & tf_error)
  	    error ("invalid use of void expression");
  	  return NULL;
Index: trunk/gcc/cp/typeck.c
===================================================================
*** trunk.orig/gcc/cp/typeck.c	2011-06-21 13:06:09.000000000 +0200
--- trunk/gcc/cp/typeck.c	2011-06-21 13:15:05.000000000 +0200
*************** convert_for_assignment (tree type, tree
*** 7247,7252 ****
--- 7247,7262 ----
    /* The RHS of an assignment cannot have void type.  */
    if (coder == VOID_TYPE)
      {
+       /* If this is a builtin call with a covariant return type attribute just
+          accept it as is.  */
+       if (TREE_CODE (rhs) == CALL_EXPR)
+         {
+           tree fndecl = get_callee_fndecl (rhs);
+           if (fndecl
+               && lookup_attribute ("covariant return",
+                                    TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
+             return rhs;
+         }
        if (complain & tf_error)
  	error ("void value not ignored as it ought to be");
        return error_mark_node;
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-1.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-1.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,46 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ void __attribute__((noinline))
+ test(int *A_, int *B_)
+ {
+   int (* A)[8][16] = (int (*)[8][16])A_;
+   int (* B)[4][4] = (int (*)[4][4])B_;
+   int x, y, i, j;
+   x = __builtin_array_idx (__builtin_array_select (&(*A)[0][8], 4, 1, 4, 16), i, j);
+   y = __builtin_array_idx (__builtin_array_select (B, 4, 1, 4, 4), i, j);
+   __builtin_array_store (&(*A)[0][8], __builtin_array_ridx (x + y, i, 4, j, 4), 4, 1, 4, 16);
+ }
+ 
+ extern "C" void abort (void);
+ 
+ int
+ main()
+ {
+   int A[8][16];
+   int B[4][4];
+   int i, j;
+   for (i=0; i<8; ++i)
+     for (j=0; j<16; ++j)
+       A[i][j] = 1;
+   for (i=0; i<4; ++i)
+     for (j=0; j<4; ++j)
+       B[i][j] = 2;
+   test(&A[0][0], &B[0][0]);
+   for (i=0; i<4; ++i)
+     for (j=8; j<12; ++j)
+       {
+         if (A[i][j] != 3)
+ 	  abort ();
+ 	A[i][j] = 1;
+       }
+   for (i=0; i<8; ++i)
+     for (j=0; j<16; ++j)
+       if (A[i][j] != 1)
+ 	abort ();
+   for (i=0; i<4; ++i)
+     for (j=0; j<4; ++j)
+       if (B[i][j] != 2)
+ 	abort ();
+   return 0;
+ }
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-2.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-2.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ test(float *A_, float *B_)
+ {
+   float (* A)[8][16] = (float (*)[8][16])A_;
+   float (* B)[8][16] = (float (*)[8][16])B_;
+   __builtin_array_store (A, B);
+ }
+ 
+ void
+ test_r(float *A_, float *B_)
+ {
+   float (* A)[8][16] = (float (*)[8][16])A_;
+   float (* B)[8][16] = (float (*)[8][16])B_;
+   int i, j;
+   for (i = 0; i < 8; ++i)
+     for (j = 0; j < 16; ++j)
+       (*A)[i][j] = (*B)[i][j];
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-3.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-3.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ test(float *A_, float *B_, int n, int m)
+ {
+   float (* A)[n][m] = (float (*)[n][m])A_;
+   float (* B)[n][m] = (float (*)[n][m])B_;
+   __builtin_array_store (A, B);
+ }
+ 
+ void
+ test_r(float *A_, float *B_, int n, int m)
+ {
+   float (* A)[n][m] = (float (*)[n][m])A_;
+   float (* B)[n][m] = (float (*)[n][m])B_;
+   int i, j;
+   for (i = 0; i < n; ++i)
+     for (j = 0; j < m; ++j)
+       (*A)[i][j] = (*B)[i][j];
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-4.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-4.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void __attribute__((noinline))
+ test(int *A_, int *B_)
+ {
+   int (* A)[4][4] = (int (*)[4][4])A_;
+   int (* B)[4][4] = (int (*)[4][4])B_;
+   int i, j, x;
+   x = __builtin_array_idx (__builtin_array_select (B, 4, 1, 4, 4), i, j);
+   x = x + 1;
+   x = x * i + j;
+   __builtin_array_store (A, __builtin_array_ridx (x, i, 4, j, 4));
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-5.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-5.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,43 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ void
+ matmul(float *w, float *u, float *v, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n][n] = (float (*)[n][n])w;
+   int i, j, k, l;
+   float Ukj, Vil, VUij;
+   Ukj = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, j);
+   Vil = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), i, l);
+   VUij = __builtin_array_delta (Vil * Ukj, m, k, l);
+   __builtin_array_store (W, __builtin_array_ridx (VUij, i, n, j, n), n, 1, n, n);
+ }
+ 
+ extern "C" void abort (void);
+ 
+ int
+ main()
+ {
+   float U[2][4], V[4][2], W[2][2];
+   int i, j, k;
+   __builtin_memset (U, 0, sizeof (U));
+   __builtin_memset (V, 0, sizeof (V));
+   __builtin_memset (W, 0, sizeof (W));
+   U[0][0] = 1.0;
+   U[1][1] = 1.0;
+   V[0][0] = 1.0;
+   V[1][1] = 1.0;
+   matmul (&W[0][0], &U[0][0], &V[0][0], 2, 4);
+   for (i = 0; i < 2; ++i)
+     for (j = 0; j < 2; ++j)
+       {
+ 	float sum = 0.0;
+         for (k = 0; k < 4; ++k)
+ 	  sum += U[i][k]*V[k][j];
+ 	if (sum != W[i][j])
+ 	  abort ();
+       }
+   return 0;
+ }
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-6.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-6.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,30 ----
+ /* { dg-do run } */
+ /* { dg-options "-O" } */
+ 
+ extern "C" void abort (void);
+ 
+ float
+ scalarprod (float *u, float *v, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   float (*V)[n] = (float (*)[n])v;
+   float Ui, Vj, res;
+   int i, j;
+   Ui = __builtin_array_idx (__builtin_array_select (U, n, 1), i);
+   Vj = __builtin_array_idx (__builtin_array_select (V, n, 1), j);
+   res = __builtin_array_delta (Ui * Vj, n, i, j);
+   return res;
+ }
+ 
+ int main()
+ {
+   float U[3] = {1, 1, 1}, V[3] = {1, 1, 1}, W;
+   int i;
+   float res = scalarprod (U, V, 3);
+   float sum = 0.0;
+   for (i = 0; i < 3; ++i)
+     sum += U[i]*V[i];
+   if (sum != res)
+     abort ();
+   return 0;
+ }
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-7.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-7.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,19 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ idx1 (float *u, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   int i;
+   __builtin_array_store (U, __builtin_array_ridx ((float)i, i, n), n, 1);
+ }
+ 
+ void
+ idx2 (int *v, int n)
+ {
+   int (*V)[n] = (int (*)[n])v;
+   int i;
+   __builtin_array_store (V, __builtin_array_ridx (i, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-8.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-8.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,23 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* This implements matrix-vector multiplication with the matrix
+    resulting from a matrix-matrix multiplication.  */
+ 
+ void
+ fancy (float *res, float *u, float *v, float *w, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n] = (float (*)[n])w;
+   float (*R)[n] = (float (*)[n])res;
+   int i, j, k;
+   float Uki, Vjk, Wj, VUij, Ri;
+   Uki = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, i);
+   Vjk = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), j, k);
+   Wj = __builtin_array_idx (__builtin_array_select (W, n, 1), j);
+   VUij = __builtin_array_delta (Vjk * Uki, m, k, k);
+   Ri = __builtin_array_delta (VUij * Wj, n, j, j);
+   __builtin_array_store (R, __builtin_array_ridx (Ri, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-9.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-9.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* This implements a vector norm of a matrix-vector multiplication
+    result with the matrix resulting from a matrix-matrix multiplication.  */
+ 
+ float
+ more_fancy (float *u, float *v, float *w, int n, int m)
+ {
+   float (*U)[n][m] = (float (*)[n][m])u;
+   float (*V)[m][n] = (float (*)[m][n])v;
+   float (*W)[n] = (float (*)[n])w;
+   int i, j, k;
+   float Uki, Vjk, Wj, VUij, Ri, norm;
+   Uki = __builtin_array_idx (__builtin_array_select (U, m, 1, n, m), k, i);
+   Vjk = __builtin_array_idx (__builtin_array_select (V, n, 1, m, n), j, k);
+   Wj = __builtin_array_idx (__builtin_array_select (W, n, 1), j);
+   VUij = __builtin_array_delta (Vjk * Uki, m, k, k);
+   Ri = __builtin_array_delta (VUij * Wj, n, j, j);
+   Ri = Ri * Ri;
+   norm = __builtin_array_delta (Ri, n, i);
+   return __builtin_sqrtf (norm);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-10.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-10.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,16 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* Compute the sum of the diagonal elements (trace) of the matrix A.  */
+ 
+ double
+ test(double *A_, int m, int n)
+ {
+   double (* A)[n][m] = (double (*)[n][m])A_;
+   int i, j;
+   double Aii, trace;
+   Aii = __builtin_array_idx (__builtin_array_select (A, m, 1, n, m), i, i);
+   trace = __builtin_array_delta (Aii, m < n ? m : n, i);
+   return trace;
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-11.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-11.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,17 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* Extract a vector with the diagonal elements from the matrix A.  */
+ 
+ void
+ test (double *B_, double *A_, int m, int n)
+ {
+   double (* A)[n][m] = (double (*)[n][m])A_;
+   int l = n > m ? m : n;
+   double (* B)[l] = (double (*)[l])B_;
+   int i, j;
+   double Aii;
+   Aii = __builtin_array_idx (__builtin_array_select (A, m, 1, n, m), i, i);
+   __builtin_array_store (B, __builtin_array_ridx (Aii, i, l), l, 1);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-12.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-12.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,17 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ void
+ test (float *u, float *v, int n)
+ {
+   float (*U)[n][n] = (float (*)[n][n])u;
+   float (*V)[n][n] = (float (*)[n][n])v;
+   int i, j, k;
+   float Uij, Vim1jm1, Vip1jp1, sum;
+   Uij = __builtin_array_idx (__builtin_array_select (&U[1][1], n-2, 1, n-2, n), i, j);
+   Vim1jm1 = __builtin_array_idx (__builtin_array_select (&V[0][0], n, 1, n, n), i, j);
+   Vip1jp1 = __builtin_array_idx (__builtin_array_select (&V[0][0], n, 1, n, n), i+2, j+2);
+   sum = Vim1jm1 + Vip1jp1;
+   __builtin_array_store (&U[1][1], __builtin_array_ridx (sum, i, n-2, j, n-2), n-2, 1, n-2, n);
+ }
+ 
Index: trunk/gcc/testsuite/g++.dg/tree-ssa/mea-10.C
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/g++.dg/tree-ssa/mea-10.C	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* U(:) = WHERE (U(:) < 0, 0) */
+ void
+ test (float *u, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   float Ui;
+   int i;
+   Ui = __builtin_array_idx (__builtin_array_select (U, n, 1), i);
+   Ui = Ui < 0.0 ? 0.0 : Ui;
+   __builtin_array_store (U, __builtin_array_ridx (Ui, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-13.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-13.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,10 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ int
+ test (int from, int to)
+ {
+   int i, sum;
+   sum = __builtin_array_delta (i + from, to - from, i);
+   return sum;
+ }
Index: trunk/gcc/testsuite/gcc.dg/mea-14.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-14.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,17 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* U = cV */
+ 
+ void
+ test (float *u, float *v, float *c, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   float (*V)[n] = (float (*)[n])v;
+   float Vi, cVi;
+   int i;
+   Vi = __builtin_array_idx (__builtin_array_select (V, n, 1), i);
+   cVi = *c * Vi;
+   __builtin_array_store (U, __builtin_array_ridx (cVi, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/testsuite/gcc.dg/mea-15.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- trunk/gcc/testsuite/gcc.dg/mea-15.c	2011-06-21 13:15:05.000000000 +0200
***************
*** 0 ****
--- 1,15 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O" } */
+ 
+ /* U(:) = WHERE (U(:) < 0, 0) */
+ void
+ test (float *u, int n)
+ {
+   float (*U)[n] = (float (*)[n])u;
+   float Ui;
+   int i;
+   Ui = __builtin_array_idx (__builtin_array_select (U, n, 1), i);
+   Ui = Ui < 0.0 ? 0.0 : Ui;
+   __builtin_array_store (U, __builtin_array_ridx (Ui, i, n), n, 1);
+ }
+ 
Index: trunk/gcc/gimple.c
===================================================================
*** trunk.orig/gcc/gimple.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/gimple.c	2011-06-21 13:15:05.000000000 +0200
*************** get_gimple_rhs_num_ops (enum tree_code c
*** 2598,2603 ****
--- 2598,2607 ----
        || (SYM) == ASSERT_EXPR						    \
        || (SYM) == ADDR_EXPR						    \
        || (SYM) == WITH_SIZE_EXPR					    \
+       || (SYM) == VLA_IDX_EXPR						    \
+       || (SYM) == VLA_RIDX_EXPR						    \
+       || (SYM) == VLA_DELTA_EXPR					    \
+       || (SYM) == VLA_VIEW_EXPR						    \
        || (SYM) == SSA_NAME						    \
        || (SYM) == VEC_COND_EXPR) ? GIMPLE_SINGLE_RHS			    \
     : GIMPLE_INVALID_RHS),
*************** is_gimple_lvalue (tree t)
*** 2644,2649 ****
--- 2648,2654 ----
  {
    return (is_gimple_addressable (t)
  	  || TREE_CODE (t) == WITH_SIZE_EXPR
+ 	  || TREE_CODE (t) == VLA_VIEW_EXPR
  	  /* These are complex lvalues, but don't have addresses, so they
  	     go here.  */
  	  || TREE_CODE (t) == BIT_FIELD_REF);
*************** is_gimple_reg (tree t)
*** 2926,2934 ****
    if (!is_gimple_variable (t))
      return false;
  
-   if (!is_gimple_reg_type (TREE_TYPE (t)))
-     return false;
- 
    /* A volatile decl is not acceptable because we can't reuse it as
       needed.  We need to copy it into a temp first.  */
    if (TREE_THIS_VOLATILE (t))
--- 2931,2936 ----
*************** is_gimple_reg (tree t)
*** 2955,2964 ****
    /* Complex and vector values must have been put into SSA-like form.
       That is, no assignments to the individual components.  */
    if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
!       || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
      return DECL_GIMPLE_REG_P (t);
  
!   return true;
  }
  
  
--- 2957,2967 ----
    /* Complex and vector values must have been put into SSA-like form.
       That is, no assignments to the individual components.  */
    if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
!       || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE
!       || TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
      return DECL_GIMPLE_REG_P (t);
  
!   return is_gimple_reg_type (TREE_TYPE (t));
  }
  
  
*************** get_base_address (tree t)
*** 3059,3064 ****
--- 3062,3070 ----
    while (handled_component_p (t))
      t = TREE_OPERAND (t, 0);
  
+   if (TREE_CODE (t) == VLA_VIEW_EXPR)
+     t = TREE_OPERAND (t, 1);
+ 
    if ((TREE_CODE (t) == MEM_REF
         || TREE_CODE (t) == TARGET_MEM_REF)
        && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
*************** get_base_loadstore (tree op)
*** 5187,5192 ****
--- 5193,5200 ----
  {
    while (handled_component_p (op))
      op = TREE_OPERAND (op, 0);
+   if (TREE_CODE (op) == VLA_VIEW_EXPR)
+     op = TREE_OPERAND (op, 1);
    if (DECL_P (op)
        || INDIRECT_REF_P (op)
        || TREE_CODE (op) == MEM_REF
Index: trunk/gcc/tree-ssa-alias.c
===================================================================
*** trunk.orig/gcc/tree-ssa-alias.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-ssa-alias.c	2011-06-21 13:15:05.000000000 +0200
*************** refs_may_alias_p_1 (ao_ref *ref1, ao_ref
*** 997,1010 ****
  			|| TREE_CODE (ref1->ref) == STRING_CST
  			|| handled_component_p (ref1->ref)
  			|| TREE_CODE (ref1->ref) == MEM_REF
! 			|| TREE_CODE (ref1->ref) == TARGET_MEM_REF)
  		       && (!ref2->ref
  			   || TREE_CODE (ref2->ref) == SSA_NAME
  			   || DECL_P (ref2->ref)
  			   || TREE_CODE (ref2->ref) == STRING_CST
  			   || handled_component_p (ref2->ref)
  			   || TREE_CODE (ref2->ref) == MEM_REF
! 			   || TREE_CODE (ref2->ref) == TARGET_MEM_REF));
  
    /* Decompose the references into their base objects and the access.  */
    base1 = ao_ref_base (ref1);
--- 997,1012 ----
  			|| TREE_CODE (ref1->ref) == STRING_CST
  			|| handled_component_p (ref1->ref)
  			|| TREE_CODE (ref1->ref) == MEM_REF
! 			|| TREE_CODE (ref1->ref) == TARGET_MEM_REF
! 			|| TREE_CODE (ref1->ref) == VLA_VIEW_EXPR)
  		       && (!ref2->ref
  			   || TREE_CODE (ref2->ref) == SSA_NAME
  			   || DECL_P (ref2->ref)
  			   || TREE_CODE (ref2->ref) == STRING_CST
  			   || handled_component_p (ref2->ref)
  			   || TREE_CODE (ref2->ref) == MEM_REF
! 			   || TREE_CODE (ref2->ref) == TARGET_MEM_REF
! 			   || TREE_CODE (ref2->ref) == VLA_VIEW_EXPR));
  
    /* Decompose the references into their base objects and the access.  */
    base1 = ao_ref_base (ref1);
Index: trunk/gcc/tree-ssa-sccvn.c
===================================================================
*** trunk.orig/gcc/tree-ssa-sccvn.c	2011-06-21 13:05:55.000000000 +0200
--- trunk/gcc/tree-ssa-sccvn.c	2011-06-21 13:15:05.000000000 +0200
*************** copy_reference_ops_from_ref (tree ref, V
*** 617,622 ****
--- 617,629 ----
  
        switch (temp.opcode)
  	{
+ 	case VLA_VIEW_EXPR:
+ 	case VLA_IDX_EXPR:
+ 	case VLA_RIDX_EXPR:
+ 	case VLA_DELTA_EXPR:
+ 	  /* FIXME.  */
+ 	  temp.op0 = ref;
+ 	  break;
  	case MEM_REF:
  	  /* The base address gets its own vn_reference_op_s structure.  */
  	  temp.op0 = TREE_OPERAND (ref, 1);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]