diff mbox

Cilk Plus Array Notation for C++

Message ID BF230D13CA30DD48930C31D4099330003A42E4B8@FMSMSX101.amr.corp.intel.com
State New
Headers show

Commit Message

Iyer, Balaji V June 12, 2013, 8:49 p.m. UTC
Hi Aldy,
	Please see my comments below with the fixed patch.

Thanks,

Balaji V. Iyer.

> -----Original Message-----
> From: Aldy Hernandez [mailto:aldyh@redhat.com]
> Sent: Wednesday, June 12, 2013 12:34 PM
> To: Iyer, Balaji V
> Cc: gcc-patches@gcc.gnu.org; Jason Merrill (jason@redhat.com);
> rth@redhat.com
> Subject: Re: [PATCH] Cilk Plus Array Notation for C++
> 
> [Jason/Richard: there are some things below I could use your feedback on.]
> 
> Hi Balaji.
> 
> Overall, a lot of the stuff in cp-array-notation.c looks familiar from the C front-
> end changes.  Can't you reuse a lot of it?
> 
> Otherwise, here are some minor nits...
> 
> > +      /* If the function call is builtin array notation function then we do not
> > +	 need to do any type conversion.  */
> > +      if (flag_enable_cilkplus && fn && TREE_CODE (fn) == FUNCTION_DECL
> > +	  && DECL_NAME (fn) && IDENTIFIER_POINTER (DECL_NAME (fn))
> > +	  && !strncmp (IDENTIFIER_POINTER (DECL_NAME (fn)),
> "__sec_reduce", 12))
> > +	val = arg;
> 
> Don't we have BUILT_IN_CILKPLUS_SEC_REDUCE* now?  So you shouldn't need
> to poke at the actual identifier.  And even so, won't the above strncmp match
> __sec_reducegarbage?

FIXED!

> 
> > +/* This function parses Cilk Plus array notations.  The starting index is
> > +   passed in INIT_INDEX and the array name is passed in ARRAY_VALUE.  The
> > +   return value of this function is a tree node called VALUE_TREE of type
> > +   ARRAY_NOTATION_REF.  If some error occurred it returns
> > +error_mark_node.  */
> > +
> 
> It looks like a NULL in INIT_INDEX is a specially handled case.  Perhaps you
> should document that INIT_INDEX can be null and what it means.
> Also, you don't need to document what internal variable name you are using as
> a return value (VALUE_TREE).  Perhaps instead of "The return value..." you could
> write "This function returns the ARRAY_NOTATION_REF node." or something
> like it.

It is documented inside the function, right before checking for !init_index. Is that enough?

> 
> > +    case ARRAY_NOTATION_REF:
> > +      {
> > +	tree start_index, length, stride;
> > +	op1 = tsubst_non_call_postfix_expression (ARRAY_NOTATION_ARRAY
> (t),
> > +						  args, complain, in_decl);
> > +	start_index = RECUR (ARRAY_NOTATION_START (t));
> > +	length = RECUR (ARRAY_NOTATION_LENGTH (t));
> > +	stride = RECUR (ARRAY_NOTATION_STRIDE (t));
> > +
> > +	/* We do type-checking here for templatized array notation triplets.  */
> > +	if (!TREE_TYPE (start_index)
> > +	    || !INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
> > +	  {
> > +	    error_at (loc, "start-index of array notation triplet is not an "
> > +		      "integer");
> > +	    RETURN (error_mark_node);
> > +	  }
> > +	if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length)))
> > +	  {
> > +	    error_at (loc, "length of array notation triplet is not an "
> > +		      "integer");
> > +	    RETURN (error_mark_node);
> > +	  }
> > +	if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
> > +	  {
> > +	    error_at (loc, "stride of array notation triplet is not an "
> > +		      "integer");
> > +	    RETURN (error_mark_node);
> > +	  }
> > +	if (TREE_CODE (TREE_TYPE (op1)) == FUNCTION_TYPE)
> > +	  {
> > +	    error_at (loc, "array notations cannot be used with function type");
> > +	    RETURN (error_mark_node);
> > +	  }
> > +	RETURN (build_array_notation_ref (EXPR_LOCATION (t), op1,
> start_index,
> > +					  length, stride, TREE_TYPE (op1)));
> > +      }
> 
> 
> You do all this type checking here, but aren't you doing the same type checking
> in build_array_notation_ref() which you're going to call anyway?  It looks like
> there is some code duplication going on.
> 
> Also, I see you have a build_array_notation_ref() in cp/cp-array-notation.c and
> also in c/c-array-notation.c.  Can you not implement one function that handles
> both C and C++, or at the very least reuse some of the common things?

As we discussed in the previous email-exchange, I have created a new function called cilkplus_an_triplet_types_ok_p (). The reason why I prefixed "cilkplus_an" is because it is not a static function and I want to make sure this is unique and descriptive and does not cause any interference with anything present or future. 

> 
> You are missing a ChangeLog entry for the above snippet.

I have put it in now.

> 
> > +      /* If the return expr. has a builtin array notation function, then its
> > +	 OK.  */
> > +      if (rank >= 1)
> > +	{
> > +	  error_at (input_location, "array notation expression cannot be "
> > +		    "used as a return value");
> > +	  return error_mark_node;
> > +	}
> 
> The comment doesn't seem to match the code, or am I missing something?
> 
> > +      /* If find_rank returns false,  then it should have reported an
> > + error,

FIXED

> 
> Extra whitespace.
> 
> > +      if (rank > 1)
> > +	{
> > +	  error_at (loc, "rank of the array%'s index is greater than 1");
> > +	  return error_mark_node;
> > +	}
> 
> No corresponding test.

This is being tested in the file "testsuite/c-c++-common/cilk-plus/AN/gather-scatter-errors.c"

> 
> > +  /* If we are dealing with built-in array notation function then we don't need
> > +     to convert them. They will be broken up into modify exprs in future,
> > +     during which all these checks will be done.  */
> 
> Line too long, please wrap.
> 
> There are various lines throughout your patch that are pretty long (both in code
> and in ChangeLog entries).  I don't know what the official GNU guidelines say,
> but what I usually see as prior art in the GCC code base is something along the
> lines of wrapping around column 72.  Perhaps someone can pontificate on this,
> but lines reaching the 78-80 columns look pretty darn long to me.

The line length is specified to be at most 80 characters (http://gcc.gnu.org/codingconventions.html#Line). I have followed it everywhere except in the cases of dg-error since I can't fit them all in one line.
> 
> > diff --git gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c
> > gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c
> > index c22b818..b863276 100644
> > --- gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c
> > +++ gcc/testsuite/c-c++-common/cilk-plus/AN/sec_implicit_ex.c
> > @@ -1,9 +1,6 @@
> >  /* { dg-do run } */
> >  /* { dg-options "-fcilkplus" } */
> >
> > -void abort (void);
> > -void exit  (int);
> > -
> >
> >  int main(void)
> >  {
> > @@ -24,10 +21,7 @@ int main(void)
> >      for (jj = 0; jj < 10; jj++)
> >        for (kk = 0; kk < 10; kk++)
> >  	if (array_3[ii][jj][kk] != array_3C[ii][jj][kk])
> > -	  abort ();
> > +	  return 1;
> >
> > -
> > -  exit (0);
> > -
>  >   return 0;
> 
> Changes to existing tests should be submitted as a separate patch, since this
> doesn't seem to be C++ specific.  And BTW, this particular test change can be
> committed as obvious.

OK will do.  What about adding {target c} and {target c++} for test cases. Can that be submitted with the patch?

> 
> > +  int    iarray[10], iarray2[10], i_result, i_max;
> > +  long   larray[10], larray2[10], l_result, l_max;
> > +  float  farray[10], farray2[10], f_result, f_max;
> > +  double darray[10], darray2[10], d_result, d_max; #if 1
> > +  for (int ii = 0; ii < 10; ii++)
> > +    {
> > +      if (ii%2 && ii)
> 
> Remove this redundant #if 1/#endif pair.  Similarly in other tests.

FIXED!

> 
> > +	    if (flag_enable_cilkplus
> > +		&& contains_array_notation_expr (condition))
> > +	      {
> > +		error_at (EXPR_LOCATION (condition),
> > +			  "array notations cannot be used as a condition for "
> > +			  "switch statement");
> 
> No corresponding test, or is this handled by the existing
> c-c++-common/cilk-plus tests?

Please see c-c++-common/cilk-plus/AN/misc.c

> 
> > +		  /* This could be a function ptr.  If so, then emit error.  */
> > +		  subtype = TREE_TYPE (subtype);
> > +		  if (subtype && TREE_CODE (subtype) == FUNCTION_TYPE)
> > +		    {
> > +		      error_at (loc, "array notations cannot be used with"
> > +				" function pointer arrays");
> 
> No need to document the obvious.  The error message can be used in lieu of the
> comment :).  Also, no corresponding test.  I didn't see one matching in c-c++-
> common/cilkplus either.

OK. This testcase (testsuite/c-c++-common/cilk-plus/AN/fn_ptr.c) checks this error.

> 
> > +	      /* Disable correcting single colon correcting to scope.  */
> > +	      parser->colon_corrects_to_scope_p = false;
> 
> No need to document the obvious.

FIXED!

> 
> I suggest a different name for fix_array_notation_exprs() to avoid confusion
> with the C function fix_array_notation_expr() (no final "s").
>   Perhaps cpp_fix_array_notation_expr, or something similar?
> 
> > +/* Handles expression of the form "a[i:j:k]" or "a[:]" or "a[i:j]," which
> > +   denotes an array notation expression.  If a is a variable or a
> > +member, then
> 
> Do you mean "ARRAY" instead of "a"?
> 
> > +   we generate a ARRAY_NOTATION_REF front-end tree and return it.
> 
> s/a ARRAY/an ARRAY/
> 
> > +   This tree is broken down to ARRAY_REF toward the end of parsing.
> > +   ARRAY_NOTATION_REF tree holds the START_INDEX, LENGTH, STRIDE and
> the TYPE
> > +   of ARRAY_REF.  Restrictions on START_INDEX, LENGTH and STRIDE is same
> as that
> > +   of the index field passed into ARRAY_REF.  The only additional restriction
> > +   is that, unlike index in ARRAY_REF, stride, length and start_index cannot
> > +   contain ARRAY_NOTATIONS.   */
> > +
> > +tree
> > +build_array_notation_ref (location_t loc, tree array, tree start_index,
> > +			  tree length, tree stride, tree type)
> 
> Overall this function comment needs to be reworded.  From reading the
> comment, I still don't know what the function actually does and what it returns.
> "Handles expression..." is rather ambiguous.  Perhaps something like "Given a
> blah blah blah in ARRAY, construct an ARRAY_NOTATION_REF and return it.
> START_INDEX is blah, LENGTH is blah, etc etc".

Reworded it. Please let me know if it is OK.

> 
> Again, you can probably reuse a lot of the C counterpart.  It looks like a lot of
> the same code.
> 
> > +  XDELETEVEC (compare_expr);
> > +  XDELETEVEC (expr_incr);
> > +  XDELETEVEC (ind_init);
> > +  XDELETEVEC (array_var);
> > +
> > +  for (ii = 0; ii < list_size; ii++)
> > +    {
> > +      XDELETEVEC (count_down[ii]);
> > +      XDELETEVEC (array_value[ii]);
> > +      XDELETEVEC (array_stride[ii]);
> > +      XDELETEVEC (array_length[ii]);
> > +      XDELETEVEC (array_start[ii]);
> > +      XDELETEVEC (array_ops[ii]);
> > +      XDELETEVEC (array_vector[ii]);
> > +    }
> > +
> > +  XDELETEVEC (count_down);
> > +  XDELETEVEC (array_value);
> > +  XDELETEVEC (array_stride);
> > +  XDELETEVEC (array_length);
> > +  XDELETEVEC (array_start);
> > +  XDELETEVEC (array_ops);
> > +  XDELETEVEC (array_vector);
> 
> I see a lot of this business going on.  Perhaps one of the core maintainers can
> comment, but I would rather use an obstack, and avoid having to keep track of
> all these little buckets-- which seems rather error prone, and then free the
> obstack all in one swoop.  But I'll defer to Richard or Jason.
> 
> 
> > +		     is not, we convert induction variable to stride's
> 
> Rephrase as "is not, convert the induction variable to the stride's"
> Similarly in a few other places.  It looks like you used the same comment.

FIXED!

> 
> > +		  /* If we reach here, then the stride and start are of
> > +		     different types, and so it doesn't really matter what
> > +		     the induction variable type is, we stay safe and convert
> 
> s/type is, we stay safe/type is.  We stay safe/.
> Similarly in a few other places.  It looks like you used the same comment.

FIXED!

> 
> > +		     everything to integer.  The reason why we pick integer
> 
> s/pick integer/pick an integer
> Similarly in a few other places.

FIXED!

> 
> > +/* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
> > +   The LHS and/or RHS will be array notation expressions that have a
> > +   MODIFYCODE.  The location of the variable is specified by
> > +LOCATION. */
> > +
> > +static tree
> > +build_x_array_notation_expr (location_t location, tree lhs,
> > +			     enum tree_code modifycode, tree rhs,
> > +			     tsubst_flags_t complain)
> 
> This is called "build_x_array_notation_expr", but it doesn't look like we build any
> ARRAY_NOTATION_EXPRs in here.  Perhaps a better name would be
> "expand_array_notation_expr" (or something to that effect)?

I renamed this function to "expand_an_in_modify_expr" to indicate that we are expanding array notations in modify expr.

> 
> > +static tree
> > +fix_builtin_array_notation_fn (tree an_builtin_fn, tree *new_var)
> 
> It looks like this function expands the __sec_reduce* builtins.  Perhaps it would
> be cleaner to rename it as such?  Maybe...
> "expand_sec_reduce_builtin" or something?

FIXED!

> 
> The fact that you are sometimes using "build_*" and sometimes "fix_*" to
> denote expansion is confusing.

Replaced all the "fix" with "expand"

> 
> > +/* Returns true of NODE has a call_expression with ARRAY_NOTATION_REF
> > +tree.  */
> > +
> > +static bool
> > +has_call_expr_with_array_notation (tree node)
> 
> s/of NODE/if NODE

FIXED!

> 
> Thanks.
> Aldy

Comments

Aldy Hernandez June 13, 2013, 4:11 p.m. UTC | #1
>> It looks like a NULL in INIT_INDEX is a specially handled case.  Perhaps you
>> should document that INIT_INDEX can be null and what it means.
>> Also, you don't need to document what internal variable name you are using as
>> a return value (VALUE_TREE).  Perhaps instead of "The return value..." you could
>> write "This function returns the ARRAY_NOTATION_REF node." or something
>> like it.
>
> It is documented inside the function, right before checking for !init_index. Is that enough?

Please put it in the function comment.  As it stands, users would have 
to look through the body to find that init_index==NULL is a special case.


>> Changes to existing tests should be submitted as a separate patch, since this
>> doesn't seem to be C++ specific.  And BTW, this particular test change can be
>> committed as obvious.
>
> OK will do.  What about adding {target c} and {target c++} for test cases. Can that be submitted with the patch?

Yes.

> +  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX)
> +    {
> +      /* If the TYPE_MIN_VALUE is available for the new_var_type, then
> +	 set that as the initial value.  */
> +      if (TYPE_MIN_VALUE (new_var_type))
> +	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					    TYPE_MIN_VALUE (new_var_type), 1);
> +      else
> +	/* ... otherwise set initial value as the first element of array.  */
> +	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					    func_parm, 1);
> +      new_no_expr  = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					  *new_var, 1);
> +      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					  func_parm, 1);
> +      new_cond_expr = build_x_binary_op (location, LT_EXPR, *new_var,
> +					 TREE_CODE (*new_var), func_parm,
> +					 TREE_CODE (func_parm), NULL,
> +					 tf_warning_or_error);
> +      new_expr = build_x_conditional_expr (location, new_cond_expr,
> +					   new_yes_expr, new_no_expr,
> +					   tf_warning_or_error);
> +    }
> +  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN)
> +    {
> +      /* If the TYPE_MAX_VALUE is available for the new_var_type, then
> +	 set that as the initial value.  */
> +      if (TYPE_MAX_VALUE (new_var_type))
> +	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					    TYPE_MAX_VALUE (new_var_type), 1);
> +      else
> +	/* ... otherwise set initial value as the first element of array.  */
> +	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					    func_parm, 1);
> +      new_no_expr  = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					  *new_var, 1);
> +      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
> +					  func_parm, 1);
> +      new_cond_expr = build_x_binary_op (location, GT_EXPR, *new_var,
> +					 TREE_CODE (*new_var), func_parm,
> +					 TREE_CODE (func_parm), NULL,
> +					 tf_warning_or_error);
> +      new_expr = build_x_conditional_expr (location, new_cond_expr,
> +					   new_yes_expr, new_no_expr,
> +					   tf_warning_or_error);
> +    }

The whole slew of these cases have a lot of duplicated code.  For 
instance, BUILT_IN_CILKPLUS_SEC_REDUCE_MIN is the same as 
BUILT_IN_CILKPLUS_SEC_REDUCE_MAX, the only difference being GT_EXPR vs 
LT_EXPR.  Surely you could do something like:

if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN
     || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX) {
    enum tree_code code;
    if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN)
      code = GT_EXPR;
    else
      code = LT_EXPR;
    // stuff
}

The compiler should be able to optimize the above, but even if it 
couldn't, I am willing to compare twice and save lines and lines of code.

Similarly for SEC_REDUCE_ANY_ZERO/SEC_REDUCE_ANY_NONZERO, 
SEC_REDUCE_ALL_ZERO/SEC_REDUCE_ALL_NONZERO, 
SEC_REDUCE_ADD/SEC_REDUCE_MUL, etc etc etc.

> +  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.  */

Extra whitespace.

> +  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
> +    {
> +      tree lhs_base = lhs;
> +      tree rhs_base = rhs;
> +
> +      for (ii = 0; ii < lhs_rank; ii++)
> +	lhs_base = ARRAY_NOTATION_ARRAY (lhs_base);
> +
> +      while (rhs_base && TREE_CODE (rhs_base) != ARRAY_NOTATION_REF)
> +	rhs_base = TREE_OPERAND (rhs_base, 0);
> +      for (ii = 0; ii < rhs_rank; ii++)
> +	rhs_base = ARRAY_NOTATION_ARRAY (rhs_base);
> +
> +      if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (lhs))
> +	location = EXPR_LOCATION (lhs);
> +      error_at (location, "rank mismatch between %qD and %qD", lhs_base,
> +		rhs_base);
> +      return error_mark_node;
> +    }

This whole block seems to be indented incorrectly.

> +  /* Assign the array notation components to variable so that they can satisfy
> +     the exec-once rule.  */
> +  for (ii = 0; ii < lhs_list_size; ii++)
> +    {
> +      tree array_node = (*lhs_list)[ii];
> +      tree array_begin = ARRAY_NOTATION_START (array_node);
> +      tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
> +      tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
> +
> +      if (TREE_CODE (array_begin) != INTEGER_CST)
> +	{
> +	  lhs_begin_var = build_decl (location, VAR_DECL, NULL_TREE,
> +				      integer_type_node);
> +	  finish_expr_stmt (build_x_modify_expr (location, lhs_begin_var,
> +						 NOP_EXPR, array_begin,
> +						 complain));
> +	  ARRAY_NOTATION_START (array_node) = lhs_begin_var;
> +	}
> +      if (TREE_CODE (array_lngth) != INTEGER_CST)
> +	{
> +	  lhs_lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
> +				      integer_type_node);
> +	  finish_expr_stmt (build_x_modify_expr (location, lhs_lngth_var,
> +						 NOP_EXPR, array_lngth,
> +						 complain));
> +	  ARRAY_NOTATION_LENGTH (array_node) = lhs_lngth_var;
> +	}

All these exec-one wrappers seem to be doing the same thing over and 
over.  Can you abstract this sequence into a separate helper function? 
Perhaps something like:

for (ii = 0; ii < lhs_list_size; ii++)
   {
     exec_once (&ARRAY_NOTATION_START (array_node));
     exec_once (&ARRAY_NOTATION_LENGTH (array_node));
     exec_once (&ARRAY_NOTATION_STRIDE (array_node));
     ...
     ...
   }

or something to that effect.

> +  if (lhs_rank)
> +    {
> +      for (ii = 0; ii < lhs_list_size; ii++)
> +	{
> +	  jj = 0;
> +	  ii_tree = (*lhs_list)[ii];
> +	  while (ii_tree)
> +	    {
> +	      if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
> +		{
> +		  lhs_array[ii][jj] = ii_tree;
> +		  jj++;
> +		  ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
> +		}
> +	      else if (TREE_CODE (ii_tree) == ARRAY_REF)
> +		ii_tree = TREE_OPERAND (ii_tree, 0);
> +	      else if (TREE_CODE (ii_tree) == VAR_DECL
> +		       || TREE_CODE (ii_tree) == PARM_DECL)
> +		break;
> +	    }
> +	}
> +    }
> +  else
> +    lhs_array[0][0] = NULL_TREE;
> +
> +  if (rhs_rank)
> +    {
> +      for (ii = 0; ii < rhs_list_size; ii++)
> +	{
> +	  jj = 0;
> +	  ii_tree = (*rhs_list)[ii];
> +	  while (ii_tree)
> +	    {
> +	      if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
> +		{
> +		  rhs_array[ii][jj] = ii_tree;
> +		  jj++;
> +		  ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
> +		}
> +	      else if (TREE_CODE (ii_tree) == ARRAY_REF)
> +		ii_tree = TREE_OPERAND (ii_tree, 0);
> +	      else if (TREE_CODE (ii_tree) == VAR_DECL
> +		       || TREE_CODE (ii_tree) == PARM_DECL
> +		       || TREE_CODE (ii_tree) == CALL_EXPR)
> +		break;
> +	    }
> +	}
> +    }

Can't you abstract the common idiom into some inline function?

> +  for (ii = 0; ii < lhs_list_size; ii++)
> +    {
> +      if (TREE_CODE ((*lhs_list)[ii]) == ARRAY_NOTATION_REF)
> +	{
> +	  for (jj = 0; jj < lhs_rank; jj++)
> +	    {
> +	      if (TREE_CODE (lhs_array[ii][jj]) == ARRAY_NOTATION_REF)
> +		{
> +		  lhs_value[ii][jj] = ARRAY_NOTATION_ARRAY (lhs_array[ii][jj]);
> +		  lhs_start[ii][jj] = ARRAY_NOTATION_START (lhs_array[ii][jj]);
> +		  lhs_length[ii][jj] =
> +		    fold_build1 (CONVERT_EXPR, integer_type_node,
> +				 ARRAY_NOTATION_LENGTH (lhs_array[ii][jj]));
> +		  lhs_stride[ii][jj] =
> +		    fold_build1 (CONVERT_EXPR, integer_type_node,
> +				 ARRAY_NOTATION_STRIDE (lhs_array[ii][jj]));
> +		  lhs_vector[ii][jj] = true;
> +		
> +		  /* If the stride value is variable (i.e. not constant) then
> +		     assume that the length is positive.  */
> +		  if (!TREE_CONSTANT (lhs_length[ii][jj]))
> +		    lhs_count_down[ii][jj] = false;
> +		  else if (tree_int_cst_lt
> +			   (lhs_length[ii][jj],
> +			    build_zero_cst (TREE_TYPE (lhs_length[ii][jj]))))
> +		    lhs_count_down[ii][jj] = true;
> +		  else
> +		    lhs_count_down[ii][jj] = false;
> +		}
> +	      else
> +		lhs_vector[ii][jj] = false;
> +	    }
> +	}
> +    }
> +  for (ii = 0; ii < rhs_list_size; ii++)
> +    {
> +      if (TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
> +	{
> +	  for (jj = 0; jj < rhs_rank; jj++)
> +	    {
> +	      if (TREE_CODE (rhs_array[ii][jj]) == ARRAY_NOTATION_REF)
> +		{
> +		  rhs_value[ii][jj]  = ARRAY_NOTATION_ARRAY (rhs_array[ii][jj]);
> +		  rhs_start[ii][jj]  = ARRAY_NOTATION_START (rhs_array[ii][jj]);
> +		  rhs_length[ii][jj] =
> +		    ARRAY_NOTATION_LENGTH (rhs_array[ii][jj]);
> +		  rhs_stride[ii][jj] =
> +		    ARRAY_NOTATION_STRIDE (rhs_array[ii][jj]);
> +		  rhs_vector[ii][jj] = true;
> +		  /* If the stride value is variable (i.e. not constant) then
> +		     assume that the length is positive.  */
> +		  if (!TREE_CONSTANT (rhs_length[ii][jj]))
> +		    rhs_count_down[ii][jj] = false;
> +		  else if (tree_int_cst_lt
> +			   (rhs_length[ii][jj],
> +			    build_zero_cst (TREE_TYPE (rhs_length[ii][jj]))))
> +		    rhs_count_down[ii][jj] = true;
> +		  else
> +		    rhs_count_down[ii][jj] = false;	
> +		}
> +	      else
> +		rhs_vector[ii][jj] = false;
> +	    }

Similarly here, though I don't know if the CONVERT_EXPR in the first 
case and not in the second case is an oversight.

> +  if (lhs_rank)
> +    {
> +      for (ii = 0; ii < lhs_list_size; ii++)
> +	{
> +	  if (lhs_vector[ii][0])
> +	    {
> +	      /* The last ARRAY_NOTATION element's ARRAY component should be
> +		 the array's base value.  */
> +	      tree lhs_array_opr = lhs_value[ii][lhs_rank - 1];
> +	      for (s_jj = lhs_rank - 1; s_jj >= 0; s_jj--)
> +		{
> +		  tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
> +		  if ((TREE_TYPE (lhs_start[ii][s_jj]) ==
> +		       TREE_TYPE (lhs_stride[ii][s_jj]))
> +		      && (TREE_TYPE (lhs_stride[ii][s_jj]) !=
> +			  TREE_TYPE (lhs_var[s_jj])))
> +		    {
> +		      /* If stride and start are of same type and the induction
> +			 var is not, convert induction variable to stride's
> +			 type.  */
> +		      start = lhs_start[ii][s_jj];
> +		      stride = lhs_stride[ii][s_jj];
> +		      var = build_c_cast (location,
> +					  TREE_TYPE (lhs_stride[ii][s_jj]),
> +					  lhs_var[s_jj]);
> +		    }
> +		  else if (TREE_TYPE (lhs_start[ii][s_jj]) !=
> +			   TREE_TYPE (lhs_stride[ii][s_jj]))
> +		    {
> +		      /* If we reach here, then the stride and start are of
> +			 different types, and so it doesn't really matter what
> +			 the induction variable type is, convert everything to
> +			 integer.  The reason why we pick an integer instead of
> +			 something like size_t is because the stride and
> +			 length can be + or -.  */
> +		      start = build_c_cast (location, integer_type_node,
> +					    lhs_start[ii][s_jj]);
> +		      stride = build_c_cast (location, integer_type_node,
> +					     lhs_stride[ii][s_jj]);
> +		      var = build_c_cast (location, integer_type_node,
> +					  lhs_var[s_jj]);
> +		    }
> +		  else
> +		    {
> +		      start = lhs_start[ii][s_jj];
> +		      stride = lhs_stride[ii][s_jj];
> +		      var = lhs_var[s_jj];
> +		    }
> +		  if (lhs_count_down[ii][s_jj])
> +		    /* Array[start_index - (induction_var * stride)].  */
> +		    lhs_array_opr = grok_array_decl
> +		      (location, lhs_array_opr,
> +		       build2 (MINUS_EXPR, TREE_TYPE (var), start,
> +			       build2 (MULT_EXPR, TREE_TYPE (var), var,
> +				       stride)), false);	
> +		  else
> +		    /* Array[start_index + (induction_var * stride)].  */
> +		    lhs_array_opr = grok_array_decl
> +		      (location, lhs_array_opr,
> +		       build2 (PLUS_EXPR, TREE_TYPE (var), start,
> +			       build2 (MULT_EXPR, TREE_TYPE (var), var,
> +				       stride)), false);
> +		}
> +	      vec_safe_push (lhs_array_operand, lhs_array_opr);
> +	    }
> +	  else
> +	    vec_safe_push (lhs_array_operand, integer_one_node);
> +	}

99% of this looks exactly like the rhs_rank case, surely you can 
abstract most of this into a separate function.

> +      for (ii = 0; ii < rhs_list_size; ii++)
> +	{
> +	  tree rhs_node = (*rhs_list)[ii];
> +	  if (TREE_CODE (rhs_node) == CALL_EXPR)
> +	    {
> +	      int idx_value = 0;
> +	      tree func_name = CALL_EXPR_FN (rhs_node);
> +	      if (TREE_CODE (func_name) == ADDR_EXPR)
> +		if (is_sec_implicit_index_fn (func_name))
> +		  {
> +		    idx_value =
> +		      extract_sec_implicit_index_arg (location, rhs_node);
> +		    if (idx_value < (int) lhs_rank && idx_value >= 0)
> +		      vec_safe_push (rhs_array_operand, rhs_var[idx_value]);
> +		    else
> +		      {
> +			size_t ee = 0;
> +			tree rhs_base = (*lhs_list)[ii];
> +			for (ee = 0; ee < rhs_rank; ee++)
> +			  if (rhs_base
> +			      && TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
> +			    rhs_base = ARRAY_NOTATION_ARRAY (rhs_base);
> +
> +			error_at (location, "__sec_implicit_index argument %d "
> +				  "must be less than rank of %qD", idx_value,
> +				  rhs_base);
> +			return error_mark_node;
> +		      }
> +		  }
> +	    }
> +	}	
> +      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
> +      array_expr_rhs = rhs;
> +    }
> +  else
> +    {
> +      for (ii = 0; ii < rhs_list_size; ii++)
> +	{
> +	  tree rhs_node = (*rhs_list)[ii];
> +	  if (TREE_CODE (rhs_node) == CALL_EXPR)
> +	    {
> +	      int idx_value = 0;
> +	      tree func_name = CALL_EXPR_FN (rhs_node);
> +	      if (is_sec_implicit_index_fn (func_name))
> +		{
> +		  idx_value =  extract_sec_implicit_index_arg (location,
> +							       rhs_node);
> +		  if (idx_value < (int) lhs_rank && idx_value >= 0)
> +		    vec_safe_push (rhs_array_operand, lhs_var[idx_value]);
> +		  else
> +		    {
> +		      size_t ee = 0;
> +		      tree lhs_base = (*lhs_list)[ii];
> +		      for (ee = 0; ee < lhs_rank; ee++)
> +			if (lhs_base
> +			    && TREE_CODE (lhs_base) == ARRAY_NOTATION_REF)
> +			  lhs_base = ARRAY_NOTATION_ARRAY (lhs_base);
> +		      error_at (location, "__sec_implicit_index argument %d "
> +				"must be less than the rank of %qD", idx_value,
> +				lhs_base);
> +		      return error_mark_node;
> +		    }
> +		}
> +	    }

Again, a lot of stuff that looks exactly the same.

Similarly in the rest of expand_an_in_modify_expr().  The function is 
HUGE, and there's a lot of code duplication going on.  Try to abstract 
the things you do more than once into their own helper functions.  This 
will cut down on the maintenance burden.

> +  if (TREE_CODE (orig_stmt) == COND_EXPR)
> +    {
> +      size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
> +      tree yes_expr = COND_EXPR_THEN (orig_stmt);
> +      tree no_expr = COND_EXPR_ELSE (orig_stmt);
> +      tree cond = COND_EXPR_COND (orig_stmt);
> +      if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
> +	  || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
> +			 &yes_rank)
> +	  || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
> +			&no_rank))
> +	return error_mark_node;
> +      if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0)
> +	{
> +	  error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
> +		    " expression of parent if-statement");
> +	  return error_mark_node;
> +	}
> +      else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0)
> +	{
> +	  error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
> +		    "expression of parent if-statement");
> +	  return error_mark_node;
> +	}
> +    }
> +  else if (TREE_CODE (orig_stmt) == IF_STMT)
> +    {
> +      size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
> +      tree yes_expr = THEN_CLAUSE (orig_stmt);
> +      tree no_expr = ELSE_CLAUSE (orig_stmt);
> +      tree cond = IF_COND (orig_stmt);
> +      if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
> +	  || (yes_expr
> +	      && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
> +			     &yes_rank))
> +	  || (no_expr
> +	      && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
> +			     &no_rank)))
> +	return error_mark_node;
> +      if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0)
> +	{
> +	  error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
> +		    " expression of parent if-statement");
> +	  return error_mark_node;
> +	}
> +      else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0)
> +	{
> +	  error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
> +		    "expression of parent if-statement");
> +	  return error_mark_node;
> +	}
> +    }

And here in cp_expand_cond_array_notations().

> +  for (ii = 0; ii < list_size; ii++)
> +    {
> +      jj = 0;
> +      jj_tree = (*array_list)[ii];
> +      while (jj_tree)
> +	{
> +	  if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF)
> +	    {
> +	      array_ops[ii][jj] = jj_tree;
> +	      jj++;
> +	      jj_tree = ARRAY_NOTATION_ARRAY (jj_tree);
> +	    }
> +	  else if (TREE_CODE (jj_tree) == ARRAY_REF)
> +	    jj_tree = TREE_OPERAND (jj_tree, 0);
> +	  else if (TREE_CODE (jj_tree) == VAR_DECL
> +		   || TREE_CODE (jj_tree) == PARM_DECL)
> +	    break;
> +	}
> +    }

The above snippet appears in the exact same form in both 
expand_sec_reduce_builtin() and cp_expand_cond_array_notations().  I'm 
not going to mention any more of these duplicated code sequences, but 
you should go through the entire file and abstract what you can into 
separate inlineable functions, no sense maintaining 10 copies of the 
same thing.

Aldy
Richard Henderson June 13, 2013, 4:18 p.m. UTC | #2
On 06/13/2013 09:11 AM, Aldy Hernandez wrote:
> The whole slew of these cases have a lot of duplicated code.  For instance,
> BUILT_IN_CILKPLUS_SEC_REDUCE_MIN is the same as
> BUILT_IN_CILKPLUS_SEC_REDUCE_MAX, the only difference being GT_EXPR vs
> LT_EXPR.  Surely you could do something like:
> 
> if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN
>     || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX) {
>    enum tree_code code;
>    if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN)
>      code = GT_EXPR;
>    else
>      code = LT_EXPR;
>    // stuff
> }
> 
> The compiler should be able to optimize the above, but even if it couldn't, I
> am willing to compare twice and save lines and lines of code.
> 
> Similarly for SEC_REDUCE_ANY_ZERO/SEC_REDUCE_ANY_NONZERO,
> SEC_REDUCE_ALL_ZERO/SEC_REDUCE_ALL_NONZERO, SEC_REDUCE_ADD/SEC_REDUCE_MUL, etc
> etc etc.

Yep.  It's at this point that I normally start using the idiom

	switch (an_type)
	  {
	  case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
	    code = GT_EXPR;
	    goto do_min_max;
	  case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
	    code = LT_EXPR;
	    goto do_min_max;
	  do_min_max:
	    // stuff

So much the better if you can include the other SEC_* cases in that switch too,
doing one compiler-controlled dispatch.

It also occurs to me to wonder why you're building your own COND_EXPR here,
with the comparison, rather than using MIN/MAX_EXPR...


r~
Iyer, Balaji V June 17, 2013, 5 p.m. UTC | #3
> -----Original Message-----
> From: gcc-patches-owner@gcc.gnu.org [mailto:gcc-patches-
> owner@gcc.gnu.org] On Behalf Of Richard Henderson
> Sent: Thursday, June 13, 2013 12:19 PM
> To: Aldy Hernandez
> Cc: Iyer, Balaji V; gcc-patches@gcc.gnu.org; Jason Merrill (jason@redhat.com)
> Subject: Re: [PATCH] Cilk Plus Array Notation for C++
> 
> On 06/13/2013 09:11 AM, Aldy Hernandez wrote:
> > The whole slew of these cases have a lot of duplicated code.  For
> > instance, BUILT_IN_CILKPLUS_SEC_REDUCE_MIN is the same as
> > BUILT_IN_CILKPLUS_SEC_REDUCE_MAX, the only difference being GT_EXPR
> vs
> > LT_EXPR.  Surely you could do something like:
> >
> > if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN
> >     || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX) {
> >    enum tree_code code;
> >    if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN)
> >      code = GT_EXPR;
> >    else
> >      code = LT_EXPR;
> >    // stuff
> > }
> >
> > The compiler should be able to optimize the above, but even if it
> > couldn't, I am willing to compare twice and save lines and lines of code.
> >
> > Similarly for SEC_REDUCE_ANY_ZERO/SEC_REDUCE_ANY_NONZERO,
> > SEC_REDUCE_ALL_ZERO/SEC_REDUCE_ALL_NONZERO,
> > SEC_REDUCE_ADD/SEC_REDUCE_MUL, etc etc etc.
> 
> Yep.  It's at this point that I normally start using the idiom
> 
> 	switch (an_type)
> 	  {
> 	  case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
> 	    code = GT_EXPR;
> 	    goto do_min_max;
> 	  case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
> 	    code = LT_EXPR;
> 	    goto do_min_max;
> 	  do_min_max:
> 	    // stuff
> 
> So much the better if you can include the other SEC_* cases in that switch too,
> doing one compiler-controlled dispatch.

I didn't use goto, but I did try to abstract out the common parts and either tried to lump them together in the same case or  put them outside of the case. The new patch is here: http://gcc.gnu.org/ml/gcc-patches/2013-06/msg00984.html

> 
> It also occurs to me to wonder why you're building your own COND_EXPR here,
> with the comparison, rather than using MIN/MAX_EXPR...

In hindsight, I could have for __sec_reduce_max and __sec_reduce_min. I was more familiar with conditional expression. Out of curiosity, is there a big performance benefit of using max/min expr over conditional?


Thanks,

Balaji V. Iyer.

> 
> 
> r~
Richard Henderson June 17, 2013, 5:06 p.m. UTC | #4
On 06/17/2013 10:00 AM, Iyer, Balaji V wrote:
> In hindsight, I could have for __sec_reduce_max and __sec_reduce_min. I was
> more familiar with conditional expression. Out of curiosity, is there a big
> performance benefit of using max/min expr over conditional?

There can be.  The COND->MIN/MAX transformation is not done without the
-ffinite-math-only component of -ffast-math.  I.e. we don't try the transform
when NaNs are a possibility.

So, yes, you probably should generate MIN/MAX_EXPR right from the start.


r~
diff mbox

Patch

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
old mode 100644
new mode 100755
index 2c93982..362f0bc
Binary files a/gcc/cp/ChangeLog and b/gcc/cp/ChangeLog differ
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index df8ed3e..6e80bcf 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -80,7 +80,7 @@  CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/cp-array-notation.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -266,6 +266,9 @@  CXX_PRETTY_PRINT_H = cp/cxx-pretty-print.h $(C_PRETTY_PRINT_H)
 cp/lex.o: cp/lex.c $(CXX_TREE_H) $(TM_H) $(FLAGS_H) \
   $(C_PRAGMA_H) input.h cp/operators.def $(TM_P_H) \
   c-family/c-objc.h
+cp/cp-array-notation.o: cp/cp-array-notation.c $(CONFIG_H) $(SYSTEM_H) \
+  coretypes.h $(TREE_H) $(CXX_TREE_H) $(DIAGNOSTIC_H) tree-iterator.h vec.h \
+  $(GIMPLE_H) c-family/array-notation-common.o $(C_COMMON_H) 
 cp/cp-lang.o: cp/cp-lang.c $(CXX_TREE_H) $(TM_H) debug.h langhooks.h \
   $(LANGHOOKS_DEF_H) $(C_COMMON_H) gtype-cp.h gt-cp-cp-lang.h \
   cp/cp-objcp-common.h $(EXPR_H) $(TARGET_H) $(CXX_PARSER_H)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index dfd061a..64be41f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -5858,9 +5858,15 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	    break;
 	}
 
-      if (permerror (loc, "invalid conversion from %qT to %qT",
-		     TREE_TYPE (expr), totype)
-	  && fn)
+      if (flag_enable_cilkplus
+	  && (contains_array_notation_expr (expr)
+	      || contains_array_notation_expr (fn)))
+	/* If we are using array notations, we fix them up at a later stage
+	   and we will do these checks then.  */
+	;
+      else if (permerror (loc, "invalid conversion from %qT to %qT",
+			  TREE_TYPE (expr), totype)
+	       && fn)
 	inform (DECL_SOURCE_LOCATION (fn),
 		"initializing argument %P of %qD", argnum, fn);
 
@@ -6890,12 +6896,20 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	    }
 	}
 
-      val = convert_like_with_context (conv, arg, fn, i-is_method,
-	                               conversion_warning
-				       ? complain
-				       : complain & (~tf_warning));
+      /* If the function call is builtin array notation function then no need
+	 to do any type conversion.  */
+      if (flag_enable_cilkplus
+	  && is_cilkplus_reduce_builtin (fn) != BUILT_IN_NONE)
+	val = arg;
+      else
+	{
+	  val = convert_like_with_context (conv, arg, fn, i-is_method,
+					   conversion_warning
+					   ? complain
+					   : complain & (~tf_warning));
 
-      val = convert_for_arg_passing (type, val, complain);
+	  val = convert_for_arg_passing (type, val, complain);
+	}
       if (val == error_mark_node)
         return error_mark_node;
       else
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
new file mode 100755
index 0000000..34c73f3
--- /dev/null
+++ b/gcc/cp/cp-array-notation.c
@@ -0,0 +1,2850 @@ 
+/* This file is part of the Intel(R) Cilk(TM) Plus support
+   It contains routines to handle Array Notation expression
+   handling routines in the C++ Compiler.
+   Copyright (C) 2013  Free Software Foundation, Inc.
+   Contributed by Balaji V. Iyer <balaji.v.iyer@intel.com>,
+                  Intel Corporation
+
+   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/>.  */
+
+/* The Array Notation Transformation Technique:
+
+   An array notation expression has 4 major components:
+   1. The array name
+   2. Start Index
+   3. Number of elements we need to acess (we call it length)
+   4. Stride
+
+   So, if we have something like A[0:5:2], we are accessing A[0], A[2], A[4],
+   A[6] and A[8]. The user is responsible to make sure the access length does
+   not step outside the array's size.
+   
+   In this section, I highlight the overall method on how array notations are
+   broken up into C/C++ code.  Almost all the functions follows this step:
+
+   Let's say the user has used the array notation in a statement like this:
+
+   A[St1:Ln:Str1] = B[St2:Ln:Str2] + <NON ARRAY_NOT STMT>
+
+   where St{1,2} = Starting index, Ln = Number of elements we need to access,
+   and Str{1,2} = the stride.
+   Note: The length of both the array notation expressions must be the same.
+   
+   The above expression is broken into the following:
+
+   for (Tmp_Var = 0; Tmp_Var < Ln; Tmp_Var++)
+     A[St1 + Tmp_Var * Str1] = B[St1 + Tmp_Var * Str2] + <NON_ARRAY_NOT_STMT>;
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "c-family/c-common.h"
+#include "diagnostic.h"
+#include "tree-iterator.h"
+#include "vec.h"
+#include "gimple.h"
+
+
+/* Creates a FOR_STMT with INIT, COND, INCR and BODY as the initializer,
+   condition, increment expression and the loop-body, respectively.  */
+
+static void
+create_an_loop (tree init, tree cond, tree incr, tree body)
+{
+  tree for_stmt;
+
+  finish_expr_stmt (init);
+  for_stmt = begin_for_stmt (NULL_TREE, NULL_TREE);
+  finish_for_init_stmt (for_stmt);
+  finish_for_cond (cond, for_stmt);
+  finish_for_expr (incr, for_stmt);
+  finish_expr_stmt (body);
+  finish_for_stmt (for_stmt);
+}
+
+/* Replaces all the scalar expressions in *NODE.  Returns a STATEMENT LIST that
+   holds the NODE along with the variables that hold the results of the
+   invariant expressions.  */
+
+static tree
+replace_invariant_exprs (tree *node)
+{
+  size_t ix = 0;
+  tree node_list = NULL_TREE;
+  tree t = NULL_TREE, new_var = NULL_TREE, new_node; 
+  struct inv_list data;
+
+  data.list_values = NULL;
+  data.replacement = NULL;
+  data.additional_tcodes = NULL;
+  cp_walk_tree (node, find_inv_trees, (void *) &data, NULL);
+
+  if (vec_safe_length (data.list_values))
+    {
+      node_list = push_stmt_list ();
+      for (ix = 0; vec_safe_iterate (data.list_values, ix, &t); ix++)
+	{
+	  if (processing_template_decl || !TREE_TYPE (t))
+	    new_var = build_min_nt_loc (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
+				       	NULL_TREE);
+	  else
+	    new_var = build_decl (EXPR_LOCATION (t), VAR_DECL, NULL_TREE,
+				  TREE_TYPE (t));
+	  gcc_assert (new_var != NULL_TREE && new_var != error_mark_node);
+	  new_node = build_x_modify_expr (EXPR_LOCATION (t), new_var, NOP_EXPR,
+					  t, tf_warning_or_error);
+	  finish_expr_stmt (new_node);
+	  vec_safe_push (data.replacement, new_var);
+	}
+      cp_walk_tree (node, replace_inv_trees, (void *) &data, NULL);
+      node_list = pop_stmt_list (node_list);
+    }
+  return node_list;
+}
+
+/* Returns true if NODE has a call_expression with ARRAY_NOTATION_REF tree.  */
+
+static bool
+has_call_expr_with_array_notation (tree node)
+{
+  int ii = 0;
+  
+  if (!contains_array_notation_expr (node))
+    return false;
+  
+  if (TREE_CODE (node) == ARRAY_NOTATION_REF)
+    return false;
+  else if (TREE_CODE (node) == DECL_EXPR)
+    {
+      tree x = DECL_EXPR_DECL (node);
+      if (x && TREE_CODE (x) != FUNCTION_DECL)
+	if (DECL_INITIAL (x))
+	  return has_call_expr_with_array_notation (DECL_INITIAL (x));
+	
+    }
+  else if (TREE_CODE (node) == STATEMENT_LIST)
+    {
+      tree_stmt_iterator ii_tsi;
+      for (ii_tsi = tsi_start (node); !tsi_end_p (ii_tsi); tsi_next (&ii_tsi))
+	return has_call_expr_with_array_notation (*tsi_stmt_ptr (ii_tsi));
+    }
+  else if (TREE_CODE (node) == CALL_EXPR)
+    {
+      if (is_cilkplus_reduce_builtin (CALL_EXPR_FN (node)) != BUILT_IN_NONE)
+	return true;
+	
+      if (is_sec_implicit_index_fn (CALL_EXPR_FN (node)))
+	return true;
+	 
+      if (TREE_CODE (TREE_OPERAND (node, 0)) == INTEGER_CST)
+	{
+	  int length = TREE_INT_CST_LOW (TREE_OPERAND (node, 0));
+	  bool x = false;
+	  for (ii = 0; ii < length; ii++)
+	    x |= contains_array_notation_expr (TREE_OPERAND (node, ii));
+	  return x;
+	}
+      else
+	gcc_unreachable  ();	  
+    } 
+  else
+    {
+      bool x = false;
+      for (ii = 0; ii < TREE_CODE_LENGTH (TREE_CODE (node)); ii++) 
+	x |= has_call_expr_with_array_notation (TREE_OPERAND (node, ii));
+      return x;
+    }
+  return false;
+}
+
+/* Replace array notation's built-in function passed in AN_BUILTIN_FN with
+   the appropriate loop and computation (all stored in variable LOOP of type
+   tree node).  The output of the function function is always a scalar and that
+   result is returned in *NEW_VAR.  *NEW_VAR is NULL_TREE if the function is
+   __sec_reduce_mutating.  */
+
+static tree
+expand_sec_reduce_builtin (tree an_builtin_fn, tree *new_var)
+{
+  tree new_var_type = NULL_TREE, func_parm, new_expr, new_yes_expr, new_no_expr;
+  tree array_ind_value = NULL_TREE, new_no_ind, new_yes_ind, new_no_list;
+  tree new_yes_list, new_cond_expr; 
+  tree new_var_init = NULL_TREE, new_exp_init = NULL_TREE;
+  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
+  int s_jj = 0;
+  size_t list_size = 0, rank = 0, ii = 0, jj = 0;
+  tree **array_ops, *array_var, jj_tree;
+  tree **array_value, **array_stride, **array_length, **array_start;
+  tree  body, an_init, loop_with_init = alloc_stmt_list ();
+  tree *compare_expr, array_op0, *expr_incr, *ind_init, comp_node;
+  tree call_fn = NULL_TREE, identity_value = NULL_TREE, new_call_expr;
+  bool **count_down, **array_vector;
+  tree begin_var, lngth_var, strde_var;
+  location_t location = UNKNOWN_LOCATION;
+  tsubst_flags_t complain = tf_warning_or_error;
+
+  enum built_in_function an_type =
+    is_cilkplus_reduce_builtin (CALL_EXPR_FN (an_builtin_fn));
+  
+  if (an_type == BUILT_IN_NONE)
+    return NULL_TREE;
+
+  if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE
+      && an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
+    func_parm = CALL_EXPR_ARG (an_builtin_fn, 0);
+  else
+    {
+      call_fn = CALL_EXPR_ARG (an_builtin_fn, 2);
+
+      /* We need to do this because we are "faking" the builtin function types,
+	 so the compiler does a bunch of typecasts and this will get rid of
+	 all that!  */
+      while (TREE_CODE (call_fn) == CONVERT_EXPR
+	     || TREE_CODE (call_fn) == NOP_EXPR)
+	call_fn = TREE_OPERAND (call_fn, 0);
+
+      if (TREE_CODE (call_fn) != OVERLOAD
+	  && TREE_CODE (call_fn) != FUNCTION_DECL)
+	call_fn = TREE_OPERAND (call_fn, 0);
+      identity_value = CALL_EXPR_ARG (an_builtin_fn, 0);
+      func_parm = CALL_EXPR_ARG (an_builtin_fn, 1);
+
+      /* We need to do this because we are "faking" the builtin function types
+	 so the compiler does a bunch of typecasts and this will get rid of
+	 all that!  */
+      while (TREE_CODE (identity_value) == CONVERT_EXPR
+	     || TREE_CODE (identity_value) == NOP_EXPR)
+	identity_value = TREE_OPERAND (identity_value, 0);
+    }
+
+  while (TREE_CODE (func_parm) == CONVERT_EXPR
+	 || TREE_CODE (func_parm) == NOP_EXPR)
+    func_parm = TREE_OPERAND (func_parm, 0);
+  
+  location = EXPR_LOCATION (an_builtin_fn);
+  if (!find_rank (location, an_builtin_fn, an_builtin_fn, true, &rank))
+      return error_mark_node;
+  if (rank == 0)
+    return an_builtin_fn;
+  else if (rank > 1 
+	   && (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
+	       || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND))
+    { 
+      error_at (location, "__sec_reduce_min_ind or __sec_reduce_max_ind cannot "
+		"have arrays with dimension greater than 1");
+      return error_mark_node;
+    }
+  
+  extract_array_notation_exprs (func_parm, true, &array_list);
+  list_size = vec_safe_length (array_list);
+    switch (an_type)
+    {
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_ADD:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUL:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN:
+      new_var_type = TREE_TYPE ((*array_list)[0]);
+      break;
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO:
+      new_var_type = integer_type_node;
+      break;
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND:
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND:
+      new_var_type = size_type_node;
+      break;
+    case BUILT_IN_CILKPLUS_SEC_REDUCE:
+      if (call_fn && identity_value)
+	new_var_type = TREE_TYPE ((*array_list)[0]);
+      break;
+    case BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING:
+      new_var_type = NULL_TREE;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+    
+  if (new_var_type && TREE_CODE (new_var_type) == ARRAY_TYPE)
+    new_var_type = TREE_TYPE (new_var_type);
+  
+  array_ops = XNEWVEC (tree *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_ops[ii] = XNEWVEC (tree,  rank);
+  
+  array_vector = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_vector[ii] = XNEWVEC (bool, rank);
+
+  array_value =  XNEWVEC (tree *, list_size);
+  array_stride =  XNEWVEC (tree *, list_size);
+  array_length =  XNEWVEC (tree *, list_size);
+  array_start =  XNEWVEC (tree *, list_size);
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      array_value[ii]  = XNEWVEC (tree, rank);
+      array_stride[ii] = XNEWVEC (tree, rank);
+      array_length[ii] = XNEWVEC (tree, rank);
+      array_start[ii]  = XNEWVEC (tree, rank);
+    }
+
+  compare_expr = XNEWVEC (tree, rank);
+  expr_incr = XNEWVEC (tree, rank);
+  ind_init = XNEWVEC (tree, rank);
+  
+  count_down = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    count_down[ii] = XNEWVEC (bool, rank);
+  
+  array_var = XNEWVEC (tree, rank);
+  an_init = push_stmt_list ();
+
+    /* Assign the array notation components to variable so that they can satisfy
+       the exec-once rule.  */
+  for (ii = 0; ii < list_size; ii++)
+    {
+      tree array_node = (*array_list)[ii];
+      tree array_begin = ARRAY_NOTATION_START (array_node);
+      tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+      tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+      if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+	{
+	  if (TREE_CODE (array_begin) != INTEGER_CST)
+	    {
+	      begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, begin_var,
+						     NOP_EXPR, array_begin,
+						     complain));
+	      ARRAY_NOTATION_START (array_node) = begin_var;
+	    }
+	  if (TREE_CODE (array_lngth) != INTEGER_CST)
+	    {
+	      lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, lngth_var,
+						     NOP_EXPR, array_lngth,
+						     complain));
+	      ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+	    }
+	  if (TREE_CODE (array_strde) != INTEGER_CST)
+	    {
+	      strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, strde_var,
+						     NOP_EXPR, array_strde,
+						     complain));
+	      ARRAY_NOTATION_STRIDE (array_node) = strde_var;
+	    }
+	}
+    }
+  for (ii = 0; ii < list_size; ii++)
+    {
+      jj = 0;
+      jj_tree = (*array_list)[ii];
+      while (jj_tree)
+	{
+	  if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF)
+	    {
+	      array_ops[ii][jj] = jj_tree;
+	      jj++;
+	      jj_tree = ARRAY_NOTATION_ARRAY (jj_tree);
+	    }
+	  else if (TREE_CODE (jj_tree) == ARRAY_REF)
+	    jj_tree = TREE_OPERAND (jj_tree, 0);
+	  else if (TREE_CODE (jj_tree) == VAR_DECL
+		   || TREE_CODE (jj_tree) == PARM_DECL)
+	    break;
+	}
+    }
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
+	for (jj = 0; jj < rank; jj++)
+	  {
+	    if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF)
+	      {
+		array_value[ii][jj] =
+		  ARRAY_NOTATION_ARRAY (array_ops[ii][jj]);
+		array_start[ii][jj] =
+		  ARRAY_NOTATION_START (array_ops[ii][jj]);
+		array_length[ii][jj] =
+		  fold_build1 (CONVERT_EXPR, integer_type_node,
+			       ARRAY_NOTATION_LENGTH (array_ops[ii][jj]));
+		array_stride[ii][jj] =
+		  ARRAY_NOTATION_STRIDE (array_ops[ii][jj]);
+		array_vector[ii][jj] = true;
+
+		if (!TREE_CONSTANT (array_length[ii][jj])
+		    || TREE_CODE (array_length[ii][jj]) != INTEGER_TYPE)
+		  count_down[ii][jj] = false;
+		else if (tree_int_cst_sgn (array_length[ii][jj]) == -1)
+		  count_down[ii][jj] = true;
+		else
+		  count_down[ii][jj] = false;
+	      }
+	    else
+	      array_vector[ii][jj] = false;
+	  }
+    }
+
+  for (ii = 0; ii < rank; ii++)
+    {
+      array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE,
+				  TREE_TYPE (array_start[0][ii]));
+      ind_init[ii] = build_x_modify_expr
+	(location, array_var[ii], NOP_EXPR, 
+	 build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error);
+    }
+  for (ii = 0; ii < list_size; ii++)
+    if (array_vector[ii][0])
+      {
+	tree array_opr = array_value[ii][rank - 1];
+	for (s_jj = rank - 1; s_jj >= 0; s_jj--)
+	  {
+	    tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
+
+	    /* If stride and start are of same type and the induction var
+	       is not, convert induction variable to stride's type.  */
+	    if ((TREE_TYPE (array_start[ii][s_jj]) ==
+		 TREE_TYPE (array_stride[ii][s_jj]))
+		&& (TREE_TYPE (array_stride[ii][s_jj]) !=
+		    TREE_TYPE (array_var[s_jj])))
+	      {
+		start = array_start[ii][s_jj];
+		stride = array_stride[ii][s_jj];
+		var =
+		  build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]),
+				array_var[s_jj]);
+	      }
+	    else if (TREE_TYPE (array_start[ii][s_jj]) !=
+		     TREE_TYPE (array_stride[ii][s_jj]))
+	      {
+		/* If we reach here, then the stride and start are of
+		   different types, and so it doesn't really matter what
+		   the induction variable type is, convert everything to 
+		   integer.  The reason why we pick an integer
+		   instead of something like size_t is because the stride
+		   and length can be + or -.  */
+		start = build_c_cast (location, integer_type_node,
+				      array_start[ii][s_jj]);
+		stride = build_c_cast (location, integer_type_node,
+				       array_stride[ii][s_jj]);
+		var = build_c_cast (location, integer_type_node,
+				    array_var[s_jj]);
+	      }
+	    else
+	      {
+		start = array_start[ii][s_jj];
+		stride = array_stride[ii][s_jj];
+		var = array_var[s_jj];
+	      }
+	    if (count_down[ii][s_jj])
+	      /* Array[start_index - (induction_var * stride)].  */
+	      array_opr = grok_array_decl
+		(location, array_opr,
+		 build2 (MINUS_EXPR, TREE_TYPE (var), start,
+			 build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		 false);	
+	    else
+	      /* Array[start_index + (induction_var * stride)].  */
+	      array_opr = grok_array_decl
+		(location, array_opr,
+		 build2 (PLUS_EXPR, TREE_TYPE (var), start,
+			 build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		 false);
+	  }
+	vec_safe_push (array_operand, array_opr);
+      }
+    else
+      vec_safe_push (array_operand, integer_one_node);
+    
+  replace_array_notations (&func_parm, true, array_list, array_operand);
+  
+  if (!TREE_TYPE (func_parm))      
+    TREE_TYPE (func_parm) = TREE_TYPE ((*array_list)[0]);
+  
+  for (ii = 0; ii < rank; ii++)
+    if (count_down[0][ii])
+      expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+    else
+      expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+  
+  for (jj = 0; jj < rank; jj++)
+    if (rank && expr_incr[jj])
+      {
+	if (count_down[0][jj])
+	  compare_expr[jj] = build_x_binary_op
+	    (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	     array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	     tf_warning_or_error);
+	else
+	  compare_expr[jj] = build_x_binary_op
+	    (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	     array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	     tf_warning_or_error);
+      } 
+  if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
+    {
+      if (processing_template_decl)
+	*new_var = build_decl (location, VAR_DECL, NULL_TREE, new_var_type);
+      else
+	*new_var = create_tmp_var (new_var_type, NULL);
+    }
+  else
+    /* We do not require a new variable for mutating.  The "identity value"
+       itself is a variable.  */
+    *new_var = NULL_TREE;
+  
+  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
+      || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
+    {
+      array_ind_value = create_tmp_var (TREE_TYPE (func_parm), NULL);
+      gcc_assert (array_ind_value && (array_ind_value != error_mark_node));
+      DECL_INITIAL (array_ind_value) = NULL_TREE;
+      pushdecl (array_ind_value);
+    }
+  array_op0 = (*array_operand)[0];
+  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ADD)
+    {
+      if (ARITHMETIC_TYPE_P (new_var_type))
+	new_var_init = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR,
+					    build_zero_cst (new_var_type), 1);
+      else
+	new_var_init = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR,
+					    integer_zero_node, 1);
+      new_expr = build_x_modify_expr (location, *new_var, PLUS_EXPR, 
+				      func_parm, 1);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUL)
+    {
+      if (ARITHMETIC_TYPE_P (new_var_type))
+	new_var_init = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR,
+					    build_one_cst (new_var_type), 1);
+      else
+	new_var_init = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR,
+					    integer_one_node, 1);
+      new_expr = build_x_modify_expr (location, *new_var, MULT_EXPR, 
+				      func_parm, 1);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_ZERO)
+    {
+      new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  build_one_cst (new_var_type), 1);
+      /* Initially you assume everything is zero, now if we find a case where
+	 it is NOT true, then we set the result to false. Otherwise we just
+	 keep the previous value.  */
+      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  build_zero_cst (new_var_type), 1);
+      new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, 
+					 *new_var, 1);
+      if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm)))
+	comp_node = build_zero_cst (TREE_TYPE (func_parm));
+      else
+	comp_node = integer_zero_node;
+      new_cond_expr = build_x_binary_op
+	(location, NE_EXPR, func_parm, TREE_CODE (func_parm), comp_node,
+	 TREE_CODE (comp_node), NULL, tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr, 
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ALL_NONZERO)
+    {
+      new_var_init = build_x_modify_expr
+	(location, *new_var, NOP_EXPR, build_one_cst (new_var_type), 1);
+      /* Initially you assume everything is non-zero, now if we find a case
+	 where it is NOT true, then we set the result to false. Otherwise we
+	 just keep the previous value.  */
+      new_yes_expr = build_x_modify_expr
+	(location, *new_var, NOP_EXPR, 
+	 build_zero_cst (TREE_TYPE (*new_var)), 1);
+      new_no_expr = build_x_modify_expr (location, *new_var, NOP_EXPR, 
+					 *new_var, 1);
+      if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm)))
+	comp_node = build_zero_cst (TREE_TYPE (func_parm));
+      else
+	comp_node = integer_zero_node;
+      new_cond_expr = build_x_binary_op
+	(location, EQ_EXPR, func_parm, TREE_CODE (func_parm), comp_node,
+	 TREE_CODE (comp_node), NULL, tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr, 
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_ZERO)
+    {
+      new_var_init = build_x_modify_expr
+	(location, *new_var, NOP_EXPR, 
+	 build_zero_cst (new_var_type), 1);
+      /* Initially we assume there are NO zeros in the list. When we find a
+	 non-zero, we keep the previous value. If we find a zero, we set the
+	 value to true.  */
+      new_no_expr = build_x_modify_expr
+	(location, *new_var, NOP_EXPR, 
+	 build_one_cst (TREE_TYPE (*new_var)), 1);
+      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, 1);
+      if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm)))
+	comp_node = build_zero_cst (TREE_TYPE (func_parm));
+      else
+	comp_node = integer_zero_node;
+      new_cond_expr = build_x_binary_op
+	(location, EQ_EXPR, func_parm, TREE_CODE (func_parm), comp_node,
+	 TREE_CODE (comp_node), NULL, tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr, 
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_ANY_NONZERO)
+    {
+      new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR, 
+					  build_zero_cst (new_var_type), 1);
+      /* Initially we assume there are NO non-zeros in the list. When we find a
+	 zero, we keep the previous value. If we find a zero, we set the value
+	 to true.  */
+      new_no_expr = build_x_modify_expr
+	(location, *new_var, NOP_EXPR, 
+	 build_one_cst (TREE_TYPE (*new_var)), 1);
+      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, 1);
+      if (ARITHMETIC_TYPE_P (TREE_TYPE (func_parm)))
+	comp_node = build_zero_cst (TREE_TYPE (func_parm));
+      else
+	comp_node = integer_zero_node;
+      new_cond_expr = build_x_binary_op
+	(location, NE_EXPR, func_parm, TREE_CODE (func_parm), comp_node,
+	 TREE_CODE (comp_node), NULL, tf_warning_or_error); 
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr,
+					   tf_warning_or_error);      
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX)
+    {
+      /* If the TYPE_MIN_VALUE is available for the new_var_type, then
+	 set that as the initial value.  */
+      if (TYPE_MIN_VALUE (new_var_type))
+	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					    TYPE_MIN_VALUE (new_var_type), 1);
+      else
+	/* ... otherwise set initial value as the first element of array.  */
+	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					    func_parm, 1);
+      new_no_expr  = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, 1);
+      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  func_parm, 1);
+      new_cond_expr = build_x_binary_op (location, LT_EXPR, *new_var,
+					 TREE_CODE (*new_var), func_parm,
+					 TREE_CODE (func_parm), NULL,
+					 tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr,
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN)
+    {
+      /* If the TYPE_MAX_VALUE is available for the new_var_type, then
+	 set that as the initial value.  */
+      if (TYPE_MAX_VALUE (new_var_type))
+	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					    TYPE_MAX_VALUE (new_var_type), 1);
+      else
+	/* ... otherwise set initial value as the first element of array.  */
+	new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					    func_parm, 1);
+      new_no_expr  = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, 1);
+      new_yes_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  func_parm, 1);
+      new_cond_expr = build_x_binary_op (location, GT_EXPR, *new_var,
+					 TREE_CODE (*new_var), func_parm,
+					 TREE_CODE (func_parm), NULL,
+					 tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_expr, new_no_expr,
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND)
+    {
+      new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  array_var[0], tf_warning_or_error);
+      new_exp_init = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR, func_parm, 
+					  tf_warning_or_error);
+      new_no_ind   = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, tf_warning_or_error);
+      new_no_expr  = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR,
+					  array_ind_value, tf_warning_or_error);
+      if (list_size > 1)
+	new_yes_ind  = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR, array_var[0],
+					    tf_warning_or_error);
+      else
+	new_yes_ind  = build_x_modify_expr
+	  (location, *new_var, NOP_EXPR, 
+	   TREE_OPERAND (array_op0, 1), tf_warning_or_error);
+      new_yes_expr = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR, func_parm,
+					  tf_warning_or_error);
+      new_yes_list = alloc_stmt_list ();
+      append_to_statement_list (new_yes_ind, &new_yes_list);
+      append_to_statement_list (new_yes_expr, &new_yes_list);
+
+      new_no_list = alloc_stmt_list ();
+      append_to_statement_list (new_no_ind, &new_no_list);
+      append_to_statement_list (new_no_expr, &new_no_list);
+
+      new_cond_expr = build_x_binary_op
+	(location, LT_EXPR, array_ind_value,
+	 TREE_CODE (array_ind_value),
+	 func_parm, TREE_CODE (func_parm), NULL, tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr, 
+					   new_yes_list, new_no_list, 
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
+    {
+      new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  array_var[0], 1);
+      new_exp_init = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR, func_parm, 1);
+      new_no_ind   = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  *new_var, 1);
+      new_no_expr  = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR, array_ind_value, 1);
+      if (list_size > 1)
+	new_yes_ind  = build_x_modify_expr (location, *new_var, 
+					    NOP_EXPR, array_var[0], 1);
+      else
+	new_yes_ind  = build_x_modify_expr
+	  (location, *new_var, NOP_EXPR, TREE_OPERAND (array_op0, 1), 1);
+      new_yes_expr = build_x_modify_expr (location, array_ind_value, 
+					  NOP_EXPR, func_parm, 1);
+      new_yes_list = alloc_stmt_list ();
+      append_to_statement_list (new_yes_ind, &new_yes_list);
+      append_to_statement_list (new_yes_expr, &new_yes_list);
+
+      new_no_list = alloc_stmt_list ();
+      append_to_statement_list (new_no_ind, &new_no_list);
+      append_to_statement_list (new_no_expr, &new_no_list);
+      new_cond_expr =
+	build_x_binary_op (location, GT_EXPR, array_ind_value,
+			   TREE_CODE (array_ind_value), func_parm,
+			   TREE_CODE (func_parm), NULL, tf_warning_or_error);
+      new_expr = build_x_conditional_expr (location, new_cond_expr,
+					   new_yes_list, new_no_list, 
+					   tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE)
+    {
+      vec<tree, va_gc> *func_args;
+      func_args = make_tree_vector ();
+      vec_safe_push (func_args, *new_var);
+      vec_safe_push (func_args, func_parm);
+
+      new_var_init = build_x_modify_expr (location, *new_var, NOP_EXPR,
+					  identity_value, tf_warning_or_error);
+      new_call_expr = finish_call_expr (call_fn, &func_args, false, true,
+					tf_warning_or_error);
+      new_expr = build_x_modify_expr (location, *new_var, NOP_EXPR,
+				      new_call_expr, tf_warning_or_error);
+    }
+  else if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
+    {
+      vec<tree, va_gc> *func_args;
+
+      func_args = make_tree_vector (); 
+      vec_safe_push (func_args, identity_value); 
+      vec_safe_push (func_args, func_parm);
+      new_expr = finish_call_expr (call_fn, &func_args, false, true,
+				   tf_warning_or_error);
+    }
+  else
+    gcc_unreachable ();
+
+  /* The reason we are putting initial variable twice is because the
+     new exp init below depends on this value being initialized.  */
+  for (ii = 0; ii < rank; ii++)
+    finish_expr_stmt (ind_init[ii]);
+  
+  if (an_type != BUILT_IN_CILKPLUS_SEC_REDUCE_MUTATING)
+    finish_expr_stmt (new_var_init);
+
+  if (an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MAX_IND
+      || an_type == BUILT_IN_CILKPLUS_SEC_REDUCE_MIN_IND)
+    finish_expr_stmt (new_exp_init);
+
+  an_init = pop_stmt_list (an_init);
+  append_to_statement_list_force (an_init, &loop_with_init);
+  body = new_expr;
+
+  for (ii = 0; ii < rank; ii++)
+    {
+      tree new_loop = push_stmt_list ();
+      create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body);
+      body = pop_stmt_list (new_loop);
+    }
+  append_to_statement_list_force (body, &loop_with_init);
+  
+  XDELETEVEC (compare_expr);
+  XDELETEVEC (expr_incr);
+  XDELETEVEC (ind_init);
+  XDELETEVEC (array_var);
+  
+  for (ii = 0; ii < list_size; ii++)
+    {
+      XDELETEVEC (count_down[ii]);
+      XDELETEVEC (array_value[ii]);
+      XDELETEVEC (array_stride[ii]);
+      XDELETEVEC (array_length[ii]);
+      XDELETEVEC (array_start[ii]);
+      XDELETEVEC (array_ops[ii]);
+      XDELETEVEC (array_vector[ii]);
+    }
+  XDELETEVEC (count_down);
+  XDELETEVEC (array_value);
+  XDELETEVEC (array_stride);
+  XDELETEVEC (array_length);
+  XDELETEVEC (array_start);
+  XDELETEVEC (array_ops);
+  XDELETEVEC (array_vector);
+  
+  return loop_with_init;
+}
+
+/* Returns a loop with ARRAY_REF inside it with an appropriate modify expr.
+   The LHS and/or RHS will be array notation expressions that have a
+   MODIFYCODE.  The location of the variable is specified by LOCATION. */
+
+static tree
+expand_an_in_modify_expr (location_t location, tree lhs,
+			     enum tree_code modifycode, tree rhs,
+			     tsubst_flags_t complain)
+{
+  bool **lhs_vector = NULL, **rhs_vector = NULL;
+  tree **lhs_array = NULL, **rhs_array = NULL;
+  tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE;
+  tree array_expr = NULL_TREE;
+  tree **lhs_value = NULL, **rhs_value = NULL;
+  tree **lhs_stride = NULL, **lhs_length = NULL, **lhs_start = NULL;
+  tree **rhs_stride = NULL, **rhs_length = NULL, **rhs_start = NULL;
+  tree body = NULL_TREE, *lhs_var = NULL, *rhs_var = NULL;
+  tree  *cond_expr = NULL;
+  tree *lhs_expr_incr = NULL, *rhs_expr_incr = NULL;
+  tree *lhs_ind_init = NULL, *rhs_ind_init = NULL;
+  bool **lhs_count_down = NULL, **rhs_count_down = NULL;
+  tree *lhs_compare = NULL, *rhs_compare = NULL;
+  vec<tree, va_gc> *lhs_array_operand = NULL, *rhs_array_operand = NULL;
+  size_t lhs_rank = 0, rhs_rank = 0, ii = 0, jj = 0;
+  tree ii_tree = NULL_TREE;
+  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;
+  int s_jj = 0;
+  tree lhs_begin_var, lhs_lngth_var, lhs_strde_var, rhs_begin_var;
+  tree rhs_lngth_var, rhs_strde_var;
+  tree an_init, loop_with_init = alloc_stmt_list ();
+  
+  /* Note about using find_rank (): If find_rank returns false, then it must
+     have already reported an error, thus we just return an error_mark_node
+     without any doing any error emission.  */
+  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
+	{
+	  pop_stmt_list (an_init);
+	  return NULL_TREE;
+	}
+    }
+
+  /* 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)
+    {
+      tree rhs_base = rhs;
+      if (TREE_CODE (rhs_base) == COMPOUND_EXPR)
+	rhs_base = TREE_OPERAND (rhs_base, 0);
+      if (TREE_CODE (rhs_base) == TARGET_EXPR)
+	rhs_base = TARGET_EXPR_INITIAL (rhs_base);
+      
+      if (TREE_CODE (rhs) != CALL_EXPR
+	  && !has_call_expr_with_array_notation (rhs))
+	{
+	  for (ii = 0; ii < rhs_rank; ii++)
+	    rhs_base = ARRAY_NOTATION_ARRAY (rhs);
+      	  
+	  if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (rhs))
+	    location = EXPR_LOCATION (rhs);
+	  error_at (location, "%qD cannot be scalar when %qD is not", lhs,
+		    rhs_base);
+	  return error_mark_node;
+	}
+    }
+  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
+    {
+      tree lhs_base = lhs;
+      tree rhs_base = rhs;
+      
+      for (ii = 0; ii < lhs_rank; ii++)
+	lhs_base = ARRAY_NOTATION_ARRAY (lhs_base);
+
+      while (rhs_base && TREE_CODE (rhs_base) != ARRAY_NOTATION_REF)
+	rhs_base = TREE_OPERAND (rhs_base, 0);
+      for (ii = 0; ii < rhs_rank; ii++)
+	rhs_base = ARRAY_NOTATION_ARRAY (rhs_base);
+
+      if (location == UNKNOWN_LOCATION && EXPR_HAS_LOCATION (lhs))
+	location = EXPR_LOCATION (lhs);
+      error_at (location, "rank mismatch between %qD and %qD", lhs_base,
+		rhs_base);
+      return error_mark_node;
+    }
+
+  /* Assign the array notation components to variable so that they can satisfy
+     the exec-once rule.  */
+  for (ii = 0; ii < lhs_list_size; ii++)
+    {
+      tree array_node = (*lhs_list)[ii];
+      tree array_begin = ARRAY_NOTATION_START (array_node);
+      tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+      tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+
+      if (TREE_CODE (array_begin) != INTEGER_CST)
+	{
+	  lhs_begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	  finish_expr_stmt (build_x_modify_expr (location, lhs_begin_var,
+						 NOP_EXPR, array_begin,
+						 complain));
+	  ARRAY_NOTATION_START (array_node) = lhs_begin_var;
+	}
+      if (TREE_CODE (array_lngth) != INTEGER_CST)
+	{
+	  lhs_lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	  finish_expr_stmt (build_x_modify_expr (location, lhs_lngth_var,
+						 NOP_EXPR, array_lngth,
+						 complain));
+	  ARRAY_NOTATION_LENGTH (array_node) = lhs_lngth_var;
+	}
+      if (TREE_CODE (array_strde) != INTEGER_CST)
+	{
+	  lhs_strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	  finish_expr_stmt (build_x_modify_expr (location, lhs_strde_var,
+						 NOP_EXPR, array_strde,
+						 complain));
+	  ARRAY_NOTATION_STRIDE (array_node) = lhs_strde_var;
+	}
+    }
+  for (ii = 0; ii < rhs_list_size; ii++)
+    {
+      tree array_node = (*rhs_list)[ii];
+      if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+	{
+	  tree array_begin = ARRAY_NOTATION_START (array_node);
+	  tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+	  tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+
+	  if (TREE_CODE (array_begin) != INTEGER_CST)
+	    {
+	      rhs_begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+					  integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, rhs_begin_var,
+						     NOP_EXPR, array_begin,
+						     complain));
+	      ARRAY_NOTATION_START (array_node) = rhs_begin_var;
+	    }
+	  if (TREE_CODE (array_lngth) != INTEGER_CST)
+	    {
+	      rhs_lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+					  integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, rhs_lngth_var,
+						     NOP_EXPR, array_lngth,
+						     complain));
+	      ARRAY_NOTATION_LENGTH (array_node) = rhs_lngth_var;
+	    }
+	  if (TREE_CODE (array_strde) != INTEGER_CST)
+	    {
+	      rhs_strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+					  integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, rhs_strde_var,
+						     NOP_EXPR, array_strde,
+						     complain));
+	      ARRAY_NOTATION_STRIDE (array_node) = rhs_strde_var;
+	    }
+	}
+    }  
+  lhs_vector = XNEWVEC (bool *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_vector[ii] = XNEWVEC (bool, lhs_rank);
+  
+  rhs_vector = XNEWVEC (bool *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_vector[ii] = XNEWVEC (bool, rhs_rank);
+
+  lhs_array = XNEWVEC (tree *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_array[ii] = XNEWVEC (tree, lhs_rank);
+  
+  rhs_array = XNEWVEC (tree *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_array[ii] = XNEWVEC (tree, rhs_rank);
+
+  lhs_value = XNEWVEC (tree *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_value[ii] = XNEWVEC (tree, lhs_rank);
+  
+  rhs_value = XNEWVEC (tree *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_value[ii] = XNEWVEC (tree, rhs_rank);
+
+  lhs_stride = XNEWVEC (tree *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_stride[ii] = XNEWVEC (tree, lhs_rank);
+
+  rhs_stride = XNEWVEC (tree *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_stride[ii] = XNEWVEC (tree, rhs_rank);
+
+  lhs_length = XNEWVEC (tree *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_length[ii] = XNEWVEC (tree, lhs_rank);
+  
+  rhs_length = XNEWVEC (tree *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_length[ii] = XNEWVEC (tree, rhs_rank);
+
+  lhs_start = XNEWVEC (tree *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_start[ii] = XNEWVEC (tree, lhs_rank);
+  
+  rhs_start = XNEWVEC (tree *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_start[ii] = XNEWVEC (tree, rhs_rank);
+   
+  lhs_var = XNEWVEC (tree, lhs_rank);
+  rhs_var = XNEWVEC (tree, rhs_rank);
+  
+
+  /* The reason why we are just using lhs_rank for this is because we have then
+     following scenarios:
+     1.  LHS_RANK == RHS_RANK
+     2.  LHS_RANK != RHS_RANK && RHS_RANK = 0
+
+     In both the scenarios, just checking the LHS_RANK is OK.  */
+
+  cond_expr = XNEWVEC (tree, MAX (lhs_rank, rhs_rank));
+  lhs_expr_incr = XNEWVEC (tree, lhs_rank);
+  rhs_expr_incr = XNEWVEC (tree, rhs_rank);
+
+  lhs_ind_init = XNEWVEC (tree, lhs_rank);
+  rhs_ind_init = XNEWVEC (tree, rhs_rank);
+
+  lhs_count_down = XNEWVEC (bool *, lhs_list_size);
+  for (ii = 0; ii < lhs_list_size; ii++)
+    lhs_count_down[ii] = XNEWVEC (bool, lhs_rank);
+  
+  rhs_count_down = XNEWVEC (bool *, rhs_list_size);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    rhs_count_down[ii] = XNEWVEC (bool, rhs_rank);
+
+  lhs_compare = XNEWVEC (tree, lhs_rank);
+  rhs_compare = XNEWVEC (tree, rhs_rank);
+
+  if (lhs_rank)
+    {
+      for (ii = 0; ii < lhs_list_size; ii++)
+	{
+	  jj = 0;
+	  ii_tree = (*lhs_list)[ii];
+	  while (ii_tree)
+	    {
+	      if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
+		{
+		  lhs_array[ii][jj] = ii_tree;
+		  jj++;
+		  ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
+		}
+	      else if (TREE_CODE (ii_tree) == ARRAY_REF)
+		ii_tree = TREE_OPERAND (ii_tree, 0);
+	      else if (TREE_CODE (ii_tree) == VAR_DECL
+		       || TREE_CODE (ii_tree) == PARM_DECL)
+		break;
+	    }
+	}
+    }
+  else
+    lhs_array[0][0] = NULL_TREE;
+  
+  if (rhs_rank)
+    {
+      for (ii = 0; ii < rhs_list_size; ii++)
+	{
+	  jj = 0;
+	  ii_tree = (*rhs_list)[ii];
+	  while (ii_tree)
+	    {
+	      if (TREE_CODE (ii_tree) == ARRAY_NOTATION_REF)
+		{
+		  rhs_array[ii][jj] = ii_tree;
+		  jj++;
+		  ii_tree = ARRAY_NOTATION_ARRAY (ii_tree);
+		}
+	      else if (TREE_CODE (ii_tree) == ARRAY_REF)
+		ii_tree = TREE_OPERAND (ii_tree, 0);
+	      else if (TREE_CODE (ii_tree) == VAR_DECL
+		       || TREE_CODE (ii_tree) == PARM_DECL
+		       || TREE_CODE (ii_tree) == CALL_EXPR)
+		break;
+	    }
+	}
+    }  
+  for (ii = 0; ii < lhs_list_size; ii++)
+    {
+      if (TREE_CODE ((*lhs_list)[ii]) == ARRAY_NOTATION_REF)
+	{
+	  for (jj = 0; jj < lhs_rank; jj++)
+	    {
+	      if (TREE_CODE (lhs_array[ii][jj]) == ARRAY_NOTATION_REF)
+		{
+		  lhs_value[ii][jj] = ARRAY_NOTATION_ARRAY (lhs_array[ii][jj]);
+		  lhs_start[ii][jj] = ARRAY_NOTATION_START (lhs_array[ii][jj]);
+		  lhs_length[ii][jj] =
+		    fold_build1 (CONVERT_EXPR, integer_type_node,
+				 ARRAY_NOTATION_LENGTH (lhs_array[ii][jj]));
+		  lhs_stride[ii][jj] =
+		    fold_build1 (CONVERT_EXPR, integer_type_node,
+				 ARRAY_NOTATION_STRIDE (lhs_array[ii][jj]));
+		  lhs_vector[ii][jj] = true;
+		  
+		  /* If the stride value is variable (i.e. not constant) then
+		     assume that the length is positive.  */
+		  if (!TREE_CONSTANT (lhs_length[ii][jj]))
+		    lhs_count_down[ii][jj] = false;
+		  else if (tree_int_cst_lt
+			   (lhs_length[ii][jj],
+			    build_zero_cst (TREE_TYPE (lhs_length[ii][jj]))))
+		    lhs_count_down[ii][jj] = true;
+		  else
+		    lhs_count_down[ii][jj] = false;
+		}
+	      else
+		lhs_vector[ii][jj] = false;
+	    }
+	}
+    }
+  for (ii = 0; ii < rhs_list_size; ii++)
+    {
+      if (TREE_CODE ((*rhs_list)[ii]) == ARRAY_NOTATION_REF)
+	{
+	  for (jj = 0; jj < rhs_rank; jj++)
+	    {
+	      if (TREE_CODE (rhs_array[ii][jj]) == ARRAY_NOTATION_REF)
+		{
+		  rhs_value[ii][jj]  = ARRAY_NOTATION_ARRAY (rhs_array[ii][jj]);
+		  rhs_start[ii][jj]  = ARRAY_NOTATION_START (rhs_array[ii][jj]);
+		  rhs_length[ii][jj] =
+		    ARRAY_NOTATION_LENGTH (rhs_array[ii][jj]);
+		  rhs_stride[ii][jj] =
+		    ARRAY_NOTATION_STRIDE (rhs_array[ii][jj]);
+		  rhs_vector[ii][jj] = true;
+		  /* If the stride value is variable (i.e. not constant) then
+		     assume that the length is positive.  */
+		  if (!TREE_CONSTANT (rhs_length[ii][jj]))
+		    rhs_count_down[ii][jj] = false;
+		  else if (tree_int_cst_lt
+			   (rhs_length[ii][jj],
+			    build_zero_cst (TREE_TYPE (rhs_length[ii][jj]))))
+		    rhs_count_down[ii][jj] = true;
+		  else
+		    rhs_count_down[ii][jj] = false;	
+		}
+	      else
+		rhs_vector[ii][jj] = false;
+	    }
+	}
+      else
+	for (jj = 0; jj < rhs_rank; jj++)
+	  {
+	    rhs_vector[ii][jj] = false;
+	    rhs_length[ii][jj] = NULL_TREE;
+	  }
+    }
+
+  if (length_mismatch_in_expr_p (EXPR_LOCATION (lhs), lhs_length,
+				 lhs_list_size, lhs_rank)
+      || length_mismatch_in_expr_p (EXPR_LOCATION (rhs), rhs_length,
+				    rhs_list_size, rhs_rank))
+    {
+      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_length[0][0]) == INTEGER_CST
+      && rhs_length[0][0] && TREE_CODE (rhs_length[0][0]) == INTEGER_CST)
+    {
+      HOST_WIDE_INT l_length = int_cst_value (lhs_length[0][0]);
+      HOST_WIDE_INT r_length = int_cst_value (rhs_length[0][0]);
+      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_start[0][ii] && TREE_TYPE (lhs_start[0][ii]))
+	lhs_var[ii] =  build_decl (location, VAR_DECL, NULL_TREE,
+				   TREE_TYPE (lhs_start[0][ii]));
+    else
+      lhs_var[ii] = build_decl (location, VAR_DECL, NULL_TREE,
+				integer_type_node);
+
+  for (ii = 0; ii < rhs_list_size; ii++)
+    {
+      if (TREE_CODE ((*rhs_list)[ii]) == CALL_EXPR)
+	{
+	  int idx_value = 0;
+	  tree func_name = CALL_EXPR_FN ((*rhs_list)[ii]);
+	  if (TREE_CODE (func_name) == ADDR_EXPR)
+	    {
+	      if (is_sec_implicit_index_fn (func_name))
+		{
+		  idx_value = 
+		    extract_sec_implicit_index_arg (location, (*rhs_list)[ii]);
+		  if (idx_value < (int) lhs_rank && idx_value >= 0)
+		    vec_safe_push (rhs_array_operand, lhs_var[idx_value]);
+		  else if (idx_value == -1)
+		    return error_mark_node;
+		  else
+		    {
+		      size_t ee = 0;
+		      tree lhs_base = (*lhs_list)[ii];
+		      for (ee = 0; ee < lhs_rank; ee++)
+			if (lhs_base
+			    && TREE_CODE (lhs_base) == ARRAY_NOTATION_REF)
+			  lhs_base = ARRAY_NOTATION_ARRAY (lhs_base);
+
+		      if (location == UNKNOWN_LOCATION
+			  && EXPR_HAS_LOCATION (lhs))
+			location = EXPR_LOCATION (lhs);
+		      error_at (location, "__sec_implicit_index argument %d "
+				"must be less than the rank of %qD", idx_value,
+				lhs_base);
+		      return error_mark_node;
+		    }
+		}
+	      else
+		vec_safe_push (rhs_array_operand, (*rhs_list)[ii]);
+	    }
+	  else
+	    vec_safe_push (rhs_array_operand, (*rhs_list)[ii]);
+	}
+      else
+	vec_safe_push (rhs_array_operand, (*rhs_list)[ii]);
+    }
+
+  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 < lhs_rank; ii++)
+    if (lhs_vector[0][ii])
+      {
+	lhs_ind_init[ii] = build_x_modify_expr
+	  (location, lhs_var[ii], NOP_EXPR,
+	   build_zero_cst (TREE_TYPE (lhs_var[ii])), complain);
+      }
+    
+
+  for (ii = 0; ii < rhs_rank; ii++)
+    {
+      /* When we have a polynomial, we assume that the indices are of type
+	 integer.  */
+      rhs_var[ii] =  build_decl (location, VAR_DECL, NULL_TREE,
+				 TREE_TYPE (rhs_start[0][ii]));
+      rhs_ind_init[ii] = build_x_modify_expr
+	(location, rhs_var[ii], NOP_EXPR, 
+	 build_zero_cst (TREE_TYPE (rhs_var[ii])), complain);
+    }
+
+  if (lhs_rank)
+    {
+      for (ii = 0; ii < lhs_list_size; ii++)
+	{
+	  if (lhs_vector[ii][0])
+	    {
+	      /* The last ARRAY_NOTATION element's ARRAY component should be
+		 the array's base value.  */
+	      tree lhs_array_opr = lhs_value[ii][lhs_rank - 1];
+	      for (s_jj = lhs_rank - 1; s_jj >= 0; s_jj--)
+		{
+		  tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
+		  if ((TREE_TYPE (lhs_start[ii][s_jj]) ==
+		       TREE_TYPE (lhs_stride[ii][s_jj]))
+		      && (TREE_TYPE (lhs_stride[ii][s_jj]) !=
+			  TREE_TYPE (lhs_var[s_jj])))
+		    {
+		      /* If stride and start are of same type and the induction
+			 var is not, convert induction variable to stride's
+			 type.  */
+		      start = lhs_start[ii][s_jj];
+		      stride = lhs_stride[ii][s_jj];
+		      var = build_c_cast (location,
+					  TREE_TYPE (lhs_stride[ii][s_jj]),
+					  lhs_var[s_jj]);
+		    }
+		  else if (TREE_TYPE (lhs_start[ii][s_jj]) !=
+			   TREE_TYPE (lhs_stride[ii][s_jj]))
+		    {
+		      /* If we reach here, then the stride and start are of
+			 different types, and so it doesn't really matter what
+			 the induction variable type is, convert everything to 
+			 integer.  The reason why we pick an integer instead of 
+			 something like size_t is because the stride and 
+			 length can be + or -.  */
+		      start = build_c_cast (location, integer_type_node,
+					    lhs_start[ii][s_jj]);
+		      stride = build_c_cast (location, integer_type_node,
+					     lhs_stride[ii][s_jj]);
+		      var = build_c_cast (location, integer_type_node,
+					  lhs_var[s_jj]);
+		    }
+		  else
+		    {
+		      start = lhs_start[ii][s_jj];
+		      stride = lhs_stride[ii][s_jj];
+		      var = lhs_var[s_jj];
+		    }
+		  if (lhs_count_down[ii][s_jj])
+		    /* Array[start_index - (induction_var * stride)].  */
+		    lhs_array_opr = grok_array_decl
+		      (location, lhs_array_opr,
+		       build2 (MINUS_EXPR, TREE_TYPE (var), start,
+			       build2 (MULT_EXPR, TREE_TYPE (var), var,
+				       stride)), false);	
+		  else
+		    /* Array[start_index + (induction_var * stride)].  */
+		    lhs_array_opr = grok_array_decl
+		      (location, lhs_array_opr,
+		       build2 (PLUS_EXPR, TREE_TYPE (var), start,
+			       build2 (MULT_EXPR, TREE_TYPE (var), var,
+				       stride)), false);
+		}
+	      vec_safe_push (lhs_array_operand, lhs_array_opr);
+	    }
+	  else
+	    vec_safe_push (lhs_array_operand, integer_one_node);
+	}
+      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)
+    {
+      for (ii = 0; ii < rhs_list_size; ii++)
+	{
+	  if (rhs_vector[ii][0])
+	    {
+	      tree rhs_array_opr = rhs_value[ii][rhs_rank - 1];
+	      for (s_jj = rhs_rank - 1; s_jj >= 0; s_jj--)
+		{
+		  tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
+		  if ((TREE_TYPE (rhs_start[ii][s_jj]) ==
+		       TREE_TYPE (rhs_stride[ii][s_jj]))
+		      && (TREE_TYPE (rhs_stride[ii][s_jj]) !=
+			  TREE_TYPE (rhs_var[s_jj])))
+		    {
+		      /* If stride and start are of same type and the induction
+			 var is not, convert induction variable to stride's
+			 type.  */
+		      start = rhs_start[ii][s_jj];
+		      stride = rhs_stride[ii][s_jj];
+		      var = build_c_cast (location,
+					  TREE_TYPE (rhs_stride[ii][s_jj]),
+					  rhs_var[s_jj]);
+		    }
+		  else if (TREE_TYPE (rhs_start[ii][s_jj]) !=
+			   TREE_TYPE (rhs_stride[ii][s_jj]))
+		    {
+		      /* If we reach here, then the stride and start are of
+			 different types, and so it doesn't really matter what
+			 the induction variable type is, convert everything to 
+			  integer.  The reason why we pick an integer instead 
+			  of something like size_t is because the stride and 
+			  length can be + or -.  */
+		      start = build_c_cast (location, integer_type_node,
+					    rhs_start[ii][s_jj]);
+		      stride = build_c_cast (location, integer_type_node,
+					     rhs_stride[ii][s_jj]);
+		      var = build_c_cast (location, integer_type_node,
+					  rhs_var[s_jj]);
+		    }
+		  else
+		    {
+		      start = rhs_start[ii][s_jj];
+		      stride = rhs_stride[ii][s_jj];
+		      var = rhs_var[s_jj];
+		    }
+		  if (rhs_count_down[ii][s_jj])
+		    /* Array[start_index - (induction_var * stride)].  */
+		    rhs_array_opr = grok_array_decl
+		      (location, rhs_array_opr,
+		       build2 (MINUS_EXPR, TREE_TYPE (var), start,
+			       build2 (MULT_EXPR, TREE_TYPE (var), var,
+				       stride)), false);	
+		  else
+		    /* Array[start_index + (induction_var * stride)].  */
+		    rhs_array_opr = grok_array_decl
+		      (location, rhs_array_opr,
+		       build2 (PLUS_EXPR, TREE_TYPE (var), start,
+			       build2 (MULT_EXPR, TREE_TYPE (var), var,
+				       stride)), false);
+		}
+	      vec_safe_push (rhs_array_operand, rhs_array_opr);
+	    }
+	  else
+	    /* This is just a dummy node to make sure the list sizes for both
+	       array list and array operand list are the same.  */
+	    vec_safe_push (rhs_array_operand, integer_one_node);
+	}
+      for (ii = 0; ii < rhs_list_size; ii++)
+	{
+	  tree rhs_node = (*rhs_list)[ii];
+	  if (TREE_CODE (rhs_node) == CALL_EXPR)
+	    {
+	      int idx_value = 0;
+	      tree func_name = CALL_EXPR_FN (rhs_node);
+	      if (TREE_CODE (func_name) == ADDR_EXPR)
+		if (is_sec_implicit_index_fn (func_name))
+		  {
+		    idx_value = 
+		      extract_sec_implicit_index_arg (location, rhs_node);
+		    if (idx_value < (int) lhs_rank && idx_value >= 0)
+		      vec_safe_push (rhs_array_operand, rhs_var[idx_value]);
+		    else
+		      {
+			size_t ee = 0;
+			tree rhs_base = (*lhs_list)[ii];
+			for (ee = 0; ee < rhs_rank; ee++)
+			  if (rhs_base
+			      && TREE_CODE (rhs_base) == ARRAY_NOTATION_REF)
+			    rhs_base = ARRAY_NOTATION_ARRAY (rhs_base);
+
+			error_at (location, "__sec_implicit_index argument %d "
+				  "must be less than rank of %qD", idx_value,
+				  rhs_base);
+			return error_mark_node;
+		      }
+		  }
+	    }
+	}	
+      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
+      array_expr_rhs = rhs;
+    }
+  else
+    {
+      for (ii = 0; ii < rhs_list_size; ii++)
+	{
+	  tree rhs_node = (*rhs_list)[ii];
+	  if (TREE_CODE (rhs_node) == CALL_EXPR)
+	    {
+	      int idx_value = 0;
+	      tree func_name = CALL_EXPR_FN (rhs_node);
+	      if (is_sec_implicit_index_fn (func_name))
+		{
+		  idx_value =  extract_sec_implicit_index_arg (location,
+							       rhs_node);
+		  if (idx_value < (int) lhs_rank && idx_value >= 0)
+		    vec_safe_push (rhs_array_operand, lhs_var[idx_value]);
+		  else
+		    {
+		      size_t ee = 0;
+		      tree lhs_base = (*lhs_list)[ii];
+		      for (ee = 0; ee < lhs_rank; ee++)
+			if (lhs_base
+			    && TREE_CODE (lhs_base) == ARRAY_NOTATION_REF)
+			  lhs_base = ARRAY_NOTATION_ARRAY (lhs_base);
+		      error_at (location, "__sec_implicit_index argument %d "
+				"must be less than the rank of %qD", idx_value,
+				lhs_base);
+		      return error_mark_node;
+		    }
+		}
+	    }
+	}
+      replace_array_notations (&rhs, true, rhs_list, rhs_array_operand);
+      array_expr_rhs = rhs;
+      rhs_expr_incr[0] = NULL_TREE;
+    }
+  
+  for (ii = 0; ii < rhs_rank; ii++)
+    if (rhs_count_down[0][ii])
+      rhs_expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR,
+					    rhs_var[ii], complain);
+    else
+      rhs_expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR,
+					    rhs_var[ii], complain);
+  
+  for (ii = 0; ii < lhs_rank; ii++)
+    if (lhs_count_down[0][ii])
+      lhs_expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR,
+					    lhs_var[ii], complain);
+    else
+      lhs_expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR,
+					    lhs_var[ii], complain);
+  if (!array_expr_lhs)
+    array_expr_lhs = lhs;
+  
+  array_expr = build_x_modify_expr (location, array_expr_lhs, modifycode,
+				    array_expr_rhs, complain);
+
+  for (jj = 0; jj < MAX (lhs_rank, rhs_rank); jj++)
+    {
+      if (rhs_rank && rhs_expr_incr[jj])
+	{
+	  size_t iii = 0;
+	  if (lhs_rank)
+	    {
+	      if (lhs_count_down[0][jj])
+		lhs_compare[jj] = build_x_binary_op
+		  (location, GT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]),
+		   lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL,
+		   complain);
+	      else
+		lhs_compare[jj] = build_x_binary_op
+		  (location, LT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]),
+		   lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL,
+		   complain);
+	    }
+	  else
+	    lhs_compare[jj] = NULL_TREE;
+
+	  for (iii = 0; iii < rhs_list_size; iii++)
+	    if (rhs_vector[iii][jj])
+	      break;
+	  
+	  /* What we are doing here is this:
+	     We always count up, so:
+	       if (length is negative ==> which means we count down)
+	          we multiply length by -1 and count up => ii < -LENGTH
+	       else
+	          we just count up, so we compare for  ii < LENGTH
+	   */
+	  if (rhs_count_down[iii][jj])
+	    {
+	      tree new_rhs = build_x_modify_expr
+		(location, rhs_length[iii][jj], MULT_EXPR,
+		 build_int_cst (TREE_TYPE (rhs_length[iii][jj]), -1), complain);
+	      rhs_compare[jj] = build_x_binary_op
+		(location, GT_EXPR, rhs_var[jj], TREE_CODE (rhs_var[jj]),
+		 new_rhs, TREE_CODE (new_rhs), NULL, complain);
+	    }
+	  else
+	    rhs_compare[jj] = build_x_binary_op
+	      (location, LT_EXPR, rhs_var[jj], TREE_CODE (rhs_var[jj]),
+	       rhs_length[iii][jj], TREE_CODE (rhs_length[0][jj]), NULL,
+	       complain);
+	   
+	  if (lhs_rank)
+	    cond_expr[jj] = build_x_binary_op
+	      (location, TRUTH_ANDIF_EXPR, lhs_compare[jj],
+	       TREE_CODE (lhs_compare[jj]), rhs_compare[jj],
+	       TREE_CODE (rhs_compare[jj]), NULL, complain);
+	  else
+	    cond_expr[jj] = rhs_compare[jj];
+	}
+      else
+	{
+	  if (lhs_count_down[0][jj])
+	    cond_expr[jj] = build_x_binary_op
+	      (location, GT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]),
+	       lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL,
+	       complain);
+	    else
+	      cond_expr[jj] = build_x_binary_op
+		(location, LT_EXPR, lhs_var[jj], TREE_CODE (lhs_var[jj]),
+		 lhs_length[0][jj], TREE_CODE (lhs_length[0][jj]), NULL,
+		 complain);
+	}
+    }
+  
+  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 init_list = alloc_stmt_list ();
+      tree new_loop = push_stmt_list ();
+
+      if (lhs_rank)
+	{
+	  append_to_statement_list_force (lhs_ind_init[ii], &init_list);
+	  append_to_statement_list_force (lhs_expr_incr[ii], &incr_list);
+	}
+      if (rhs_rank)
+	{
+	  append_to_statement_list_force (rhs_ind_init[ii], &init_list);
+	  append_to_statement_list_force (rhs_expr_incr[ii], &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);
+  for (ii = 0; ii < rhs_list_size; ii++)
+    {
+      XDELETEVEC (rhs_vector[ii]);
+      XDELETEVEC (rhs_array[ii]);
+      XDELETEVEC (rhs_value[ii]);
+      XDELETEVEC (rhs_length[ii]);
+      XDELETEVEC (rhs_stride[ii]);
+      XDELETEVEC (rhs_start[ii]);
+    }
+    for (ii = 0; ii < lhs_list_size; ii++)
+    {
+      XDELETEVEC (lhs_vector[ii]);
+      XDELETEVEC (lhs_array[ii]);
+      XDELETEVEC (lhs_value[ii]);
+      XDELETEVEC (lhs_length[ii]);
+      XDELETEVEC (lhs_stride[ii]);
+      XDELETEVEC (lhs_start[ii]);
+    }
+  if (rhs_vector)
+    XDELETEVEC (rhs_vector);
+
+  if (rhs_array)
+    XDELETEVEC (rhs_array);
+  if (rhs_value)
+    XDELETEVEC (rhs_value);
+  if (rhs_length)
+    XDELETEVEC (rhs_length);
+  if (rhs_stride)
+    XDELETEVEC (rhs_stride);
+  if (rhs_start)
+    XDELETEVEC (rhs_start);
+  if (rhs_expr_incr)    
+    XDELETEVEC (rhs_expr_incr);
+  if (rhs_ind_init)
+    XDELETEVEC (rhs_ind_init);
+  if (rhs_compare)
+    XDELETEVEC (rhs_compare);
+  if (lhs_compare)
+    XDELETEVEC (lhs_compare);
+  
+  return loop_with_init;
+}
+
+/* Helper function for expand_conditonal_array_notations. Encloses the conditional
+   statement passed in ORIG_STMT with a loop around it and replaces the
+   condition in STMT with a ARRAY_REF tree-node to the array.  The condition
+   must have a ARRAY_NOTATION_REF tree.  */
+
+static tree
+cp_expand_cond_array_notations (tree orig_stmt)
+{
+  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
+  size_t list_size = 0;
+  size_t rank = 0, ii = 0, jj = 0;
+  tree **array_ops, *array_var, jj_tree, body, stmt = NULL_TREE;
+  tree **array_value, **array_stride, **array_length, **array_start;
+  tree *compare_expr, an_init, *expr_incr, *ind_init;
+  tree builtin_loop, new_var = NULL_TREE;
+  bool **count_down, **array_vector;
+  tree loop_with_init = alloc_stmt_list ();
+  int s_jj = 0;
+  tree begin_var, lngth_var, strde_var;
+  tsubst_flags_t complain = tf_warning_or_error;
+  location_t location = UNKNOWN_LOCATION;
+
+  if (TREE_CODE (orig_stmt) == COND_EXPR)
+    {
+      size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
+      tree yes_expr = COND_EXPR_THEN (orig_stmt);
+      tree no_expr = COND_EXPR_ELSE (orig_stmt);
+      tree cond = COND_EXPR_COND (orig_stmt);
+      if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
+	  || !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
+			 &yes_rank)
+	  || find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
+			&no_rank))
+	return error_mark_node;
+      if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0)
+	{
+	  error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
+		    " expression of parent if-statement");
+	  return error_mark_node;
+	}
+      else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0)
+	{
+	  error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
+		    "expression of parent if-statement");
+	  return error_mark_node;
+	}
+    }
+  else if (TREE_CODE (orig_stmt) == IF_STMT)
+    {
+      size_t cond_rank = 0, yes_rank = 0, no_rank = 0;
+      tree yes_expr = THEN_CLAUSE (orig_stmt);
+      tree no_expr = ELSE_CLAUSE (orig_stmt);
+      tree cond = IF_COND (orig_stmt);
+      if (!find_rank (EXPR_LOCATION (cond), cond, cond, true, &cond_rank)
+	  || (yes_expr
+	      && !find_rank (EXPR_LOCATION (yes_expr), yes_expr, yes_expr, true,
+			     &yes_rank))
+	  || (no_expr
+	      && !find_rank (EXPR_LOCATION (no_expr), no_expr, no_expr, true,
+			     &no_rank)))
+	return error_mark_node;
+      if (cond_rank != 0 && cond_rank != yes_rank && yes_rank != 0)
+	{
+	  error_at (EXPR_LOCATION (yes_expr), "rank mismatch with controlling"
+		    " expression of parent if-statement");
+	  return error_mark_node;
+	}
+      else if (cond_rank != 0 && cond_rank != no_rank && no_rank != 0)
+	{
+	  error_at (EXPR_LOCATION (no_expr), "rank mismatch with controlling "
+		    "expression of parent if-statement");
+	  return error_mark_node;
+	}
+    }
+
+  if (!find_rank (EXPR_LOCATION (orig_stmt), orig_stmt, orig_stmt, true,
+		  &rank))
+    return error_mark_node;
+  if (rank == 0)
+    return orig_stmt;
+
+  extract_array_notation_exprs (orig_stmt, false, &array_list);
+  stmt = alloc_stmt_list ();
+  for (ii = 0; ii < vec_safe_length (array_list); ii++)
+    {
+      tree array_node = (*array_list)[ii];
+      if (TREE_CODE (array_node) == CALL_EXPR
+	  || TREE_CODE (array_node) == AGGR_INIT_EXPR)
+	{
+	  builtin_loop = expand_sec_reduce_builtin (array_node, &new_var);
+	  if (builtin_loop == error_mark_node)
+	    finish_expr_stmt (error_mark_node);
+	  else if (new_var)
+	    {
+	      vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL;
+	      vec_safe_push (sub_list, array_node);
+	      vec_safe_push (new_var_list, new_var);
+	      replace_array_notations (&orig_stmt, false, sub_list,
+				       new_var_list);
+	      append_to_statement_list_force (builtin_loop, &stmt);
+	    }
+	}
+    }
+  append_to_statement_list_force (orig_stmt, &stmt);
+  rank = 0;
+  array_list = NULL;
+  if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank))
+    return error_mark_node;
+  if (rank == 0)
+    return stmt;
+  
+  extract_array_notation_exprs (stmt, true, &array_list);
+  list_size = vec_safe_length (array_list);
+  if (list_size == 0)
+    return stmt;
+
+  location = EXPR_LOCATION (orig_stmt);
+  array_ops = XNEWVEC (tree *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_ops[ii] = XNEWVEC (tree, rank);
+  
+  array_vector = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_vector[ii] = XNEWVEC (bool, rank);
+
+  array_value  = XNEWVEC (tree *, list_size);
+  array_stride = XNEWVEC (tree *, list_size);
+  array_length = XNEWVEC (tree *, list_size);
+  array_start  = XNEWVEC (tree *, list_size);
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      array_value[ii]  = XNEWVEC (tree, rank);
+      array_stride[ii] = XNEWVEC (tree, rank);
+      array_length[ii] = XNEWVEC (tree, rank);
+      array_start[ii]  = XNEWVEC (tree, rank);
+    }
+
+  compare_expr = XNEWVEC (tree, rank);
+  expr_incr = XNEWVEC (tree, rank);
+  ind_init = XNEWVEC (tree, rank);
+
+  list_size = vec_safe_length (array_list);
+  count_down = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    count_down[ii] = XNEWVEC (bool, rank);
+  
+  array_var = XNEWVEC (tree, rank);
+  an_init = push_stmt_list ();
+
+    /* Assign the array notation components to variable so that they can satisfy
+     the exec-once rule.  */
+  for (ii = 0; ii < list_size; ii++)
+    {
+      tree array_node = (*array_list)[ii];
+      if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+	{
+	  tree array_begin = ARRAY_NOTATION_START (array_node);
+	  tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+	  tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+
+	  if (TREE_CODE (array_begin) != INTEGER_CST)
+	    {
+	      begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, begin_var,
+						     NOP_EXPR, array_begin,
+						     complain));
+	      ARRAY_NOTATION_START (array_node) = begin_var;
+	    }
+	  if (TREE_CODE (array_lngth) != INTEGER_CST)
+	    {
+	      lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, lngth_var,
+						     NOP_EXPR, array_lngth,
+						     complain));
+	      ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+	    }
+	  if (TREE_CODE (array_strde) != INTEGER_CST)
+	    {
+	      strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, strde_var,
+						     NOP_EXPR, array_strde,
+						     complain));
+	      ARRAY_NOTATION_STRIDE (array_node) = strde_var;
+	    }
+	}
+    }
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      jj = 0;
+      jj_tree = (*array_list)[ii];
+      while (jj_tree)
+	{
+	  if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF)
+	    {
+	      array_ops[ii][jj] = jj_tree;
+	      jj++;
+	      jj_tree = ARRAY_NOTATION_ARRAY (jj_tree);
+	    }
+	  else if (TREE_CODE (jj_tree) == ARRAY_REF)
+	    jj_tree = TREE_OPERAND (jj_tree, 0);
+	  else if (TREE_CODE (jj_tree) == VAR_DECL
+		   || TREE_CODE (jj_tree) == PARM_DECL)
+	    break;
+	}
+    }
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
+	{
+	  for (jj = 0; jj < rank; jj++)
+	    {
+	      if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF)
+		{
+		  array_value[ii][jj] =
+		    ARRAY_NOTATION_ARRAY (array_ops[ii][jj]);
+		  array_start[ii][jj] =
+		    ARRAY_NOTATION_START (array_ops[ii][jj]);
+		  array_length[ii][jj] =
+		    ARRAY_NOTATION_LENGTH (array_ops[ii][jj]);
+		  array_stride[ii][jj] =
+		    ARRAY_NOTATION_STRIDE (array_ops[ii][jj]);
+		  array_vector[ii][jj] = true;
+
+		  if (!integer_zerop (array_length[ii][jj])
+		      && !integer_nonzerop (array_length[ii][jj]))
+		    count_down[ii][jj] = false;
+		  else if (tree_int_cst_lt
+			   (array_length[ii][jj],
+			    build_zero_cst (TREE_TYPE (array_length[ii][jj]))))
+		    count_down[ii][jj] = true;
+		  else
+		    count_down[ii][jj] = false;
+		}
+	      else
+		array_vector[ii][jj] = false;
+	    }
+	}
+    }
+  for (ii = 0; ii < rank; ii++)
+    {
+      if (TREE_TYPE (array_start[0][ii])
+	  && TREE_CODE (TREE_TYPE (array_start[0][ii])) != TEMPLATE_TYPE_PARM)
+	{
+	  array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE,
+				      TREE_TYPE (array_start[0][ii]));
+	  ind_init[ii] = build_x_modify_expr
+	    (location, array_var[ii], NOP_EXPR, 
+	     build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error);
+	}
+      else
+	{
+	  array_var[ii] = build_min_nt_loc (location, VAR_DECL,
+					    NULL_TREE, NULL_TREE);
+	  ind_init[ii] = build_x_modify_expr (location, array_var[ii], 
+					      NOP_EXPR,
+					      integer_zero_node, 1);
+	}
+    }
+  for (ii = 0; ii < list_size; ii++)
+    {
+      if (array_vector[ii][0])
+	{
+	  tree array_opr = array_value[ii][rank - 1];
+	  for (s_jj = rank - 1; s_jj >= 0; s_jj--)
+	    {
+	      tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
+
+	      /* If stride and start are of same type and the induction var
+		 is not, convert induction variable to stride's type.  */
+	      if ((TREE_TYPE (array_start[ii][s_jj]) ==
+		   TREE_TYPE (array_stride[ii][s_jj]))
+		  && (TREE_TYPE (array_stride[ii][s_jj]) !=
+		      TREE_TYPE (array_var[s_jj])))
+		{
+		  start = array_start[ii][s_jj];
+		  stride = array_stride[ii][s_jj];
+		  var =
+		    build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]),
+				  array_var[s_jj]);
+		}
+	      else if (TREE_TYPE (array_start[ii][s_jj]) !=
+			TREE_TYPE (array_stride[ii][s_jj]))
+		{
+		  /* If we reach here, then the stride and start are of
+		     different types, and so it doesn't really matter what
+		     the induction variable type is, we stay safe and convert
+		     everything to integer.  The reason why we pick an integer
+		     instead of something like size_t is because the stride
+		     and length can be + or -.  */
+		  start = build_c_cast (location, integer_type_node,
+					array_start[ii][s_jj]);
+		  stride = build_c_cast (location, integer_type_node,
+					 array_stride[ii][s_jj]);
+		  var = build_c_cast (location, integer_type_node,
+				      array_var[s_jj]);
+		}
+	      else
+		{
+		  start = array_start[ii][s_jj];
+		  stride = array_stride[ii][s_jj];
+		  var = array_var[s_jj];
+		}
+	      if (count_down[ii][s_jj])
+		/* Array[start_index - (induction_var * stride)].  */
+		array_opr = grok_array_decl
+		  (location, array_opr,
+		   build2 (MINUS_EXPR, TREE_TYPE (var), start,
+			   build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		   false);	
+	      else
+		/* Array[start_index + (induction_var * stride)].  */
+		array_opr = grok_array_decl
+		  (location, array_opr,
+		   build2 (PLUS_EXPR, TREE_TYPE (var), start,
+			   build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		   false);
+		
+	    }
+	  vec_safe_push (array_operand, array_opr);
+	}
+      else
+	vec_safe_push (array_operand, integer_one_node);
+    }
+  replace_array_notations (&stmt, true, array_list, array_operand);
+
+  for (ii = 0; ii < rank; ii++)
+    if (count_down[0][ii])
+      expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+    else
+      expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+  
+  for (jj = 0; jj < rank; jj++)
+    {
+      if (rank && expr_incr[jj])
+	{
+	  if (count_down[0][jj])
+	    compare_expr[jj] = build_x_binary_op
+	      (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	       array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	       tf_warning_or_error);
+	  else
+	    compare_expr[jj] = build_x_binary_op
+	      (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	       array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	       tf_warning_or_error);
+	}
+    }
+
+  an_init = pop_stmt_list (an_init);
+  append_to_statement_list_force (an_init, &loop_with_init);
+  body = stmt;
+
+  for (ii = 0; ii < rank; ii++)
+    {
+      tree new_loop = push_stmt_list ();
+      create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body);
+      body = pop_stmt_list (new_loop);
+    }
+  append_to_statement_list_force (body, &loop_with_init);
+  
+  XDELETEVEC (compare_expr);
+  XDELETEVEC (expr_incr);
+  XDELETEVEC (ind_init);
+  XDELETEVEC (array_var);
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      XDELETEVEC (count_down[ii]);
+      XDELETEVEC (array_value[ii]);
+      XDELETEVEC (array_stride[ii]);
+      XDELETEVEC (array_length[ii]);
+      XDELETEVEC (array_start[ii]);
+      XDELETEVEC (array_ops[ii]);
+      XDELETEVEC (array_vector[ii]);
+    }
+
+  XDELETEVEC (count_down);
+  XDELETEVEC (array_value);
+  XDELETEVEC (array_stride);
+  XDELETEVEC (array_length);
+  XDELETEVEC (array_start);
+  XDELETEVEC (array_ops);
+  XDELETEVEC (array_vector);
+
+  return loop_with_init;
+}
+
+/* Transforms array notations inside unary expression ORIG_STMT with an
+   appropriate loop and ARRAY_REF (and returns all this as a super-tree called
+   LOOP).  */
+
+static tree
+expand_unary_array_notation_exprs (tree orig_stmt)
+{
+  vec<tree, va_gc> *array_list = NULL, *array_operand = NULL;
+  int s_jj = 0;
+  size_t list_size = 0, rank = 0, ii = 0, jj = 0;
+  tree **array_ops, *array_var, jj_tree, body, array_opr;
+  tree **array_value, **array_stride, **array_length, **array_start;
+  tree *compare_expr, *expr_incr, *ind_init;
+  bool **count_down, **array_vector;
+  tree builtin_loop, stmt = NULL_TREE, new_var = NULL_TREE;
+  tree begin_var, lngth_var, strde_var;
+  location_t location = EXPR_LOCATION (orig_stmt);
+  tree an_init, loop_with_init = alloc_stmt_list ();
+  
+  if (!find_rank (location, orig_stmt, orig_stmt, true, &rank))
+    return error_mark_node;
+  if (rank == 0)
+    return orig_stmt;  
+  
+  extract_array_notation_exprs (orig_stmt, false, &array_list);
+  list_size = vec_safe_length (array_list);
+  location = EXPR_LOCATION (orig_stmt);
+  stmt = NULL_TREE;
+  for (ii = 0; ii < list_size; ii++)
+    {
+      tree list_node = (*array_list)[ii];
+      if (TREE_CODE (list_node) == CALL_EXPR
+	  || TREE_CODE (list_node) == AGGR_INIT_EXPR)
+	{
+	  builtin_loop = expand_sec_reduce_builtin (list_node, &new_var);
+	  if (builtin_loop == error_mark_node)
+	    return error_mark_node;
+	  else if (builtin_loop)
+	    {
+	      vec<tree, va_gc> *sub_list = NULL, *new_var_list = NULL;
+	      stmt = alloc_stmt_list ();
+	      append_to_statement_list_force (builtin_loop, &stmt);
+	      vec_safe_push (sub_list, list_node);
+	      vec_safe_push (new_var_list, new_var);
+	      replace_array_notations (&orig_stmt, false, sub_list,
+				       new_var_list);
+	    }
+	}
+    }
+  if (stmt != NULL_TREE)
+    append_to_statement_list_force (finish_expr_stmt (orig_stmt), &stmt);
+  else
+    stmt = orig_stmt;
+  rank = 0;
+  list_size = 0;
+  array_list = NULL;
+  extract_array_notation_exprs (stmt, true, &array_list);
+  list_size = vec_safe_length (array_list);
+
+  if (!find_rank (EXPR_LOCATION (stmt), stmt, stmt, true, &rank))
+    return error_mark_node;
+  if (rank == 0)
+    return stmt;
+  
+  if (list_size == 0)
+    return stmt;
+
+  array_ops = XNEWVEC (tree *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_ops[ii] = XNEWVEC (tree, rank);
+  
+  array_vector = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++)
+    array_vector[ii] = XNEWVEC (bool, rank);
+
+  array_value = XNEWVEC (tree *, list_size);
+  array_stride = XNEWVEC (tree *, list_size);
+  array_length = XNEWVEC (tree *, list_size);
+  array_start = XNEWVEC (tree *, list_size);
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      array_value[ii]  = XNEWVEC (tree, rank);
+      array_stride[ii] = XNEWVEC (tree, rank);
+      array_length[ii] = XNEWVEC (tree, rank);
+      array_start[ii]  = XNEWVEC (tree, rank);
+    }
+
+  compare_expr = XNEWVEC (tree, rank);
+  expr_incr = XNEWVEC (tree, rank);
+  ind_init = XNEWVEC (tree, rank);
+  array_var = XNEWVEC (tree, rank);
+  
+  count_down = XNEWVEC (bool *, list_size);
+  for (ii = 0; ii < list_size; ii++) 
+    count_down[ii] = XNEWVEC (bool,  rank);
+
+    /* Assign the array notation components to variable so that they can satisfy
+     the exec-once rule.  */
+  for (ii = 0; ii < list_size; ii++)
+    {
+      tree array_node = (*array_list)[ii];
+      tree array_begin = ARRAY_NOTATION_START (array_node);
+      tree array_lngth = ARRAY_NOTATION_LENGTH (array_node);
+      tree array_strde = ARRAY_NOTATION_STRIDE (array_node);
+      tsubst_flags_t complain = tf_warning_or_error;
+      if (array_node && TREE_CODE (array_node) == ARRAY_NOTATION_REF)
+	{
+	  if (TREE_CODE (array_begin) != INTEGER_CST)
+	    {
+	      begin_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, begin_var,
+						     NOP_EXPR, array_begin,
+						     complain));
+	      ARRAY_NOTATION_START (array_node) = begin_var;
+	    }
+	  if (TREE_CODE (array_lngth) != INTEGER_CST)
+	    {
+	      lngth_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, lngth_var,
+						     NOP_EXPR, array_lngth,
+						     complain));
+	      ARRAY_NOTATION_LENGTH (array_node) = lngth_var;
+	    }
+	  if (TREE_CODE (array_strde) != INTEGER_CST)
+	    {
+	      strde_var = build_decl (location, VAR_DECL, NULL_TREE,
+				      integer_type_node);
+	      finish_expr_stmt (build_x_modify_expr (location, strde_var,
+						     NOP_EXPR, array_strde,
+						     complain));
+	      ARRAY_NOTATION_STRIDE (array_node) = strde_var;
+	    }
+	}
+    }
+  for (ii = 0; ii < list_size; ii++)
+    {
+      jj = 0;
+      jj_tree = (*array_list)[ii];
+      while (jj_tree)
+	{
+	  if (TREE_CODE (jj_tree) == ARRAY_NOTATION_REF)
+	    {
+	      array_ops[ii][jj] = jj_tree;
+	      jj++;
+	      jj_tree = ARRAY_NOTATION_ARRAY (jj_tree);
+	    }
+	  else if (TREE_CODE (jj_tree) == VAR_DECL
+		   || TREE_CODE (jj_tree) == PARM_DECL)
+	    break;
+	  else
+	    jj_tree = TREE_OPERAND (jj_tree, 0);
+	}
+    }
+  for (ii = 0; ii < list_size; ii++)
+    {
+      if (TREE_CODE ((*array_list)[ii]) == ARRAY_NOTATION_REF)
+	{
+	  for (jj = 0; jj < rank; jj++)
+	    {
+	      if (TREE_CODE (array_ops[ii][jj]) == ARRAY_NOTATION_REF)
+		{
+		  array_value[ii][jj] =
+		    ARRAY_NOTATION_ARRAY (array_ops[ii][jj]);
+		  array_start[ii][jj] =
+		    ARRAY_NOTATION_START (array_ops[ii][jj]);
+		  array_length[ii][jj] =
+		    ARRAY_NOTATION_LENGTH (array_ops[ii][jj]);
+		  array_stride[ii][jj] =
+		    ARRAY_NOTATION_STRIDE (array_ops[ii][jj]);
+		  array_vector[ii][jj] = true;
+
+		  if (!TREE_CONSTANT (array_length[ii][jj])
+		      || TREE_CODE (array_length[ii][jj]) == VAR_DECL)
+		    count_down[ii][jj] = false;
+		  else if (!integer_zerop (array_length[ii][jj])
+		      && !integer_nonzerop (array_length[ii][jj]))
+		      count_down[ii][jj] = false;
+		  else if (tree_int_cst_lt
+			   (array_length[ii][jj],
+			    build_zero_cst (TREE_TYPE (array_length[ii][jj]))))
+		    count_down[ii][jj] = true;
+		  else
+		    count_down[ii][jj] = false;
+		}
+	      else
+		array_vector[ii][jj] = false;
+	    }
+	}
+    }
+
+  an_init = push_stmt_list ();
+  for (ii = 0; ii < rank; ii++)
+    {
+      array_var[ii] = build_decl (location, VAR_DECL, NULL_TREE,
+				  TREE_TYPE (array_start[0][ii]));
+      ind_init[ii] = build_x_modify_expr
+	(location, array_var[ii], NOP_EXPR, 
+	 build_zero_cst (TREE_TYPE (array_var[ii])), tf_warning_or_error);
+    }
+  for (ii = 0; ii < list_size; ii++)
+    {
+      if (array_vector[ii][0])
+	{
+	  array_opr = array_value[ii][rank - 1];
+	  for (s_jj = rank - 1; s_jj >= 0; s_jj--)
+	    {
+	      tree stride = NULL_TREE, var = NULL_TREE, start = NULL_TREE;
+	      if ((TREE_TYPE (array_start[ii][s_jj]) ==
+		   TREE_TYPE (array_stride[ii][s_jj]))
+		  && (TREE_TYPE (array_stride[ii][s_jj]) !=
+		      TREE_TYPE (array_var[s_jj])))
+		{
+		  /* If stride and start are of same type and the induction var
+		     is not, convert induction variable to stride's type.  */
+		  start = array_start[ii][s_jj];
+		  stride = array_stride[ii][s_jj];
+		  var =
+		    build_c_cast (location, TREE_TYPE (array_stride[ii][s_jj]),
+				  array_var[s_jj]);
+		}
+	      else if (TREE_TYPE (array_start[ii][s_jj]) !=
+			TREE_TYPE (array_stride[ii][s_jj]))
+		{
+		  /* If we reach here, then the stride and start are of
+		     different types, and so it doesn't really matter what
+		     the induction variable type is, convert everything to 
+		     integer.  The reason why we pick an integer
+		     instead of something like size_t is because the stride
+		     and length can be + or -.  */
+		  start = build_c_cast (location, integer_type_node,
+					array_start[ii][s_jj]);
+		  stride = build_c_cast (location, integer_type_node,
+					 array_stride[ii][s_jj]);
+		  var = build_c_cast (location, integer_type_node,
+				      array_var[s_jj]);
+		}
+	      else
+		{
+		  start = array_start[ii][s_jj];
+		  stride = array_stride[ii][s_jj];
+		  var = array_var[s_jj];
+		}
+	      if (count_down[ii][s_jj])
+		/* Array[start_index - (induction_var * stride)].  */
+		array_opr = grok_array_decl
+		  (location, array_opr,
+		   build2 (MINUS_EXPR, TREE_TYPE (var), start,
+			   build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		   false);	
+	      else
+		/* Array[start_index + (induction_var * stride)].  */
+		array_opr = grok_array_decl
+		  (location, array_opr,
+		   build2 (PLUS_EXPR, TREE_TYPE (var), start,
+			   build2 (MULT_EXPR, TREE_TYPE (var), var, stride)),
+		   false);
+	    }
+	  vec_safe_push (array_operand, array_opr);  
+	}
+      else
+	vec_safe_push (array_operand, integer_one_node);
+    }
+  replace_array_notations (&stmt, true, array_list, array_operand);
+
+  for (ii = 0; ii < rank; ii++)
+    if (count_down[0][ii])
+      expr_incr[ii] = build_x_unary_op (location, POSTDECREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+    else
+      expr_incr[ii] = build_x_unary_op (location, POSTINCREMENT_EXPR,
+					array_var[ii], tf_warning_or_error);
+
+  for (jj = 0; jj < rank; jj++)
+    {
+      if (rank && expr_incr[jj])
+	{
+	  if (count_down[0][jj])
+	    compare_expr[jj] = build_x_binary_op
+	      (location, GT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	       array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	       tf_warning_or_error);
+	  else
+	    compare_expr[jj] = build_x_binary_op
+	      (location, LT_EXPR, array_var[jj], TREE_CODE (array_var[jj]),
+	       array_length[0][jj], TREE_CODE (array_length[0][jj]), NULL,
+	       tf_warning_or_error);
+	}
+    }
+
+  an_init = pop_stmt_list (an_init);
+  append_to_statement_list_force (an_init, &loop_with_init);
+  body = stmt;
+  
+  for (ii = 0; ii < rank; ii++)
+    {
+      tree new_loop = push_stmt_list ();
+      create_an_loop (ind_init[ii], compare_expr[ii], expr_incr[ii], body);
+      body = pop_stmt_list (new_loop);
+    }
+  append_to_statement_list_force (body, &loop_with_init);
+
+  XDELETEVEC (compare_expr);
+  XDELETEVEC (expr_incr);
+  XDELETEVEC (ind_init);
+  XDELETEVEC (array_var);
+
+  for (ii = 0; ii < list_size; ii++)
+    {
+      XDELETEVEC (count_down[ii]);
+      XDELETEVEC (array_value[ii]);
+      XDELETEVEC (array_stride[ii]);
+      XDELETEVEC (array_length[ii]);
+      XDELETEVEC (array_start[ii]);
+      XDELETEVEC (array_ops[ii]);
+      XDELETEVEC (array_vector[ii]);
+    }
+    
+  XDELETEVEC (count_down);
+  XDELETEVEC (array_value);
+  XDELETEVEC (array_stride);
+  XDELETEVEC (array_length);
+  XDELETEVEC (array_start);
+  XDELETEVEC (array_ops);
+  XDELETEVEC (array_vector);
+
+  return loop_with_init;
+}
+
+/* Expands the array notation's builtin reduction function in EXPR
+   (of type RETURN_EXPR) and returns a STATEMENT_LIST that contains a loop
+   with the builtin function expansion and a return statement at the end.  */
+
+static tree
+expand_return_expr (tree expr)
+{
+  tree new_mod_list, new_var, new_mod, retval_expr;
+  location_t loc = EXPR_LOCATION (expr);
+
+  if (TREE_CODE (expr) != RETURN_EXPR)
+    return expr;
+
+  new_mod_list = alloc_stmt_list ();
+  retval_expr = TREE_OPERAND (expr, 0);
+  new_var = build_decl (loc, VAR_DECL, NULL_TREE, TREE_TYPE (retval_expr));
+  new_mod = expand_an_in_modify_expr (loc, new_var, NOP_EXPR,
+					 TREE_OPERAND (retval_expr, 1),
+					 tf_warning_or_error);
+  TREE_OPERAND (retval_expr, 1) = new_var;
+  TREE_OPERAND (expr, 0) = retval_expr;
+  append_to_statement_list_force (new_mod, &new_mod_list);
+  append_to_statement_list_force (expr, &new_mod_list);
+  return new_mod_list;
+}
+
+/* Expands ARRAY_NOTATION_REF and builtin functions in a compound statement,
+   STMT. Returns the STMT with expanded array notations.  */
+
+tree
+expand_array_notation_exprs (tree t)
+{
+  enum tree_code code;
+  bool is_expr;
+  location_t loc = UNKNOWN_LOCATION;
+  
+  /* Skip empty subtrees.  */
+  if (!t)
+    return t;
+
+  loc = EXPR_LOCATION (t);
+
+  code = TREE_CODE (t); 
+  is_expr = IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code));
+  switch (code)
+    {
+    case ERROR_MARK:
+    case IDENTIFIER_NODE:
+    case INTEGER_CST:
+    case REAL_CST:
+    case FIXED_CST:
+    case STRING_CST:
+    case BLOCK:
+    case PLACEHOLDER_EXPR:
+    case FIELD_DECL:
+    case VOID_TYPE:
+    case REAL_TYPE:
+    case SSA_NAME:
+    case LABEL_DECL:
+    case RESULT_DECL:
+    case VAR_DECL:
+    case PARM_DECL:
+    case NON_LVALUE_EXPR:
+    case NOP_EXPR:
+    case INIT_EXPR:
+    case ADDR_EXPR:
+    case ARRAY_REF:
+    case BIT_FIELD_REF:
+    case VECTOR_CST:
+    case COMPLEX_CST:
+      return t;
+    case MODIFY_EXPR:
+      if (contains_array_notation_expr (t))
+	t = expand_an_in_modify_expr (loc, TREE_OPERAND (t, 0), NOP_EXPR, 
+					 TREE_OPERAND (t, 1), 
+					 tf_warning_or_error);
+      return t;
+    case MODOP_EXPR:
+      if (contains_array_notation_expr (t) && !processing_template_decl)
+	t = expand_an_in_modify_expr
+	  (loc, TREE_OPERAND (t, 0), TREE_CODE (TREE_OPERAND (t, 1)),
+	   TREE_OPERAND (t, 2), tf_warning_or_error);
+      return t;
+    case CONSTRUCTOR:
+      return t;
+    case BIND_EXPR:
+      {
+	BIND_EXPR_BODY (t) =
+	  expand_array_notation_exprs  (BIND_EXPR_BODY (t));
+	return t;
+      }
+    case DECL_EXPR:
+      {
+	tree x = DECL_EXPR_DECL (t);
+	if (t && TREE_CODE (x) != FUNCTION_DECL)
+	  if (DECL_INITIAL (x))
+	    t = expand_unary_array_notation_exprs (t);
+      return t;
+      }
+    case STATEMENT_LIST:
+      {
+	tree_stmt_iterator i;
+	for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
+	  *tsi_stmt_ptr (i) =
+	    expand_array_notation_exprs (*tsi_stmt_ptr (i));
+	return t;
+      }
+
+    case OMP_PARALLEL:
+    case OMP_TASK:
+    case OMP_FOR:
+    case OMP_SINGLE:
+    case OMP_SECTION:
+    case OMP_SECTIONS:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_CRITICAL:
+    case OMP_ATOMIC:
+    case OMP_CLAUSE:
+    case TARGET_EXPR:
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case POINTER_TYPE:
+    case ARRAY_TYPE:
+    case RECORD_TYPE:
+    case METHOD_TYPE:
+      return t;
+    case RETURN_EXPR:
+      if (contains_array_notation_expr (t))
+	t = expand_return_expr (t);
+      return t;
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case AGGR_INIT_EXPR:
+    case CALL_EXPR:
+      t = expand_unary_array_notation_exprs (t);
+      return t;
+    case CONVERT_EXPR:
+    case CLEANUP_POINT_EXPR:
+    case EXPR_STMT:
+      TREE_OPERAND (t, 0) = expand_array_notation_exprs (TREE_OPERAND (t, 0));
+      /* It is not necessary to wrap error_mark_node in EXPR_STMT.  */
+      if (TREE_OPERAND (t, 0) == error_mark_node)
+	return TREE_OPERAND (t, 0); 
+      return t;
+    case COND_EXPR:
+      t = cp_expand_cond_array_notations (t);
+      if (TREE_CODE (t) == COND_EXPR)
+	{
+	  COND_EXPR_THEN (t) =
+	    expand_array_notation_exprs (COND_EXPR_THEN (t));
+	  COND_EXPR_ELSE (t) =
+	    expand_array_notation_exprs (COND_EXPR_ELSE (t));
+	}
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+
+    case SWITCH_EXPR:
+      t = cp_expand_cond_array_notations (t);
+      if (TREE_CODE (t) == SWITCH_EXPR)
+	SWITCH_BODY (t) = expand_array_notation_exprs (SWITCH_BODY (t));
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+      
+    case FOR_STMT:
+      
+      /* FIXME: Add a check for CILK_FOR_STMT here when we add Cilk tasking 
+	 keywords.  */
+      if (TREE_CODE (t) == FOR_STMT)
+	FOR_BODY (t) = expand_array_notation_exprs (FOR_BODY (t));
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+
+    case IF_STMT:
+      t = cp_expand_cond_array_notations (t);
+      /* If the above function added some extra instructions above the original
+	 if statement, then we can't assume it is still IF_STMT so we have to
+	 check again.  */
+      if (TREE_CODE (t) == IF_STMT)
+	{
+	  if (THEN_CLAUSE (t))
+	    THEN_CLAUSE (t) = expand_array_notation_exprs (THEN_CLAUSE (t));
+	  if (ELSE_CLAUSE (t))
+	    ELSE_CLAUSE (t) = expand_array_notation_exprs (ELSE_CLAUSE (t));
+	}
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+
+    case SWITCH_STMT:
+      t = cp_expand_cond_array_notations (t);
+      /* If the above function added some extra instructions above the original
+	 switch statement, then we can't assume it is still SWITCH_STMT so we
+	 have to check again.  */
+      if (TREE_CODE (t) == SWITCH_STMT)
+	{
+	  if (SWITCH_STMT_BODY (t))
+	    SWITCH_STMT_BODY (t) =
+	      expand_array_notation_exprs (SWITCH_STMT_BODY (t));
+	}
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+
+    case WHILE_STMT:
+      t = cp_expand_cond_array_notations (t);
+      /* If the above function added some extra instructions above the original
+	 while statement, then we can't assume it is still WHILE_STMTso we
+	 have to check again.  */
+      if (TREE_CODE (t) == WHILE_STMT)
+	{
+	  if (WHILE_BODY (t))
+	    WHILE_BODY (t) = expand_array_notation_exprs (WHILE_BODY (t));
+	}
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+      
+    case DO_STMT:
+      t = cp_expand_cond_array_notations (t);
+      /* If the above function added some extra instructions above the original
+	 do-while statement, then we can't assume it is still DO_STMT so we
+	 have to check again.  */
+      if (TREE_CODE (t) == DO_STMT)
+	{      
+	  if (DO_BODY (t))
+	    DO_BODY (t) = expand_array_notation_exprs (DO_BODY (t));
+	}
+      else
+	t = expand_array_notation_exprs (t);
+      return t;
+      
+    default:
+      if (is_expr)
+	{
+	  int i, len;
+
+	  /* Walk over all the sub-trees of this operand.  */
+	  len = TREE_CODE_LENGTH (code);
+
+	  /* Go through the subtrees.  We need to do this in forward order so
+	     that the scope of a FOR_EXPR is handled properly.  */
+	  for (i = 0; i < len; ++i)
+	    TREE_OPERAND (t, i) =
+	      expand_array_notation_exprs (TREE_OPERAND (t, i));
+	}
+      return t;
+    }
+  return t;
+}
+
+/* Given the base of an array (ARRAY), the START_INDEX, the number of elements
+   to be accessed (LENGTH) and the STRIDE, construct an ARRAY_NOTATION_REF tree
+   of type TYPE and return it.  Restrictions on START_INDEX, LENGTH and STRIDE 
+   are the same as that of index field passed into ARRAY_REF.  The only
+   additional restriction is that, unlike index in ARRAY_REF, stride, length
+   and start_index cannot contain array notations.  */
+
+tree
+build_array_notation_ref (location_t loc, tree array, tree start_index,
+			  tree length, tree stride, tree type)
+{
+  tree array_ntn_expr = NULL_TREE;
+  
+  /* When dealing with templates, do the type checking at a later time.  */
+  if (processing_template_decl || !type)
+    {
+      if (!type && TREE_TYPE (array))
+	type = TREE_TYPE (array);
+      array_ntn_expr = build_min_nt_loc (loc, ARRAY_NOTATION_REF, array,
+					 start_index, length, stride, type,
+					 NULL_TREE);
+      TREE_TYPE (array_ntn_expr) = type;
+    }
+  if (!stride)
+    {
+      if (TREE_CONSTANT (start_index) && TREE_CONSTANT (length)
+	  && TREE_CODE (start_index) != VAR_DECL
+	  && TREE_CODE (length) != VAR_DECL
+	  && tree_int_cst_lt (length, start_index))
+	stride = build_int_cst (TREE_TYPE (start_index), -1);
+      else
+	stride = build_int_cst (TREE_TYPE (start_index), 1);
+    }
+
+  if (!cilkplus_an_triplet_types_ok_p (loc, start_index, length, stride, type))
+    return error_mark_node;
+
+  if (!processing_template_decl)
+    {
+      array_ntn_expr = build4 (ARRAY_NOTATION_REF, NULL_TREE, NULL_TREE,
+			       NULL_TREE, NULL_TREE, NULL_TREE);
+      ARRAY_NOTATION_ARRAY (array_ntn_expr) = array;
+      ARRAY_NOTATION_START (array_ntn_expr) = start_index;
+      ARRAY_NOTATION_LENGTH (array_ntn_expr) = length;
+      ARRAY_NOTATION_STRIDE (array_ntn_expr) = stride;
+      if (type && (TREE_CODE (type) == ARRAY_TYPE
+		   || TREE_CODE (type) == POINTER_TYPE))
+	TREE_TYPE (array_ntn_expr) = TREE_TYPE (type);
+      else
+	TREE_TYPE (array_ntn_expr) = type;
+    }
+  SET_EXPR_LOCATION (array_ntn_expr, loc);
+
+  return array_ntn_expr;
+}
+
+
+/* Returns false if any of the Array notation triplet values: START_INDEX,
+   LENGTH and STRIDE, are not of integral type and have a rank greater than
+   zero.  */
+
+bool
+cilkplus_an_triplet_types_ok_p (location_t loc, tree start_index, tree length,
+				tree stride, tree type)
+{
+  size_t stride_rank = 0, length_rank = 0, start_rank = 0;
+  if (!TREE_TYPE (start_index) || !INTEGRAL_TYPE_P (TREE_TYPE (start_index)))
+    {
+      error_at (loc, "start-index of array notation triplet is not an integer");
+      return false;
+    }
+  if (!TREE_TYPE (length) || !INTEGRAL_TYPE_P (TREE_TYPE (length)))
+    {
+      error_at (loc, "length of array notation triplet is not an integer");
+      return false;
+    }
+  if (!TREE_TYPE (stride) || !INTEGRAL_TYPE_P (TREE_TYPE (stride)))
+    {
+      error_at (loc, "stride of array notation triplet is not an integer");
+      return false;
+    }
+  if (!TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      error_at (loc, "array notations cannot be used with function type");
+      return false;
+    }
+
+  while (type && (TREE_CODE (type) == POINTER_TYPE
+		  || TREE_CODE (type) == ARRAY_TYPE))
+    {
+      type = TREE_TYPE (type);
+      if (type && TREE_CODE (type) == FUNCTION_TYPE)
+	{
+	  error_at (loc, "array notations cannot be used with function pointer"
+		    " arrays");
+	  return false;
+	}
+    }
+  if (!find_rank (loc, start_index, start_index, false, &start_rank)
+      || !find_rank (loc, length, length, false, &length_rank)
+      || !find_rank (loc, stride, stride, false, &stride_rank))
+    return false;
+
+  if (start_rank != 0)
+    {
+      error_at (loc, "rank of an array notation triplet%'s start-index is not "
+		"zero");
+      return false;
+    }
+  if (length_rank != 0)
+    {
+      error_at (loc, "rank of an array notation triplet%'s length is not zero");
+      return false;
+    }
+  if (stride_rank != 0)
+    {
+      error_at (loc, "rank of array notation triplet%'s stride is not zero");
+      return false;
+    }
+  return true;
+}
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index bccd884..d301db0 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -321,6 +321,7 @@  cp_common_init_ts (void)
   MARK_TS_TYPED (USING_STMT);
   MARK_TS_TYPED (LAMBDA_EXPR);
   MARK_TS_TYPED (CTOR_INITIALIZER);
+  MARK_TS_TYPED (ARRAY_NOTATION_REF);
 }
 
 #include "gt-cp-cp-objcp-common.h"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 9421822..4791a32 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6135,6 +6135,10 @@  extern bool cxx_omp_privatize_by_reference	(const_tree);
 extern void suggest_alternatives_for            (location_t, tree);
 extern tree strip_using_decl                    (tree);
 
+/* In cp/cp-array-notations.c */
+extern tree expand_array_notation_exprs         (tree);
+bool cilkplus_an_triplet_types_ok_p             (location_t, tree, tree, tree,
+						 tree);
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
old mode 100644
new mode 100755
index a75fc4e..a8f52cd
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1071,6 +1071,17 @@  dump_decl (tree t, int flags)
       pp_cxx_right_bracket (cxx_pp);
       break;
 
+    case ARRAY_NOTATION_REF:
+      dump_decl (ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS);
+      pp_cxx_left_bracket (cxx_pp);
+      dump_decl (ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS);
+      pp_string (cxx_pp, ":");
+      dump_decl (ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS);
+      pp_string (cxx_pp, ":");
+      dump_decl (ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS);
+      pp_cxx_right_bracket (cxx_pp);
+      break;
+
       /* So that we can do dump_decl on an aggr type.  */
     case RECORD_TYPE:
     case UNION_TYPE:
@@ -2057,6 +2068,17 @@  dump_expr (tree t, int flags)
       pp_cxx_right_bracket (cxx_pp);
       break;
 
+    case ARRAY_NOTATION_REF:
+      dump_expr (ARRAY_NOTATION_ARRAY (t), flags | TFF_EXPR_IN_PARENS);
+      pp_cxx_left_bracket (cxx_pp);
+      dump_expr (ARRAY_NOTATION_START (t), flags | TFF_EXPR_IN_PARENS);
+      pp_string (cxx_pp, ":");
+      dump_expr (ARRAY_NOTATION_LENGTH (t), flags | TFF_EXPR_IN_PARENS);
+      pp_string (cxx_pp, ":");
+      dump_expr (ARRAY_NOTATION_STRIDE (t), flags | TFF_EXPR_IN_PARENS);
+      pp_cxx_right_bracket (cxx_pp);
+      break;
+
     case UNARY_PLUS_EXPR:
       dump_unary_op ("+", t, flags);
       break;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
old mode 100644
new mode 100755
index a581e88..523dcf7
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6060,6 +6060,168 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
   return error_mark_node;
 }
 
+/* This function parses Cilk Plus array notations.  The starting index is
+   passed in INIT_INDEX and the array name is passed in ARRAY_VALUE.  The 
+   return value of this function is a tree node called VALUE_TREE of type
+   ARRAY_NOTATION_REF.  If some error occurred it returns error_mark_node.  */
+
+static tree
+cp_parser_array_notation (location_t loc, cp_parser *parser, tree init_index,
+			  tree array_value)
+{
+  cp_token *token = NULL;
+  tree start_index = NULL_TREE, length_index = NULL_TREE, stride = NULL_TREE;
+  tree value_tree, type, array_type, array_type_domain;
+  double_int x; 
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+
+  if (!array_value || array_value == error_mark_node)
+    {
+      cp_parser_skip_to_end_of_statement (parser);
+      return error_mark_node;
+    }
+  
+  if (processing_template_decl)
+    {
+      array_type = TREE_TYPE (array_value);
+      type = TREE_TYPE (array_type);
+    }
+  else
+    {
+      array_type = TREE_TYPE (array_value);
+      gcc_assert (array_type);
+      type = array_type;
+    }
+  token = cp_lexer_peek_token (parser->lexer);
+  if (!token)
+    {
+      cp_parser_error (parser, "expected %<:%> or numeral");
+      return error_mark_node;
+    }
+  else if (token->type == CPP_COLON)
+    {
+      if (!init_index)
+	{
+	  /* If we are here, then we have a case like this A[:].  */
+	  cp_lexer_consume_token (parser->lexer);
+
+	  if (cp_lexer_peek_token (parser->lexer)->type != CPP_CLOSE_SQUARE)
+	    {
+	      cp_parser_error (parser, "expected %<]%>");
+	      cp_parser_skip_to_end_of_statement (parser);
+	      return error_mark_node;
+	    }
+	  if (TREE_CODE (array_type) == RECORD_TYPE
+	      || TREE_CODE (array_type) == POINTER_TYPE)
+	    {
+	      error_at (loc, "start-index and length fields necessary for "
+			"using array notations in pointers or records");
+	      cp_parser_skip_to_end_of_statement (parser);
+	      return error_mark_node;
+	    }
+	  if (TREE_CODE (array_type) == ARRAY_TYPE)
+	    {
+	      tree subtype = TREE_TYPE (array_type);
+	      while (subtype && TREE_CODE (subtype) == POINTER_TYPE)
+		{
+		  /* This could be a function ptr.  If so, then emit error.  */
+		  subtype = TREE_TYPE (subtype);
+		  if (subtype && TREE_CODE (subtype) == FUNCTION_TYPE)
+		    {
+		      error_at (loc, "array notations cannot be used with"
+				" function pointer arrays");
+		      cp_parser_skip_to_end_of_statement (parser);
+		      return error_mark_node;
+		    }
+		}
+	    }
+	  array_type_domain = TYPE_DOMAIN (array_type);
+	  if (!array_type_domain)
+	    {
+	      error_at (loc, "start-index and length fields necessary for "
+			"using array notations in dimensionless arrays");
+	      cp_parser_skip_to_end_of_statement (parser);
+	      return error_mark_node;
+	    }
+	  start_index = TYPE_MINVAL (array_type_domain);
+	  start_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node,
+				     start_index);
+	  x = TREE_INT_CST (TYPE_MAXVAL (array_type_domain));
+	  x.low++;
+	  length_index = double_int_to_tree (integer_type_node, x);
+	  length_index = fold_build1 (CONVERT_EXPR, ptrdiff_type_node,
+				      length_index);
+	  stride = build_int_cst (integer_type_node, 1);
+	  stride = fold_build1 (CONVERT_EXPR, ptrdiff_type_node, stride);
+	}
+      else if (init_index != error_mark_node)
+	{
+	  /* If we hare here, then there are 2 possibilities:
+	     1. Array [ EXPR : EXPR ]
+	     2. Array [ EXPR : EXPR : EXPR ]
+	  */
+	  start_index = init_index;
+	  cp_lexer_consume_token (parser->lexer);
+
+	  saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+	   /* The ':' is used in array notation.  Thus compiler cannot do scope 
+	      correction automatically.  */
+	  parser->colon_corrects_to_scope_p = false;
+	  length_index = cp_parser_expression (parser, false, NULL);
+	  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+	  if (!length_index || length_index == error_mark_node)
+	    cp_parser_skip_to_end_of_statement (parser);
+	 
+	  if (cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
+	    {
+	      cp_lexer_consume_token (parser->lexer);
+	      saved_colon_corrects_to_scope_p = 
+		parser->colon_corrects_to_scope_p;
+	      /* Disable correcting single colon correcting to scope.  */
+	      parser->colon_corrects_to_scope_p = false;
+	      stride = cp_parser_expression (parser, false, NULL);
+	      parser->colon_corrects_to_scope_p = 
+		saved_colon_corrects_to_scope_p;
+	      if (!stride || stride == error_mark_node)
+		{
+		  cp_parser_skip_to_end_of_statement (parser);
+		  if (cp_lexer_peek_token (parser->lexer)->type
+		      == CPP_CLOSE_SQUARE)
+		    cp_lexer_consume_token (parser->lexer);
+		}
+	    }
+	  else
+	    stride = build_one_cst (integer_type_node);
+	}
+      else
+	{
+	  cp_parser_skip_to_end_of_statement (parser);
+	  return error_mark_node;
+	}
+    }
+  
+  if (start_index == error_mark_node || length_index == error_mark_node
+      || stride == error_mark_node || !start_index || !length_index
+      || !stride)
+    {
+      if (cp_lexer_peek_token (parser->lexer)->type == CPP_CLOSE_SQUARE)
+	cp_lexer_consume_token (parser->lexer);
+      return error_mark_node;
+    }
+  cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
+  
+  /* We fold all 3 of the values to make things easier when we transform
+     them later.  */
+  start_index = fold (start_index);
+  length_index = fold (length_index);
+  stride = fold (stride);
+
+  value_tree = build_array_notation_ref (input_location, array_value,
+					 start_index, length_index, stride,
+					 type);
+  return value_tree;
+}
+
 /* A subroutine of cp_parser_postfix_expression that also gets hijacked
    by cp_parser_builtin_offsetof.  We're looking for
 
@@ -6081,41 +6243,78 @@  cp_parser_postfix_open_square_expression (cp_parser *parser,
   /* Consume the `[' token.  */
   cp_lexer_consume_token (parser->lexer);
 
-  /* Parse the index expression.  */
-  /* ??? For offsetof, there is a question of what to allow here.  If
-     offsetof is not being used in an integral constant expression context,
-     then we *could* get the right answer by computing the value at runtime.
-     If we are in an integral constant expression context, then we might
-     could accept any constant expression; hard to say without analysis.
-     Rather than open the barn door too wide right away, allow only integer
-     constant expressions here.  */
-  if (for_offsetof)
-    index = cp_parser_constant_expression (parser, false, NULL);
+  if (flag_enable_cilkplus
+      && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
+    /* If we are here, then we have something like this:
+       ARRAY[:]
+    */
+    postfix_expression = cp_parser_array_notation (loc, parser, NULL_TREE,
+						   postfix_expression);
   else
     {
-      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+      /* Here are have these options:
+	 1. ARRAY[EXPR]               -- This is the normal array call.
+	 2. ARRAY[EXPR : EXPR]        -- Array notation expr with default stride
+	 of 1.
+	 3. ARRAY[EXPR : EXPR : EXPR] -- Array Notation with userdefined stride.
+	 4. Array[Braced List]        -- This is handled by braced list.
+      */
+      
+      /* Parse the index expression.  */
+      /* ??? For offsetof, there is a question of what to allow here.  If
+	 offsetof is not being used in an integral constant expression context,
+	 then we *could* get the right answer by computing the value at runtime.
+	 If we are in an integral constant expression context, then we might
+	 could accept any constant expression; hard to say without analysis.
+	 Rather than open the barn door too wide right away, allow only integer
+	 constant expressions here.  */
+      if (for_offsetof)
+	index = cp_parser_constant_expression (parser, false, NULL);
+      else
 	{
-	  bool expr_nonconst_p;
-	  maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
-	  index = cp_parser_braced_list (parser, &expr_nonconst_p);
+	  bool saved_colon_corrects_to_scope_p = 
+	    parser->colon_corrects_to_scope_p;
+	  if (flag_enable_cilkplus)
+	    parser->colon_corrects_to_scope_p = false;
+	  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+	    {
+	      bool expr_nonconst_p;
+	      maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
+	      index = cp_parser_braced_list (parser, &expr_nonconst_p);
+	      if (flag_enable_cilkplus
+		  && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
+		{
+		  error_at (cp_lexer_peek_token (parser->lexer)->location,
+			    "braced list index is not allowed with array "
+			    "notations");
+		  index = error_mark_node;
+		}
+	    }
+	  else
+	    index = cp_parser_expression (parser, /*cast_p=*/false, NULL);
+	  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
 	}
+      if (flag_enable_cilkplus
+	  && cp_lexer_peek_token (parser->lexer)->type == CPP_COLON)
+	postfix_expression = cp_parser_array_notation (loc, parser, index,
+						       postfix_expression);
       else
-	index = cp_parser_expression (parser, /*cast_p=*/false, NULL);
-    }
-
-  /* Look for the closing `]'.  */
-  cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
-
-  /* Build the ARRAY_REF.  */
-  postfix_expression = grok_array_decl (loc, postfix_expression,
-					index, decltype_p);
+	{
+  	  /* Look for the closing `]'.  */
+	  cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE);
 
-  /* When not doing offsetof, array references are not permitted in
-     constant-expressions.  */
-  if (!for_offsetof
-      && (cp_parser_non_integral_constant_expression (parser, NIC_ARRAY_REF)))
-    postfix_expression = error_mark_node;
+	  /* Build the ARRAY_REF.  */
+	  postfix_expression = grok_array_decl (loc, postfix_expression,
+						index, decltype_p);
 
+	  /* When not doing offsetof, array references are not permitted in
+	     constant-expressions.  */
+	  if (!for_offsetof
+	      && (cp_parser_non_integral_constant_expression (parser,
+							      NIC_ARRAY_REF)))
+	    postfix_expression = error_mark_node;
+	}
+    }
   return postfix_expression;
 }
 
@@ -9342,6 +9541,8 @@  cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
   /* Consume the `}'.  */
   cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
 
+  if (flag_enable_cilkplus && contains_array_notation_expr (compound_stmt))
+    compound_stmt = expand_array_notation_exprs (compound_stmt);
   return compound_stmt;
 }
 
@@ -9534,6 +9735,14 @@  cp_parser_selection_statement (cp_parser* parser, bool *if_p)
 
 	    /* Now we're all done with the switch-statement.  */
 	    finish_switch_stmt (statement);
+	    if (flag_enable_cilkplus
+		&& contains_array_notation_expr (condition))
+	      {
+		error_at (EXPR_LOCATION (condition),
+			  "array notations cannot be used as a condition for "
+			  "switch statement");
+		statement = error_mark_node;
+	      }      
 	  }
 
 	return statement;
@@ -10094,6 +10303,12 @@  cp_parser_iteration_statement (cp_parser* parser)
 	parser->in_statement = in_statement;
 	/* We're done with the while-statement.  */
 	finish_while_stmt (statement);
+	if (flag_enable_cilkplus && contains_array_notation_expr (condition))
+	  {
+	    error_at (EXPR_LOCATION (condition), "array notations cannot be "
+		      "used as a condition for while statement");
+	    statement = error_mark_node;
+	  }
       }
       break;
 
@@ -10120,6 +10335,15 @@  cp_parser_iteration_statement (cp_parser* parser)
 	cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
 	/* Look for the `;'.  */
 	cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+	if (flag_enable_cilkplus
+	    && contains_array_notation_expr (DO_COND (statement)))
+	  {
+	    error_at (EXPR_LOCATION (DO_COND (statement)),
+		      "array notations cannot be used as a condition for a "
+		      "do-while statement");
+	    statement = error_mark_node;
+	  }
+
       }
       break;
 
@@ -10138,8 +10362,17 @@  cp_parser_iteration_statement (cp_parser* parser)
 	cp_parser_already_scoped_statement (parser);
 	parser->in_statement = in_statement;
 
-	/* We're done with the for-statement.  */
-	finish_for_stmt (statement);
+	if (flag_enable_cilkplus
+	    && contains_array_notation_expr (FOR_COND (statement)))
+	  {
+	    error_at (EXPR_LOCATION (FOR_COND (statement)),
+		      "array notations cannot be used in a condition for a "
+		      "for-loop");
+	    statement = error_mark_node;
+	  }
+	else
+	  /* We're done with the for-statement.  */
+	  finish_for_stmt (statement);
       }
       break;
 
@@ -16714,30 +16947,53 @@  cp_parser_direct_declarator (cp_parser* parser,
 	    {
 	      bool non_constant_p;
 
-	      bounds
-		= cp_parser_constant_expression (parser,
-						 /*allow_non_constant=*/true,
-						 &non_constant_p);
-	      if (!non_constant_p)
-		/* OK */;
-	      else if (error_operand_p (bounds))
-		/* Already gave an error.  */;
-	      else if (!parser->in_function_body
-		       || current_binding_level->kind == sk_function_parms)
+	      if (flag_enable_cilkplus
+		  && cp_lexer_next_token_is (parser->lexer, CPP_COLON))
 		{
-		  /* Normally, the array bound must be an integral constant
-		     expression.  However, as an extension, we allow VLAs
-		     in function scopes as long as they aren't part of a
-		     parameter declaration.  */
-		  cp_parser_error (parser,
-				   "array bound is not an integer constant");
 		  bounds = error_mark_node;
+		  error_at (cp_lexer_peek_token (parser->lexer)->location,
+			    "array notations cannot be used in declaration");
+		  cp_lexer_consume_token (parser->lexer);
 		}
-	      else if (processing_template_decl)
+	      else
 		{
-		  /* Remember this wasn't a constant-expression.  */
-		  bounds = build_nop (TREE_TYPE (bounds), bounds);
-		  TREE_SIDE_EFFECTS (bounds) = 1;
+		  bounds
+		    = cp_parser_constant_expression (parser,
+						     /*allow_non_constant=*/true,
+						     &non_constant_p);
+		  if (!non_constant_p)
+		    /* OK */;
+		  else if (error_operand_p (bounds))
+		    /* Already gave an error.  */;
+		  else if (!parser->in_function_body
+			   || current_binding_level->kind == sk_function_parms)
+		    {
+		      /* Normally, the array bound must be an integral constant
+			 expression.  However, as an extension, we allow VLAs
+			 in function scopes as long as they aren't part of a
+			 parameter declaration.  */
+		      cp_parser_error (parser,
+				       "array bound is not an integer constant");
+		      bounds = error_mark_node;
+		    }
+		  else if (processing_template_decl)
+		    {
+		      /* Remember this wasn't a constant-expression.  */
+		      bounds = build_nop (TREE_TYPE (bounds), bounds);
+		      TREE_SIDE_EFFECTS (bounds) = 1;
+		    }
+		  if (flag_enable_cilkplus
+		      && cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+		    {
+		      location_t loc =
+			cp_lexer_peek_token (parser->lexer)->location;
+		      while (cp_lexer_next_token_is_not (parser->lexer,
+							 CPP_CLOSE_SQUARE))
+			cp_lexer_consume_token (parser->lexer);
+		      error_at (loc, "array notations cannot be used in "
+			 	"declaration");
+		      bounds = error_mark_node; 
+		    }
 		}
 	    }
 	  else
@@ -18108,6 +18364,11 @@  cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser,
   cp_parser_function_body (parser, in_function_try_block);
   if (check_body_p)
     check_constexpr_ctor_body (last, list);
+
+  /* Transform all array notations to the equivalent array refs and loop.  */
+  if (flag_enable_cilkplus && contains_array_notation_expr (body))
+    body = expand_array_notation_exprs (body);
+  
   /* Finish the function body.  */
   finish_function_body (body);
 
@@ -22087,6 +22348,12 @@  cp_parser_function_definition_after_declarator (cp_parser* parser,
 
   finish_lambda_scope ();
 
+  /* Expand all array notation expressions here.  */
+  if (flag_enable_cilkplus && current_function_decl
+      && contains_array_notation_expr (DECL_SAVED_TREE (current_function_decl)))
+    DECL_SAVED_TREE (current_function_decl) =
+      expand_array_notation_exprs (DECL_SAVED_TREE (current_function_decl));
+  
   /* Finish the function.  */
   fn = finish_function ((ctor_initializer_p ? 1 : 0) |
 			(inline_p ? 2 : 0));
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
old mode 100644
new mode 100755
index 3602fcd..0a7d523
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13740,6 +13740,20 @@  tsubst_copy_and_build (tree t,
 				 RECUR (TREE_OPERAND (t, 1)),
 				 complain|decltype_flag));
 
+    case ARRAY_NOTATION_REF:
+      {
+	tree start_index, length, stride;
+	op1 = tsubst_non_call_postfix_expression (ARRAY_NOTATION_ARRAY (t),
+						  args, complain, in_decl);
+	start_index = RECUR (ARRAY_NOTATION_START (t));
+	length = RECUR (ARRAY_NOTATION_LENGTH (t));
+	stride = RECUR (ARRAY_NOTATION_STRIDE (t));
+	if (!cilkplus_an_triplet_types_ok_p (loc, start_index, length, stride,
+					     TREE_TYPE (op1)))
+	  RETURN (error_mark_node);
+	RETURN (build_array_notation_ref (EXPR_LOCATION (t), op1, start_index,
+					  length, stride, TREE_TYPE (op1)));
+      }
     case SIZEOF_EXPR:
       if (PACK_EXPANSION_P (TREE_OPERAND (t, 0)))
 	RETURN (tsubst_copy (t, args, complain, in_decl));
@@ -15712,6 +15726,9 @@  type_unification_real (tree tparms,
       arg = args[ia];
       ++ia;
 
+      if (flag_enable_cilkplus && TREE_CODE (arg) == ARRAY_NOTATION_REF)
+	return 1;
+
       if (unify_one_argument (tparms, targs, parm, arg, subr, strict,
 			      flags, explain_p))
 	return 1;
@@ -19119,6 +19136,11 @@  instantiate_decl (tree d, int defer_ok,
       pointer_map_destroy (local_specializations);
       local_specializations = saved_local_specializations;
 
+      /* We expand all the array notation expressions here.  */
+      if (flag_enable_cilkplus
+	  && contains_array_notation_expr (DECL_SAVED_TREE (d)))
+	DECL_SAVED_TREE (d) = expand_array_notation_exprs (DECL_SAVED_TREE (d));
+      
       /* Finish the function.  */
       d = finish_function (0);
       expand_or_defer_fn (d);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b5c3b0a..656962b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -779,6 +779,22 @@  finish_return_stmt (tree expr)
   tree r;
   bool no_warning;
 
+  if (flag_enable_cilkplus && contains_array_notation_expr (expr))
+    {
+      size_t rank = 0;
+      
+      if (!find_rank (input_location, expr, expr, false, &rank))
+	return error_mark_node;
+
+      /* If the return expression contains array notatinos, then flag it as
+	 error.  */
+      if (rank >= 1)
+	{
+	  error_at (input_location, "array notation expression cannot be "
+		    "used as a return value");
+	  return error_mark_node;
+	}
+    }
   expr = check_return_expr (expr, &no_warning);
 
   if (flag_openmp && !check_omp_return ())
@@ -8066,6 +8082,7 @@  cxx_eval_constant_expression (const constexpr_call *call, tree t,
 				       non_constant_p, overflow_p);
       break;
 
+    case ARRAY_NOTATION_REF:
     case ARRAY_REF:
       r = cxx_eval_array_reference (call, t, allow_non_constant, addr,
 				    non_constant_p, overflow_p);
@@ -8877,6 +8894,7 @@  potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags)
       want_rval = true;
       /* Fall through.  */
     case ARRAY_REF:
+    case ARRAY_NOTATION_REF:
     case ARRAY_RANGE_REF:
     case MEMBER_REF:
     case DOTSTAR_EXPR:
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 8524f6c..dd2fda4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -141,6 +141,7 @@  lvalue_kind (const_tree ref)
     case INDIRECT_REF:
     case ARROW_EXPR:
     case ARRAY_REF:
+    case ARRAY_NOTATION_REF:
     case PARM_DECL:
     case RESULT_DECL:
       return clk_ordinary;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
old mode 100644
new mode 100755
index 11ac85b..17f19c7
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3005,6 +3005,22 @@  cp_build_array_ref (location_t loc, tree array, tree idx,
       return error_mark_node;
     }
 
+  /* If an array's index is an array notation, then its rank cannot be
+     greater than one.  */ 
+  if (flag_enable_cilkplus && contains_array_notation_expr (idx))
+    {
+      size_t rank = 0;
+
+      /* If find_rank returns false,  then it should have reported an error,
+	 thus it is unnecessary for repetition.  */
+      if (!find_rank (loc, idx, idx, true, &rank))
+	return error_mark_node;
+      if (rank > 1)
+	{
+	  error_at (loc, "rank of the array%'s index is greater than 1");
+	  return error_mark_node;
+	}
+    }
   if (TREE_TYPE (array) == error_mark_node
       || TREE_TYPE (idx) == error_mark_node)
     return error_mark_node;
@@ -3477,8 +3493,12 @@  cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
       params = &allocated;
     }
 
-  nargs = convert_arguments (parm_types, params, fndecl, LOOKUP_NORMAL,
-			     complain);
+  if (flag_enable_cilkplus
+      && is_cilkplus_reduce_builtin (fndecl) != BUILT_IN_NONE)
+    nargs = (*params)->length ();
+  else
+    nargs = convert_arguments (parm_types, params, fndecl, LOOKUP_NORMAL,
+			       complain);
   if (nargs < 0)
     return error_mark_node;
 
@@ -3936,8 +3956,15 @@  cp_build_binary_op (location_t location,
 	}
     }
 
-  type0 = TREE_TYPE (op0);
-  type1 = TREE_TYPE (op1);
+  if (flag_enable_cilkplus && contains_array_notation_expr (op0))
+    type0 = find_correct_array_notation_type (op0);
+  else
+    type0 = TREE_TYPE (op0);
+
+  if (flag_enable_cilkplus && contains_array_notation_expr (op1))
+    type1 = find_correct_array_notation_type (op1);
+  else
+    type1 = TREE_TYPE (op1);
 
   /* The expression codes of the data types of the arguments tell us
      whether the arguments are integers, floating, pointers, etc.  */
@@ -5140,6 +5167,13 @@  cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
 
   gcc_assert (!identifier_p (arg) || !IDENTIFIER_OPNAME_P (arg));
 
+  if (flag_enable_cilkplus && TREE_CODE (arg) == ARRAY_NOTATION_REF)
+    {
+      val = build_address (arg);
+      if (TREE_CODE (arg) == OFFSET_REF)
+	PTRMEM_OK_P (val) = PTRMEM_OK_P (arg);
+      return val;
+    }
   if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
       && !really_overloaded_fn (TREE_OPERAND (arg, 1)))
     {
@@ -7818,6 +7852,13 @@  convert_for_assignment (tree type, tree rhs,
   tree rhstype;
   enum tree_code coder;
 
+  /* If we are dealing with built-in array notation function then we don't need
+     to convert them. They will be broken up into modify exprs in future,
+     during which all these checks will be done.  */
+  if (flag_enable_cilkplus
+      && is_cilkplus_reduce_builtin (fndecl) != BUILT_IN_NONE)
+    return rhs;
+  
   /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue.  */
   if (TREE_CODE (rhs) == NON_LVALUE_EXPR)
     rhs = TREE_OPERAND (rhs, 0);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
old mode 100644
new mode 100755
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c
index e4f1ea8..282a55d 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/array_test1.c
@@ -1,4 +1,4 @@ 
-/* { dg-do compile } */
+/* { dg-do run } */
 /* { dg-options "-fcilkplus" } */
 
 #include <stdlib.h>
@@ -47,7 +47,7 @@  int main2 (char **argv)
   array[x:y:z] = 505;
   for (ii = x; ii < 10; ii += z)
     if (array[ii] != 505)
-      return 2;
+      return 4;
     
   x = atoi(argv[1]);
   z = (10-atoi(argv[1]))/atoi(argv[1]);
@@ -57,7 +57,7 @@  int main2 (char **argv)
 
   for (ii = x; ii < 10; ii += z)
     if (array[ii] != 25)
-      return 1;
+      return 5;
   x = atoi(argv[1]);
   z = (10-atoi(argv[1]))/atoi(argv[1]);
   y = 10-atoi(argv[1]);
@@ -66,19 +66,19 @@  int main2 (char **argv)
     1400;
   for (ii = x; ii < 10; ii += z)
     if (array[ii] != 1400)
-      return 1;
+      return 6;
   
 
   array[atoi("5"):5:1] = 5555;
   
   for (ii = atoi ("5"); ii < 10; ii++)
     if (array[ii] != 5555)
-      return 2;
+      return 7;
   
 
   array[atoi("5"):atoi("5"):atoi("1")] = 9999;
   for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1"))
     if (array[ii] != 9999)
-      return 3;
+      return 8;
   return 0;
 }
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c
index d17d8cf..579d396 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/if_test_errors.c
@@ -18,19 +18,19 @@  int main (void)
     array2[:] = 5;
   else
     array2[:] = 10;
-  if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the then-block" } */
-    array2d[:][:] = 5;
+  if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the then-block" "" { target c } } */
+    array2d[:][:] = 5; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */
   else
     array2[:] = 10;
 
-  if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the else-block" } */
+  if (!(array[0:10:1] + array[0:10:1])) /* { dg-error "condition and the else-block" "" { target c } } */
     array2[:] = 5;
   else
-    array2d[:][:] = 10;
+    array2d[:][:] = 10; /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */
 
 
-  if (TwodArray[:][:] != 10) /* { dg-error "condition and the then-block" } */
-    array2[:] = 10; 
+  if (TwodArray[:][:] != 10) /* { dg-error "condition and the then-block" "" { target c } } */
+    array2[:] = 10;  /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */
   else
     array2[:] = 5;
 
@@ -40,8 +40,8 @@  int main (void)
     array4[32][:][:][:] = 5;
 
   /* atoi(argv[1]) == 10, so it will convert all 10's to 5's */
-  if (FourDArray[42][0:10:1][9:10:-1][0:5:2] != 10) /* { dg-error "condition and the then-block" } */
-    array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 10; 
+  if (FourDArray[42][0:10:1][9:10:-1][0:5:2] != 10) /* { dg-error "condition and the then-block" "" { target c } } */
+    array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 10;  /* { dg-error "rank mismatch with controlling expression of parent" "" { target c++ } } */
   else
     array4[0:10:1][0:5:2][9:10:-1][0:5:2] = 5;
 
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c
index 35eb115..14421d9 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/misc.c
@@ -73,13 +73,13 @@  int main (void)
   while (ii != array2[1:x:3][1:2:1]) /* { dg-error "array notations cannot be used as a condition for while statement"  } */
     x = 2;
 
-  do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" } */
+  do { /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c } } */
     x = 3;
-  } while (ii != array2[:][:]); 
+  } while (ii != array2[:][:]); /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c++ } } */
 
-  do {  /* { dg-error "array notations cannot be used as a condition for a do-while statement" } */
+  do {  /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c } } */
     x = 2;
-  } while (ii != (x + array2[:][1:x:2]) + 2);
+  } while (ii != (x + array2[:][1:x:2]) + 2); /* { dg-error "array notations cannot be used as a condition for a do-while statement" "" { target c++ } } */
   
   do { 
     x += 3;
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
old mode 100644
new mode 100755
index a0a3742..18816e0
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
@@ -8,4 +8,4 @@  int main (void)
   array2[:] = array2[: ;  /* { dg-error "expected ']'" } */
 
   return 0;
-} /* { dg-error "expected ';' before" } */
+} /* { dg-error "expected ';' before" "" { target c } } */
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
index 2e86b4f..4314090 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
@@ -5,7 +5,8 @@  int main (void)
 {
   int array[10][10], array2[10];
   
-  array2[:] = array2[1:2:] ;  /* { dg-error "expected expression before" } */
+  array2[:] = array2[1:2:] ;  /* { dg-error "expected expression before" "" { target c } } */ 
+  /* { dg-error  "expected primary-expression before" "" { target c++ } 8 } */
 
-  return 0; /* { dg-error "expected ';' before" } */
+  return 0; /* { dg-error "expected ';' before" "" { target c }  } */
 }
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
index 34dfa16..47b5979 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
@@ -5,7 +5,8 @@  int main (void)
 {
   int array[10][10], array2[10];
   
-  array2[:] = array2[1::] ;  /* { dg-error "expected expression before" } */
+  array2[:] = array2[1: :] ;  /* { dg-error "expected expression before" "" { target c }  } */ 
+  /* { dg-error "expected primary-expression before" "" { target c++ }  8 } */
 
-  return 0; /* { dg-error "expected ';' before" } */
+  return 0; /* { dg-error "expected ';' before" "" { target c } } */
 }
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c
index eba28a8..a0efc04 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors4.c
@@ -5,7 +5,7 @@  int main (void)
 {
   int array[10][10], array2[10];
   
-  array2[:] = array2[::] ;  /* { dg-error " expected ']' before ':' token" } */
+  array2[:] = array2[ : : ] ;  /* { dg-error " expected ']' before ':' token" }  */
 
   return 0;
 }
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c
index cabdb23..793afb2 100755
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr57541.c
@@ -4,11 +4,11 @@ 
 int A[10];
 
 int main () {
-  char c = (char)N; /* { dg-error "undeclared" } */
+  char c = (char)N; /* { dg-error "declared" } */
   short s = (short)N;
   long l = (long)N;
   A[l:s:c];
 }
 
-/* { dg-message "note: each" "defined" { target *-*-* }  7 } */
+/* { dg-message "note: each" "defined" { target c }  7 } */
 
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c
index 843745e..3b0777e 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/vla.c
@@ -1,5 +1,5 @@ 
-/* { dg-do compile } */
-/* { dg-options "-fcilkplus -std=c99" } */
+/* { dg-do compile { target c } } */
+/* { dg-options "-fcilkplus -std=c99 -w" } */
 
 int func (int x)
 {
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc
new file mode 100644
index 0000000..e9ee7ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test1_tplt.cc
@@ -0,0 +1,118 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcilkplus" } */
+
+#include <cstdlib>
+#include <string.h>
+#if HAVE_IO
+#include <cstdio>
+#endif
+template <class T> int main2 (char **argv);
+
+int main (void)
+{
+  int x = 1, y = 1, z = 1;
+  char *array[2];
+  array[0] = strdup ("a.out");
+  array[1] = strdup ("5");
+  x  = main2<unsigned char> (array);
+  x += main2<char> (array);
+  y  = main2<short> (array);
+  y += main2<unsigned short> (array);
+  y += main2<int> (array);
+  y += main2<unsigned int> (array);
+  z  = main2<long> (array);
+  z += main2<long long> (array);
+  y += main2<float> (array);
+  z += main2<double> (array);
+      
+  return x+y+z;
+}
+template <class T>
+int main2 (char **argv)
+{
+  T array[10];
+  int ii = 0, x = 2, z= 0 , y = 0;
+
+  for (ii = 0; ii < 10; ii++)
+    array[ii] = 10;
+
+  array[0:10:1] = (T)15;
+
+  for (ii = 0; ii < 10; ii++)
+    if (array[ii] != (T)15)
+      return 1;
+  
+
+  array[0:5:2] = (T)20;
+
+  for (ii = 0; ii < 10; ii += 2)
+    if (array[ii] != (T)20)
+      return 2;
+
+
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+
+  array[x:5:z] = (T)50;
+  
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != (T)50)
+      return 3;
+
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]); /* (10 - 5) / 5 = 1 */
+  y = 10-atoi(argv[1]);
+  
+  array[x:y:z] = (T)52;
+#if HAVE_IO
+  for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1"))
+    std::printf("%d\t", (int)array[ii]);
+  std::printf("\n");
+#endif
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != (T)52)
+      return 4;
+    
+
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+  y = 10-atoi(argv[1]);
+  
+  array[x:y:((10-atoi(argv[1]))/atoi(argv[1]))] = (T)25;
+
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != (T)25)
+      return 5;
+  
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+  y = 10-atoi(argv[1]);
+ 
+  array[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))] =
+    (T)14;
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != (T)14)
+      return 6;
+  
+
+  array[atoi("5"):5:1] = (T)65;
+  
+  for (ii = atoi ("5"); ii < 10; ii++)
+    if (array[ii] != (T)65)
+      return 7;
+  
+
+  array[atoi("5"):atoi("5"):atoi("1")] = 99;
+
+#if HAVE_IO
+  for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1"))
+    std::printf("%d\t", (int)array[ii]);
+  std::printf("\n");
+#endif
+
+  for (ii = atoi ("5"); ii < (atoi ("5") + atoi ("5")); ii += atoi ("1"))
+    if (array[ii] != (T)99)
+      return 8;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc
new file mode 100644
index 0000000..87c37e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test2_tplt.cc
@@ -0,0 +1,141 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcilkplus" } */
+
+#include <cstdlib>
+#include <string.h>
+template <class T> int main2(char **argv);
+int main(void)
+{
+  int x = 1, y = 1, z = 1, w = 1; 
+  char *array[2]; 
+  array[0] = strdup ("a.out"); 
+  array[1] = strdup ("5");
+  w  = main2<short>(array);
+  w += main2<unsigned short> (array);
+  x  = main2<char> (array);
+  x += main2<unsigned char> (array);
+  y  = main2<int> (array);
+  y += main2<unsigned int> (array);
+  z = main2<long> (array);
+  z += main2<unsigned long> (array);
+  z += main2<long long> (array);
+      
+  return (w+x+y+z);
+}
+
+template<class T>
+int main2(char **argv)
+{
+  T array[10], array2[10]; 
+  int  ii = 0, x = 2, z= 0 , y = 0 ;
+
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii] = 10;
+      array2[ii] = 5000000;
+    }
+
+  array2[0:10:1] = array[0:10:1];
+
+  for (ii = 0; ii < 10; ii++)
+    if (array2[ii] != array[ii])
+      return 1; 
+
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii] = 10;
+      array2[ii] = 5000000;
+    }
+  
+  array2[0:5:2] = array[0:5:2];
+
+  for (ii = 0; ii < 10; ii += 2)
+    if (array[ii] != array2[ii])
+      return 2;
+  
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii] = 10;
+      array2[ii] = 5000000;
+    }
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+ 
+  array2[x:5:z] = array[x:5:z];
+
+  for (ii = x; ii < 5; ii += z)
+    if (array2[ii] != array[ii])
+      return 3;
+
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii] = 500;
+      array2[ii] = 1000000;
+    }
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+  y = 10-atoi(argv[1]);
+
+  array2[x:y:z] = array[x:y:z];
+  for (ii = x; ii < 10; ii = ii + z)
+    if (array2[ii] != array[ii])
+      return 4;
+
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii]  = 500;
+      array2[ii] = 1000000;
+    }
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+  y = 10-atoi(argv[1]);
+
+  array[x:y:((10-atoi(argv[1]))/atoi(argv[1]))] = 
+    array2[x:y:((10-atoi(argv[1]))/atoi(argv[1]))];
+
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != array2[ii])
+      return 6;
+  
+  
+  x = atoi(argv[1]);
+  z = (10-atoi(argv[1]))/atoi(argv[1]);
+  y = 10-atoi(argv[1]);
+  
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii]  = 500;
+      array2[ii] = 1000000;
+    }
+  
+  array[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))] =
+    array2[atoi(argv[1]):(10-atoi(argv[1])):((10-atoi(argv[1]))/atoi(argv[1]))];
+  for (ii = x; ii < 10; ii += z)
+    if (array[ii] != array2[ii])
+      return 6;
+
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii]  = 4;
+      array2[ii] = 2;
+    }
+
+  array[atoi("5"):5:1] = array2[atoi("5"):5:1];
+
+  for (ii = atoi ("5"); ii < 10; ii++)
+    if (array[ii] != array2[ii])
+      return 7;
+  
+  for (ii = 0; ii < 10; ii++)
+    {
+      array[ii]  = 5;
+      array2[ii] = 1;
+    }
+  array[atoi("5"):atoi("5"):atoi("1")] = array2[atoi("5"):atoi("5"):atoi("1")];
+
+  for (ii = 5; ii < 10; ii++)
+    if (array2[ii] != array[ii])
+      return 8;
+ 
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc
new file mode 100644
index 0000000..479ba13
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/array_test_ND_tplt.cc
@@ -0,0 +1,115 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcilkplus" } */
+
+#include <cstdlib>
+#include<string.h>
+template <class T> int main2(char **argv);
+
+int main(void)
+{
+  int x = 1, y=1, z=1, w = 1;
+  char *array[3];
+  array[0] = strdup ("a.out");
+  array[1] = strdup ("10");
+  array[2] = strdup ("15");
+  w  = main2<char> (array);
+  w += main2<unsigned char> (array);
+  x  = main2<int> (array);
+  x += main2<unsigned int> (array);
+  y  = main2<long> (array);
+  y += main2<unsigned long> (array);
+  z  = main2<short> (array);
+  z += main2<unsigned short> (array);
+  return x+y+z;
+}
+
+template <class T>
+int main2(char **argv)
+{  
+  T array[10][15];
+  T array_2[10][15];
+  int ii = 0, jj = 0,x = 0, z= 1 , y = 10 ,argc = 3;
+ 
+
+  for (ii = 0; ii < 10; ii++) {
+    for (jj = 0; jj< 15; jj++) {
+      array[ii][jj] = ii+jj;
+      array_2[ii][jj] = 0;
+    }
+  }
+  array_2[0:5:2][0:5:3] = array[0:5:2][0:5:3] + 1 + 5 + array[0][5] + x;
+
+  for (ii = 0; ii < 10; ii += 2)
+    {
+      for (jj = 0; jj < 15; jj += 3)
+	{
+	  if (array_2[ii][jj] != array[ii][jj] + 1 + 5 + array[0][5] + x)
+	    return 1;
+	}
+    }
+
+
+  for (ii = 0; ii < 10; ii++) {
+    for (jj = 0; jj< 15; jj++) {
+      array[ii][jj] = ii+jj;
+      array_2[ii][jj] = 0;
+    }
+  }
+  x = atoi(argv[1]);
+  y = atoi(argv[2]);
+  array_2[0:x:1][0:y:1] = array[0:x:1][0:y:1] + x + y + array[0:x:1][0:y:1];
+
+  for (ii = 0; ii < x; ii++)
+    {
+      for (jj = 0; jj < y; jj++)
+	{
+	  if (array_2[ii][jj] != array[ii][jj] + x + y + array[ii][jj])
+	    return 2;
+	}
+    }
+
+  for (ii = 0; ii < 10; ii++) {
+    for (jj = 0; jj< 15; jj++) {
+      array[ii][jj] = ii+jj;
+      array_2[ii][jj] = 0;
+    }
+  }
+  x = atoi(argv[1]);
+  y = atoi(argv[2]);
+  z = (20- atoi (argv[1]))/atoi(argv[1]);
+  /* (20-10)/10 evaluates to 1 all the time :-). */
+  array_2[0:x:z][0:y:z] = array[0:x:z][0:y:z] + array[0:x:z][0:y:z] + y + z;
+  
+  for (ii = 0; ii < x; ii += z)
+    {
+      for (jj = 0; jj < y; jj += z)
+	{
+	  if (array_2[ii][jj] != array[ii][jj] + array[ii][jj] + y + z)
+	    return 3;
+	}
+    }
+
+
+ 
+  for (ii = 0; ii < 10; ii++) {
+    for (jj = 0; jj< 15; jj++) {
+      array[ii][jj] = ii+jj;
+      array_2[ii][jj] = 0;
+    }
+  }
+  x = argc-3;
+  y = 20-atoi(argv[1]);
+  z = (20- atoi (argv[1]))/atoi(argv[1]);
+  /* (20-10)/10 evaluates to 1 all the time :-). */
+  array_2[(argc-3):(20-atoi(argv[1])):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): ((30-atoi(argv[2]))/atoi(argv[2]))] = array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])] + array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])] * array[(argc-3):20-atoi(argv[1]):(20-atoi(argv[1]))/atoi(argv[1])][(argc-3):(30-atoi(argv[2])): (30-atoi(argv[2]))/atoi(argv[2])];
+  
+  for (ii = 0; ii < 10; ii++)
+    {
+      for (jj = 0; jj < 15; jj++)
+	{
+	  if (array_2[ii][jj] != array[ii][jj] + array[ii][jj] * array[ii][jj])
+	    return 4;
+	}
+    }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc
new file mode 100755
index 0000000..b91de7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/braced_list.cc
@@ -0,0 +1,13 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus -std=c++11 " } */
+
+int main (void)
+{
+  int Array[100], Array2[100];
+
+  Array[{1,2}:2] = 5; /* { dg-error "braced list index is not allowed" } */
+  Array[1:{1,2}:2] = 5; /* { dg-error "expected primary-expression before" } */
+  Array[1:10:{1,2}] = 5; /* { dg-error "expected primary-expression before" } */
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc
new file mode 100644
index 0000000..94ffe6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_custom_tplt.cc
@@ -0,0 +1,126 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcilkplus "} */
+
+#if HAVE_IO 
+#include <cstdio>
+#endif
+
+#include <cstdlib>
+
+template <class T>
+T my_func (T x, T y)
+{
+  if (x > y)
+    return x;
+  else
+    return y;
+}
+
+template <class T>
+T main_func (T  *array, T *array2, T identity_val, int size)
+{
+  T result;
+
+  result = __sec_reduce (identity_val, array[0:size:1] * array2[0:size:1],
+			 my_func); // my_func (identity_val, array[5] * array2[5]);
+  return result;
+}
+int main (void)
+{
+  int    i_index = 0, f_index = 0, d_index = 0, l_index = 0;
+  int    iarray[10], iarray2[10], i_result, i_max;
+  long   larray[10], larray2[10], l_result, l_max;
+  float  farray[10], farray2[10], f_result, f_max;
+  double darray[10], darray2[10], d_result, d_max;
+  for (int ii = 0; ii < 10; ii++)
+    {
+      if (ii%2 && ii)
+	{
+	  darray[ii] = (double)(1.0000/(double)ii);
+	  farray[ii] = (float)(1.00/(float)ii);
+	}
+      else
+	{
+	  darray[ii] = (double) ii + 0.10;
+	  farray[ii] = (float) (1.00/((float)(ii+1.000)));
+	}
+      darray2[ii] = (double) (1.00000/ (double)(ii+1));
+      farray2[ii] = (float) (1.00/ (float)(ii+1));
+    }
+
+  for (int ii = 0; ii < 10; ii++)
+    {
+      iarray[ii] = ii;
+      larray[ii] = (long)ii;
+    }
+
+  for (int ii = 0; ii < 10; ii++)
+    {
+      iarray2[ii] = (ii-5);
+      larray2[ii] = long (ii-5);
+    }
+#if HAVE_IO
+  printf("Int: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%2d ", iarray[ii] * iarray2[ii]);
+    }
+  printf("\nfloat: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%4.3f ", farray[ii] * farray2[ii]);
+    }
+
+  printf("\nlong: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%2d ", larray[ii] * larray2[ii]);
+    }
+
+  printf("\ndouble: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%4.3f ", (float) (darray[ii] * darray2[ii]));
+    }
+  printf("\n");
+#endif
+
+  i_result = main_func<int> (iarray, iarray2, iarray[0] * iarray2[0], 10);
+  f_result = main_func<float>(farray, farray2, 0.00, 10);
+  d_result = main_func<double>(darray, darray2, 0.0000, 10);
+  l_result = main_func<long>(larray, larray2, 0, 10);
+
+#if HAVE_IO
+  printf("int result    = %2d\n", i_result);
+  printf ("long result   = %2d\n", l_result);
+  printf("float result  = %4.3f\n", f_result);
+  printf("double result = %4.3lf\n", d_result);
+#endif
+    
+  i_max = iarray[0] * iarray2[0];
+  f_max = farray[0] * farray2[0];
+  d_max = darray[0] * darray2[0];
+  l_max = larray[0] * larray2[0];
+  for (int ii = 0; ii < 10; ii++)
+    {
+      if (i_max < iarray[ii] * iarray2[ii])
+	i_max = iarray[ii] * iarray2[ii];
+      if (f_max < farray[ii] * farray2[ii])
+	f_max = farray[ii] * farray2[ii];
+      if (d_max < darray[ii] * darray2[ii])
+	d_max = darray[ii] * darray2[ii];
+      if (l_max < larray[ii] * larray2[ii])
+	l_max = larray[ii] * larray2[ii];
+    }
+
+  if (i_max != i_result)
+    return 1;
+  if (f_max != f_result)
+    return 2;
+  if (d_max != d_result)
+    return 3;
+  if (l_max != l_result)
+    return 4;
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc
new file mode 100644
index 0000000..db81912
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/builtin_fn_mutating_tplt.cc
@@ -0,0 +1,134 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcilkplus" }  */
+
+#if HAVE_IO 
+#include <cstdio>
+#include<iostream>
+#endif
+
+#include <cstdlib>
+
+template <class T>
+T my_func (T *x, T y)
+{
+  if (*x < y)
+    *x = y;
+  else
+    *x = *x;
+}
+
+template <class T> T my_func (T *x, T y);
+template <class T>
+T main_func (T  *array, T *array2, T identity_val, int size)
+{
+  T result = identity_val;
+  
+  __sec_reduce_mutating (&result, array[0:size] * array2[0:size:1], my_func);
+  
+#if HAVE_IO
+  std::cout << "Result = " << result << std::endl;
+#endif
+  return result;
+}
+
+int main (void)
+{
+  int    iarray[10], iarray2[10], i_result = 0, i_max;
+  long   larray[10], larray2[10], l_result = 0, l_max;
+  float  farray[10], farray2[10], f_result = 0, f_max;
+  double darray[10], darray2[10], d_result = 0, d_max;
+  for (int ii = 0; ii < 10; ii++)
+    {
+      if (ii%2 && ii)
+	{
+	  darray[ii] = (double)(1.0000/(double)(ii));
+	  farray[ii] = (float)(1.00/(float)(ii));
+	}
+      else
+	{
+	  darray[ii] = (double) ii + 0.10;
+	  farray[ii] = (float) (1.00/((float)(ii) + 0.10));
+	}
+      darray2[ii] = (double) (1.00000/ (double)(ii+1));
+      farray2[ii] = (float) (1.00/ (float)(ii+1));
+    }
+
+  for (int ii = 0; ii < 10; ii++)
+    {
+      iarray[ii] = ii;
+      larray[ii] = (long)ii;
+    }
+
+  for (int ii = 0; ii < 10; ii++)
+    {
+      iarray2[ii] = (ii-5);
+      larray2[ii] = (long)ii-5;
+    }
+#if HAVE_IO
+  printf("\nInt: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%2d ", iarray[ii] * iarray2[ii]);
+    }
+  printf("\nfloat: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%3.2f ", farray[ii] * farray2[ii]);
+    }
+
+  printf("\nlong: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%2d ", larray[ii] * larray2[ii]);
+    }
+
+  printf("\ndouble: ");
+  for (int ii=0; ii < 10; ii++)
+    {
+      printf("%4.3lf ", (float) (darray[ii] * darray2[ii]));
+    }
+  printf("\n");
+#endif
+
+  i_result = main_func<int> (iarray, iarray2, 0, 10);
+  l_result = main_func<long>(larray, larray2, 0, 10);
+  f_result = main_func<float>(farray, farray2, 0.00, 10);
+  d_result = main_func<double>(darray, darray2, 0.0000, 10);
+  
+  i_max = iarray[0] * iarray2[0];
+  d_max = darray[0] * darray2[0];
+  f_max = farray[0] * farray2[0];
+  l_max = larray[0] * larray2[0];
+  for (int ii = 0; ii < 10; ii++)
+    {
+      if (iarray[ii] * iarray2[ii] > i_max)
+	i_max = iarray[ii] * iarray2[ii];
+      if (darray[ii] * darray2[ii] > d_max)
+	d_max = darray[ii] * darray2[ii];
+      if (farray[ii] * farray2[ii] > f_max)
+	f_max = farray[ii] * farray2[ii];
+      if (larray[ii] * larray2[ii] > l_max)
+	l_max = larray[ii] * larray2[ii];
+    }
+#if HAVE_IO
+  printf("int result    = %2d\n", i_max);
+  printf("long result   = %2d\n", l_max);
+  printf("float result  = %4.3f\n", f_max);
+  printf("double result = %4.3lf\n", (float)d_max);
+#endif
+  
+ if (i_max != i_result)
+   return 1;
+
+ if (f_max != f_result)
+   return 2;
+
+ if (l_max != l_result)
+   return 3;
+
+ if (d_max != d_result)
+   return 4;
+ 
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c b/gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c
new file mode 100644
index 0000000..1387558
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/AN/fp_triplet_values_tplt.c
@@ -0,0 +1,36 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+float q;
+
+void func (int *x)
+{
+  *x = 5;
+}
+template <class T> int main2 (T x, T y, T z);
+
+int main (void)
+{
+  main2 <float> (1.5, 2.3, 3.443);
+  main2 <double> (1.34393, 2.38383, 4.38383);
+  return 0;
+}
+template <class T> 
+int main2 (T x, T y, T z)
+{
+  int array[10], array2[10];
+  array2[:] = array[x:2]; /* { dg-error "start-index of array notation triplet is not an integer" } */
+  array2[:] = array[1:y]; /* { dg-error "length of array notation triplet is not an integer" } */
+  array2[1:2:z] = array[:]; /* { dg-error "stride of array notation triplet is not an integer" } */
+  func (&array2[1:x:3]); /* { dg-error "length of array notation triplet is not an integer" } */
+  array2[y:9]++; /* { dg-error "start-index of array notation triplet is not an integer" } */
+  array2[1:x]++; /* { dg-error "length of array notation triplet is not an integer" } */
+  array2[1:9:x]++; /* { dg-error "stride of array notation triplet is not an integer" } */
+  
+  ++array2[1:q:3]; /* { dg-error "length of array notation triplet is not an integer" } */
+  array2[:] = array[q:1:3]; /* { dg-error "start-index of array notation triplet is not an integer" } */
+  array2[:] = array[1:q:3]; /* { dg-error "length of array notation triplet is not an integer" } */
+  array2[:] = array[1:3:q]; /* { dg-error "stride of array notation triplet is not an integer" } */
+  func (&array2[1:q:3]); /* { dg-error "length of array notation triplet is not an integer" } */
+  return 0;
+} 
diff --git a/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
new file mode 100644
index 0000000..a153529
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cilk-plus/cilk-plus.exp
@@ -0,0 +1,48 @@ 
+#   Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+# 
+# This program 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/>.
+
+# Written by Balaji V. Iyer <balaji.v.iyer@intel.com>
+
+
+load_lib g++-dg.exp
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -g -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/c-c++-common/cilk-plus/AN/*.c]] " -O3 -ftree-vectorize -fcilkplus -g" " "
+dg-finish
+
+dg-init
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O0 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O1 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O2 -ftree-vectorize -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -g -O3 -fcilkplus" " "
+dg-runtest [lsort [glob -nocomplain $srcdir/g++.dg/cilk-plus/AN/*.cc]] " -O3 -ftree-vectorize -fcilkplus -g" " "
+dg-finish
diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp
old mode 100644
new mode 100755
index 7201359..710218e
--- a/gcc/testsuite/g++.dg/dg.exp
+++ b/gcc/testsuite/g++.dg/dg.exp
@@ -33,6 +33,7 @@  dg-init
 set tests [lsort [find $srcdir/$subdir *.C]]
 set tests [prune $tests $srcdir/$subdir/bprob/*]
 set tests [prune $tests $srcdir/$subdir/charset/*]
+set tests [prune $tests $srcdir/$subdir/cilk-plus/AN/*]
 set tests [prune $tests $srcdir/$subdir/compat/*]
 set tests [prune $tests $srcdir/$subdir/debug/*]
 set tests [prune $tests $srcdir/$subdir/dfp/*]