コード例 #1
0
ファイル: c-array-notation.c プロジェクト: AHelper/gcc
tree
build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
			   enum tree_code modifycode, location_t rhs_loc,
			   tree rhs, tree rhs_origtype)
{
  bool found_builtin_fn = false;
  tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
  tree array_expr = NULL_TREE;
  tree an_init = NULL_TREE;
  vec<tree> cond_expr = vNULL;
  tree body, loop_with_init = alloc_stmt_list();
  tree scalar_mods = NULL_TREE;
  vec<tree, va_gc> *rhs_array_operand = NULL, *lhs_array_operand = NULL;
  size_t lhs_rank = 0, rhs_rank = 0;
  size_t ii = 0;
  vec<tree, va_gc> *lhs_list = NULL, *rhs_list = NULL;
  tree new_modify_expr, new_var = NULL_TREE, builtin_loop = NULL_TREE;
  size_t rhs_list_size = 0, lhs_list_size = 0; 
  vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
  vec<an_loop_parts> lhs_an_loop_info = vNULL, rhs_an_loop_info = vNULL;
  
  /* If either of this is true, an error message must have been send out
     already.  Not necessary to send out multiple error messages.  */
  if (lhs == error_mark_node || rhs == error_mark_node)
    return error_mark_node;
  
  if (!find_rank (location, rhs, rhs, false, &rhs_rank))
    return error_mark_node;
  
  extract_array_notation_exprs (rhs, false, &rhs_list);
  rhs_list_size = vec_safe_length (rhs_list);
  an_init = push_stmt_list ();
  if (rhs_rank)
    {
      scalar_mods = replace_invariant_exprs (&rhs);
      if (scalar_mods)
	add_stmt (scalar_mods);
    }
  for (ii = 0; ii < rhs_list_size; ii++)
    {
      tree rhs_node = (*rhs_list)[ii];
      if (TREE_CODE (rhs_node) == CALL_EXPR)
	{
	  builtin_loop = fix_builtin_array_notation_fn (rhs_node, &new_var);
	  if (builtin_loop == error_mark_node)
	    {
	      pop_stmt_list (an_init); 
	      return error_mark_node;
	    }
	  else if (builtin_loop)
	    {
	      add_stmt (builtin_loop);
	      found_builtin_fn = true;
	      if (new_var)
		{
		  vec<tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
		  vec_safe_push (rhs_sub_list, rhs_node);
		  vec_safe_push (new_var_list, new_var);
		  replace_array_notations (&rhs, false, rhs_sub_list,
					   new_var_list);
		}
	    }
	}
    }

  lhs_rank = 0;
  rhs_rank = 0;
  if (!find_rank (location, lhs, lhs, true, &lhs_rank))
    {
      pop_stmt_list (an_init);
      return error_mark_node;
    }
  
  if (!find_rank (location, rhs, rhs, true, &rhs_rank))
    {
      pop_stmt_list (an_init);
      return error_mark_node;
    }

  if (lhs_rank == 0 && rhs_rank == 0)
    {
      if (found_builtin_fn)
	{
	  new_modify_expr = build_modify_expr (location, lhs, lhs_origtype,
					       modifycode, rhs_loc, rhs,
					       rhs_origtype);
	  add_stmt (new_modify_expr);
	  pop_stmt_list (an_init);	  
	  return an_init;
	}
      else
	{
	  pop_stmt_list (an_init);
	  return NULL_TREE;
	}
    }
  rhs_list_size = 0;
  rhs_list = NULL;
  extract_array_notation_exprs (rhs, true, &rhs_list);
  extract_array_notation_exprs (lhs, true, &lhs_list);
  rhs_list_size = vec_safe_length (rhs_list);
  lhs_list_size = vec_safe_length (lhs_list);
  
  if (lhs_rank == 0 && rhs_rank != 0)
    {
      tree rhs_base = rhs;
      if (TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
	{
	  for (ii = 0; ii < (size_t) rhs_rank; ii++)
	    rhs_base = ARRAY_NOTATION_ARRAY (rhs);
      
	  error_at (location, "%qE cannot be scalar when %qE is not", lhs,
		    rhs_base);
	  return error_mark_node;
	}
      else
	{
	  error_at (location, "%qE cannot be scalar when %qE is not", lhs,
		    rhs_base);
	  return error_mark_node;
	}
    }
  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
    {
      error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
      pop_stmt_list (an_init);
      return error_mark_node;
    }
  
  /* Here we assign the array notation components to variable so that we can
     satisfy the exec once rule.  */
  for (ii = 0; ii < lhs_list_size; ii++)
    { 
      tree array_node = (*lhs_list)[ii];
      make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
      make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
      make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
    }
  for (ii = 0; ii < rhs_list_size; ii++)
    if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
      {  
	tree array_node = (*rhs_list)[ii];
	make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
	make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
	make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
      }
  
  cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));

  lhs_an_loop_info.safe_grow_cleared (lhs_rank);
  if (rhs_rank)
    rhs_an_loop_info.safe_grow_cleared (rhs_rank);

  cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
				&lhs_an_info);
  if (rhs_rank)
    {
      rhs_an_loop_info.safe_grow_cleared (rhs_rank);
      cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
				    &rhs_an_info);
    }
  if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
      || (rhs_rank
	  && length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_an_info)))
    {
      pop_stmt_list (an_init);
      return error_mark_node;
    }
  if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
      && TREE_CODE (lhs_an_info[0][0].length) == INTEGER_CST
      && rhs_an_info[0][0].length
      && TREE_CODE (rhs_an_info[0][0].length) == INTEGER_CST)
    {
      HOST_WIDE_INT l_length = int_cst_value (lhs_an_info[0][0].length);
      HOST_WIDE_INT r_length = int_cst_value (rhs_an_info[0][0].length);
      /* Length can be negative or positive.  As long as the magnitude is OK,
	 then the array notation is valid.  */
      if (absu_hwi (l_length) != absu_hwi (r_length))
	{
	  error_at (location, "length mismatch between LHS and RHS");
	  pop_stmt_list (an_init);
	  return error_mark_node;
	}
    }
  for (ii = 0; ii < lhs_rank; ii++)
    if (lhs_an_info[0][ii].is_vector)
      {
	lhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
	lhs_an_loop_info[ii].ind_init = build_modify_expr
	  (location, lhs_an_loop_info[ii].var,
	   TREE_TYPE (lhs_an_loop_info[ii].var), NOP_EXPR,
	   location, build_zero_cst (TREE_TYPE (lhs_an_loop_info[ii].var)),
	   TREE_TYPE (lhs_an_loop_info[ii].var));
      }
  for (ii = 0; ii < rhs_rank; ii++)
    {
      /* When we have a polynomial, we assume that the indices are of type 
	 integer.  */
      rhs_an_loop_info[ii].var = create_tmp_var (integer_type_node);
      rhs_an_loop_info[ii].ind_init = build_modify_expr
	(location, rhs_an_loop_info[ii].var,
	 TREE_TYPE (rhs_an_loop_info[ii].var), NOP_EXPR,
	 location, build_int_cst (TREE_TYPE (rhs_an_loop_info[ii].var), 0),
	 TREE_TYPE (rhs_an_loop_info[ii].var));
    }
  if (lhs_rank)
    {
      lhs_array_operand = create_array_refs
	(location, lhs_an_info, lhs_an_loop_info, lhs_list_size, lhs_rank);
      replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
      array_expr_lhs = lhs;
    }
  if (rhs_array_operand)
    vec_safe_truncate (rhs_array_operand, 0);
  if (rhs_rank)
    {
      rhs_array_operand = create_array_refs
	(location, rhs_an_info, rhs_an_loop_info, rhs_list_size, rhs_rank);
      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
      vec_safe_truncate (rhs_array_operand, 0);
      rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
						 rhs_an_loop_info, rhs_rank,
						 rhs);
      if (!rhs_array_operand)
	return error_mark_node;
      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
    }
  else if (rhs_list_size > 0)
    {
      rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
						 lhs_an_loop_info, lhs_rank,
						 lhs);
      if (!rhs_array_operand)
	return error_mark_node;
      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
    }
  array_expr_lhs = lhs;
  array_expr_rhs = rhs;
  array_expr = build_modify_expr (location, array_expr_lhs, lhs_origtype, 
				  modifycode, rhs_loc, array_expr_rhs, 
				  rhs_origtype);
  create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info);
  if (rhs_rank)
    create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info);
  
  for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
    if (ii < lhs_rank && ii < rhs_rank)
      cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, boolean_type_node,
			      lhs_an_loop_info[ii].cmp,
			      rhs_an_loop_info[ii].cmp);
    else if (ii < lhs_rank && ii >= rhs_rank)
      cond_expr[ii] = lhs_an_loop_info[ii].cmp;
    else
      gcc_unreachable ();

  an_init = pop_stmt_list (an_init);
  append_to_statement_list_force (an_init, &loop_with_init);
  body = array_expr;
  for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
    {
      tree incr_list = alloc_stmt_list ();
      tree new_loop = push_stmt_list ();
      if (lhs_rank)
	add_stmt (lhs_an_loop_info[ii].ind_init);
      if (rhs_rank)
	add_stmt (rhs_an_loop_info[ii].ind_init);
      if (lhs_rank)
	append_to_statement_list_force (lhs_an_loop_info[ii].incr, &incr_list);
      if (rhs_rank && rhs_an_loop_info[ii].incr)
	append_to_statement_list_force (rhs_an_loop_info[ii].incr, &incr_list);
      c_finish_loop (location, cond_expr[ii], incr_list, body, NULL_TREE,
		     NULL_TREE, true);
      body = pop_stmt_list (new_loop);
    }
  append_to_statement_list_force (body, &loop_with_init);

  lhs_an_info.release ();
  lhs_an_loop_info.release ();
  if (rhs_rank)
    {
      rhs_an_info.release ();
      rhs_an_loop_info.release ();
    }
  cond_expr.release ();
  return loop_with_init;
}
コード例 #2
0
ファイル: cp-array-notation.c プロジェクト: chinabin/gcc-tiny
static tree
expand_an_in_modify_expr (location_t location, tree lhs,
			  enum tree_code modifycode, tree rhs,
			  tsubst_flags_t complain)
{
  tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
  tree array_expr = NULL_TREE;
  tree body = NULL_TREE;
  auto_vec<tree> cond_expr;
  vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL;
  size_t lhs_rank = 0, rhs_rank = 0, ii = 0;
  vec<tree, va_gc> *rhs_list = NULL, *lhs_list = NULL;
  size_t rhs_list_size = 0, lhs_list_size = 0;
  tree new_modify_expr, new_var = NULL_TREE, builtin_loop, scalar_mods;
  bool found_builtin_fn = false;
  tree an_init, loop_with_init = alloc_stmt_list ();
  vec<vec<an_parts> > lhs_an_info = vNULL, rhs_an_info = vNULL;
  auto_vec<an_loop_parts> lhs_an_loop_info, rhs_an_loop_info;
  tree lhs_len, rhs_len;

  if (!find_rank (location, rhs, rhs, false, &rhs_rank))
    return error_mark_node;
  extract_array_notation_exprs (rhs, false, &rhs_list);
  rhs_list_size = vec_safe_length (rhs_list);
  an_init = push_stmt_list ();
  if (rhs_rank)
    {
      scalar_mods = replace_invariant_exprs (&rhs);
      if (scalar_mods)
	finish_expr_stmt (scalar_mods);
    }
  for (ii = 0; ii < rhs_list_size; ii++)
    {
      tree rhs_node = (*rhs_list)[ii];
      if (TREE_CODE (rhs_node) == CALL_EXPR)
	{
	  builtin_loop = expand_sec_reduce_builtin (rhs_node, &new_var);
	  if (builtin_loop == error_mark_node)
	    return error_mark_node;
	  else if (builtin_loop)
	    {
	      finish_expr_stmt (builtin_loop);
	      found_builtin_fn = true;
	      if (new_var)
		{
		  vec <tree, va_gc> *rhs_sub_list = NULL, *new_var_list = NULL;
		  vec_safe_push (rhs_sub_list, rhs_node);
		  vec_safe_push (new_var_list, new_var);
		  replace_array_notations (&rhs, false, rhs_sub_list,
					   new_var_list);
		}
	    }
	}
    }
  lhs_rank = 0;
  rhs_rank = 0;
  if (!find_rank (location, lhs, lhs, true, &lhs_rank)
      || !find_rank (location, rhs, rhs, true, &rhs_rank))
    {
      pop_stmt_list (an_init);
      return error_mark_node;
    }

  /* If both are scalar, then the only reason why we will get this far is if
     there is some array notations inside it and was using a builtin array
     notation functions.  If so, we have already broken those guys up and now 
     a simple build_x_modify_expr would do.  */
  if (lhs_rank == 0 && rhs_rank == 0)
    {
      if (found_builtin_fn)
	{
	  new_modify_expr = build_x_modify_expr (location, lhs,
						 modifycode, rhs, complain);
	  finish_expr_stmt (new_modify_expr);
	  pop_stmt_list (an_init);
	  return an_init;
	}
      else
	gcc_unreachable ();
    }

  /* If for some reason location is not set, then find if LHS or RHS has
     location info.  If so, then use that so we atleast have an idea.  */
  if (location == UNKNOWN_LOCATION)
    {
      if (EXPR_LOCATION (lhs) != UNKNOWN_LOCATION)
	location = EXPR_LOCATION (lhs);
      else if (EXPR_LOCATION (rhs) != UNKNOWN_LOCATION)
	location = EXPR_LOCATION (rhs);
    }
      
  /* We need this when we have a scatter issue.  */
  extract_array_notation_exprs (lhs, true, &lhs_list);
  rhs_list = NULL;
  extract_array_notation_exprs (rhs, true, &rhs_list);
  rhs_list_size = vec_safe_length (rhs_list);
  lhs_list_size = vec_safe_length (lhs_list);
    
  if (lhs_rank == 0 && rhs_rank != 0)
    {
      error_at (location, "%qE cannot be scalar when %qE is not", lhs, rhs);
      return error_mark_node;
    }
  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
    {
      error_at (location, "rank mismatch between %qE and %qE", lhs, rhs);
      return error_mark_node;
    }
  
  /* Assign the array notation components to variable so that they can satisfy
     the execute-once rule.  */
  for (ii = 0; ii < lhs_list_size; ii++)
    {
      tree anode = (*lhs_list)[ii];
      make_triplet_val_inv (&ARRAY_NOTATION_START (anode));
      make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (anode));
      make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (anode));
    }
  for (ii = 0; ii < rhs_list_size; ii++)
    if ((*rhs_list)[ii] && TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
      {
	tree aa = (*rhs_list)[ii];
	make_triplet_val_inv (&ARRAY_NOTATION_START (aa));
	make_triplet_val_inv (&ARRAY_NOTATION_LENGTH (aa));
	make_triplet_val_inv (&ARRAY_NOTATION_STRIDE (aa));
      }
  lhs_an_loop_info.safe_grow_cleared (lhs_rank);
  
  if (rhs_rank)
    rhs_an_loop_info.safe_grow_cleared (rhs_rank);

  cond_expr.safe_grow_cleared (MAX (lhs_rank, rhs_rank));
  cilkplus_extract_an_triplets (lhs_list, lhs_list_size, lhs_rank,
				&lhs_an_info);
  if (rhs_list)
    cilkplus_extract_an_triplets (rhs_list, rhs_list_size, rhs_rank,
				  &rhs_an_info);
  if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_an_info)
      || (rhs_list && length_mismatch_in_expr_p (EXPR_LOCATION (rhs),
						 rhs_an_info)))
    {
      pop_stmt_list (an_init);
      goto error;
    }
  rhs_len = ((rhs_list_size > 0 && rhs_rank > 0) ?
    rhs_an_info[0][0].length : NULL_TREE);
  lhs_len = ((lhs_list_size > 0 && lhs_rank > 0) ?
    lhs_an_info[0][0].length : NULL_TREE);
  if (lhs_list_size > 0 && rhs_list_size > 0 && lhs_rank > 0 && rhs_rank > 0
      && TREE_CODE (lhs_len) == INTEGER_CST && rhs_len
      && TREE_CODE (rhs_len) == INTEGER_CST 
      && !tree_int_cst_equal (rhs_len, lhs_len))
    { 
      error_at (location, "length mismatch between LHS and RHS"); 
      pop_stmt_list (an_init); 
      goto error;
    }
   for (ii = 0; ii < lhs_rank; ii++) 
     {
       tree typ = ptrdiff_type_node; 
       lhs_an_loop_info[ii].var = create_temporary_var (typ);
       add_decl_expr (lhs_an_loop_info[ii].var);
       lhs_an_loop_info[ii].ind_init = build_x_modify_expr 
	 (location, lhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), 
	  complain);
     }
   
   if (rhs_list_size > 0)
     {
       rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
						  lhs_an_loop_info, lhs_rank,
						  lhs); 
       if (!rhs_array_operand)
	 goto error;
     }
  replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
  rhs_list_size = 0;
  rhs_list = NULL;
  extract_array_notation_exprs (rhs, true, &rhs_list);
  rhs_list_size = vec_safe_length (rhs_list);    

  for (ii = 0; ii < rhs_rank; ii++)
    {
      tree typ = ptrdiff_type_node;
      rhs_an_loop_info[ii].var = create_temporary_var (typ);
      add_decl_expr (rhs_an_loop_info[ii].var);
      rhs_an_loop_info[ii].ind_init = build_x_modify_expr
	(location, rhs_an_loop_info[ii].var, INIT_EXPR, build_zero_cst (typ), 
	 complain);
    }

  if (lhs_rank)
    {
      lhs_array_operand =
	create_array_refs (location, lhs_an_info, lhs_an_loop_info,
			    lhs_list_size, lhs_rank);
      replace_array_notations (&lhs, true, lhs_list, lhs_array_operand);
    }
  
  if (rhs_array_operand)
    vec_safe_truncate (rhs_array_operand, 0);
  if (rhs_rank)
    {
      rhs_array_operand = create_array_refs (location, rhs_an_info,
					      rhs_an_loop_info, rhs_list_size,
					      rhs_rank);
      /* Replace all the array refs created by the above function because this
	 variable is blown away by the fix_sec_implicit_args function below.  */
      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
      vec_safe_truncate (rhs_array_operand , 0);
      rhs_array_operand = fix_sec_implicit_args (location, rhs_list,
						 rhs_an_loop_info, rhs_rank,
						 rhs);
      if (!rhs_array_operand)
	goto error;
      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
    }

  array_expr_rhs = rhs;
  array_expr_lhs = lhs;
  
  array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode,
				    array_expr_rhs, complain);
  create_cmp_incr (location, &lhs_an_loop_info, lhs_rank, lhs_an_info,
		   complain);
  if (rhs_rank) 
    create_cmp_incr (location, &rhs_an_loop_info, rhs_rank, rhs_an_info, 
		     complain);
  for (ii = 0; ii < MAX (rhs_rank, lhs_rank); ii++)
    if (ii < lhs_rank && ii < rhs_rank)
      cond_expr[ii] = build_x_binary_op
	(location, TRUTH_ANDIF_EXPR, lhs_an_loop_info[ii].cmp,
	 TREE_CODE (lhs_an_loop_info[ii].cmp), rhs_an_loop_info[ii].cmp,
	 TREE_CODE (rhs_an_loop_info[ii].cmp), NULL, complain);
    else if (ii < lhs_rank && ii >= rhs_rank)
      cond_expr[ii] = lhs_an_loop_info[ii].cmp;
    else
      /* No need to compare ii < rhs_rank && ii >= lhs_rank because in a valid 
	 Array notation expression, rank of RHS cannot be greater than LHS.  */
      gcc_unreachable ();
  
  an_init = pop_stmt_list (an_init);
  append_to_statement_list (an_init, &loop_with_init);
  body = array_expr;
  for (ii = 0; ii < MAX (lhs_rank, rhs_rank); ii++)
    {
      tree incr_list = alloc_stmt_list ();
      tree init_list = alloc_stmt_list ();
      tree new_loop = push_stmt_list ();

      if (lhs_rank)
	{
	  append_to_statement_list (lhs_an_loop_info[ii].ind_init, &init_list);
	  append_to_statement_list (lhs_an_loop_info[ii].incr, &incr_list);
	}
      if (rhs_rank)
	{
	  append_to_statement_list (rhs_an_loop_info[ii].ind_init, &init_list);
	  append_to_statement_list (rhs_an_loop_info[ii].incr, &incr_list);
	}
      create_an_loop (init_list, cond_expr[ii], incr_list, body);
      body = pop_stmt_list (new_loop);
    }
  append_to_statement_list (body, &loop_with_init);

  release_vec_vec (lhs_an_info);
  release_vec_vec (rhs_an_info);

  return loop_with_init;

error:
  release_vec_vec (lhs_an_info);
  release_vec_vec (rhs_an_info);

  return error_mark_node;
}
コード例 #3
0
ファイル: c-array-notation.c プロジェクト: AHelper/gcc
static tree
fix_array_notation_call_expr (tree arg)
{
  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
  tree new_var = NULL_TREE;
  size_t list_size = 0, rank = 0, ii = 0;
  tree loop_init;
  tree body, loop_with_init = alloc_stmt_list ();
  location_t location = UNKNOWN_LOCATION;
  vec<vec<an_parts> > an_info = vNULL;
  vec<an_loop_parts> an_loop_info = vNULL;

  if (TREE_CODE (arg) == CALL_EXPR
      && is_cilkplus_reduce_builtin (CALL_EXPR_FN (arg)))
    {
      loop_init = fix_builtin_array_notation_fn (arg, &new_var);
      /* We are ignoring the new var because either the user does not want to
	 capture it OR he is using sec_reduce_mutating function.  */
      return loop_init;
    }  
  if (!find_rank (location, arg, arg, false, &rank))
    return error_mark_node;
  
  if (rank == 0)
    return arg;
  
  extract_array_notation_exprs (arg, true, &array_list);
  if (vec_safe_length (array_list) == 0)
    return arg;
  
  list_size = vec_safe_length (array_list);
  location = EXPR_LOCATION (arg);
  an_loop_info.safe_grow_cleared (rank);
  
  loop_init = push_stmt_list ();
  for (ii = 0; ii < list_size; ii++)
    if ((*array_list)[ii]
	&& TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
	{
	  tree array_node = (*array_list)[ii];
	  make_triplet_val_inv (location, &ARRAY_NOTATION_START (array_node));
	  make_triplet_val_inv (location, &ARRAY_NOTATION_LENGTH (array_node));
	  make_triplet_val_inv (location, &ARRAY_NOTATION_STRIDE (array_node));
	}
  cilkplus_extract_an_triplets (array_list, list_size, rank, &an_info);
  if (length_mismatch_in_expr_p (location, an_info))
    {
      pop_stmt_list (loop_init);
      return error_mark_node;
    }
  for (ii = 0; ii < rank; ii++)
    {
      an_loop_info[ii].var = create_tmp_var (integer_type_node);
      an_loop_info[ii].ind_init =
	build_modify_expr (location, an_loop_info[ii].var,
			   TREE_TYPE (an_loop_info[ii].var), NOP_EXPR, location,
			   build_int_cst (TREE_TYPE (an_loop_info[ii].var), 0),
			   TREE_TYPE (an_loop_info[ii].var));
	
    }
  array_operand = create_array_refs (location, an_info, an_loop_info,
				     list_size, rank);
  replace_array_notations (&arg, true, array_list, array_operand);
  create_cmp_incr (location, &an_loop_info, rank, an_info);
  loop_init = pop_stmt_list (loop_init);
  append_to_statement_list_force (loop_init, &loop_with_init);
  body = arg;
  for (ii = 0; ii < rank; ii++)
    {
      tree new_loop = push_stmt_list ();
      add_stmt (an_loop_info[ii].ind_init);
      c_finish_loop (location, an_loop_info[ii].cmp, an_loop_info[ii].incr,
		     body, NULL_TREE, NULL_TREE, true);
      body = pop_stmt_list (new_loop);
    }
  append_to_statement_list_force (body, &loop_with_init);
  an_loop_info.release ();
  an_info.release ();
  return loop_with_init;
}