diff mbox

[Cilkplus] N-Dimension Array Notation Triplet Implementation

Message ID BF230D13CA30DD48930C31D409933000E630@FMSMSX102.amr.corp.intel.com
State New
Headers show

Commit Message

Iyer, Balaji V Dec. 19, 2011, 7:36 p.m. UTC
Hello Everyone,
               This patch is for the C Compiler in Cilkplus branch. It is an extension of the following patch: http://gcc.gnu.org/ml/gcc-patches/2011-12/msg00691.html. This patch will implement an N-dimension array notation for assignment expressions. 

Thanking You,

Yours sincerely,

Balaji V. Iyer.
diff mbox

Patch

diff --git a/gcc/ChangeLog.cilk b/gcc/ChangeLog.cilk
index 6d2b694..bf848b1 100644
--- a/gcc/ChangeLog.cilk
+++ b/gcc/ChangeLog.cilk
@@ -1,3 +1,10 @@ 
+2011-12-16  Balaji V. Iyer  <balaji.v.iyer@intel.com>
+
+	* c-typeck.c (find_rank): Modified to find rank of array notation
+	inside expressions such as PLUS_EXPR.
+	(build_array_notation_expr): Added support for N-Diamension array
+	notation.
+
 2011-12-09  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
 	* c-typeck.c (build_array_notation_expr): New function.
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index d9cf8e4..c4ff22e 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -5044,231 +5044,399 @@  build_modify_expr (location_t location, tree lhs, tree lhs_origtype,
   return result;
 }
 
+
+static int
+find_rank (tree array)
+{
+  int rank = 0;
+  tree ii_tree = NULL_TREE, jj_tree = NULL_TREE;
+  int highest_rank = 0, jj = 0;
+
+  if (TREE_CODE (array) != ARRAY_NOTATION_REF)
+    {
+      for (jj = 0; jj < TREE_CODE_LENGTH (TREE_CODE (array)); jj++)
+	{
+	  rank = 0;
+	  jj_tree = TREE_OPERAND (array, jj);
+	  for (ii_tree = jj_tree;
+	       ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
+	       ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+	    rank++;
+      
+	  if (highest_rank != 0 && rank != 0 && highest_rank != rank)
+	    error ("Rank Mismatch!");
+	  else if (highest_rank < rank)
+	    highest_rank = rank;
+	}
+    }
+  else
+    {
+      for (ii_tree = array;
+	   ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
+	   ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+	rank++;
+      highest_rank = rank;
+    }
+      
+  return highest_rank;
+}      
+
 tree
 build_array_notation_expr (location_t location, tree lhs, tree lhs_origtype,
 			   enum tree_code modifycode, location_t rhs_loc,
 			   tree rhs, tree rhs_origtype)
 {
-  bool lhs_vector = false, rhs_vector = false;
-  tree array_expr_lhs = NULL_TREE, array_expr_rhs = NULL_TREE, array_expr;
-  tree lhs_value = NULL_TREE, rhs_value = NULL_TREE;
-  tree lhs_stride = NULL_TREE, lhs_length = NULL_TREE, lhs_start = NULL_TREE;
-  tree rhs_stride = NULL_TREE, rhs_length = NULL_TREE, rhs_start = NULL_TREE;
-  tree loop, lhs_var = NULL_TREE, rhs_var = NULL_TREE;
-  tree body_label, body_label_expr;
-  tree exit_label, exit_label_expr, cond_expr,  if_stmt_label;
-  tree temp = NULL_TREE;
-  tree lhs_expr_incr = NULL_TREE, rhs_expr_incr = NULL_TREE;
-  bool lhs_count_down = false, rhs_count_down = false;
+  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 loop = NULL_TREE, *lhs_var = NULL, *rhs_var = NULL;
+  tree *body_label = NULL, *body_label_expr = NULL;
+  tree *exit_label = NULL, *exit_label_expr = NULL, *cond_expr = NULL;
+  tree *if_stmt_label = 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;
+  int lhs_rank = 0, rhs_rank = 0, ii = 0;
+  tree ii_tree = NULL_TREE;
   
-  if (TREE_CODE(lhs) == ARRAY_NOTATION_REF)
-    {
-      lhs_value = ARRAY_NOTATION_ARRAY (lhs);
-      lhs_start = ARRAY_NOTATION_START (lhs);
-      lhs_length = ARRAY_NOTATION_LENGTH (lhs);
-      lhs_stride = ARRAY_NOTATION_STRIDE (lhs);
-      lhs_vector = true;
-      /* if the stride value is variable (i.e. not constant) then assume the
-	 programmer knows what he is doing and keep on going */
-      if (!TREE_CONSTANT (lhs_length))
-	lhs_count_down = false; /* assume we count up */
-      else if (tree_int_cst_lt (lhs_length,
-				build_int_cst (TREE_TYPE (lhs_length), 0)))
-	lhs_count_down = true;
+  lhs_rank = find_rank (lhs);
+  rhs_rank = find_rank (rhs);
+
+    if (lhs_rank == 0 && rhs_rank != 0)
+    {
+      error_at (location, "Left Hand-side rank cannot be scalar when "
+		"right-hand side is not");
+      return error_mark_node;
     }
-  else
+  if (lhs_rank != 0 && rhs_rank != 0 && lhs_rank != rhs_rank)
     {
-      if (TREE_CODE(rhs) == ARRAY_NOTATION_REF)
-	error ("Assignment of vector to a scalar is prohibited");
-      else
-	lhs_vector = false;
+      error_at (location, "Rank-mismatch");
+      return error_mark_node;
+    }
+  
+  lhs_vector = (bool *) xmalloc (sizeof (bool) * lhs_rank);
+  rhs_vector = (bool *) xmalloc (sizeof (bool) * rhs_rank);
+
+  lhs_array = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_array = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_value = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_value = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_stride = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_stride = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_length = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_length = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_start = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_start = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_var = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_var = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  /* The reason why we are just using lhs_rank for this is because we have the
+   * following scenarios:
+   * LHS_RANK == RHS_RANK
+   * LHS_RANK != RHS_RANK && RHS_RANK = 0
+   *
+   * In both the scenarios, just checking the LHS_RANK is OK
+   */
+  body_label = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  body_label_expr = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  exit_label = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  exit_label_expr = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  cond_expr = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  if_stmt_label = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+
+  lhs_expr_incr = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_expr_incr = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_ind_init = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_ind_init = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  lhs_count_down = (bool *) xmalloc (sizeof (bool) * lhs_rank);
+  rhs_count_down = (bool *) xmalloc (sizeof (bool) * rhs_rank);
+
+  lhs_compare = (tree *) xmalloc (sizeof (tree) * lhs_rank);
+  rhs_compare = (tree *) xmalloc (sizeof (tree) * rhs_rank);
+
+  ii = 0;
+  for (ii_tree = lhs; ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
+       ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+    {
+      lhs_array[ii] = ii_tree;
+      ii++;
+    }
+
+  if (rhs_rank)
+    {
+      ii = 0;
+      for (ii_tree = rhs; ii_tree && TREE_CODE (ii_tree) == ARRAY_NOTATION_REF;
+	   ii_tree = ARRAY_NOTATION_ARRAY (ii_tree))
+	{
+	  rhs_array[ii] = ii_tree;
+	  ii++;
+	}
+    }
+
+  if (TREE_CODE (lhs) == ARRAY_NOTATION_REF)
+    {
+      for (ii = 0; ii < lhs_rank; ii++)
+	{
+	  if (TREE_CODE (lhs_array[ii]) == ARRAY_NOTATION_REF)
+	    {
+	      lhs_value[ii] = ARRAY_NOTATION_ARRAY (lhs_array[ii]);
+	      lhs_start[ii] = ARRAY_NOTATION_START (lhs_array[ii]);
+	      lhs_length[ii] = ARRAY_NOTATION_LENGTH (lhs_array[ii]);
+	      lhs_stride[ii] = ARRAY_NOTATION_STRIDE (lhs_array[ii]);
+	      lhs_vector[ii] = true;
+	      /* IF the stride value is variable (i.e. not constant) then
+	       * assume that the length is positive
+	       */
+	      if (!TREE_CONSTANT (lhs_length[ii]))
+		lhs_count_down[ii] = false;
+	      else if (tree_int_cst_lt
+		       (lhs_length[ii],
+			build_int_cst (TREE_TYPE (lhs_length[ii]), 0)))
+		lhs_count_down[ii] = true;
+	      else
+		lhs_count_down[ii] = false;
+	    }
+	  else
+	    lhs_vector[ii] = false;
+	}
     }
 
   if (TREE_CODE (rhs) == ARRAY_NOTATION_REF)
     {
-      rhs_value = ARRAY_NOTATION_ARRAY (rhs);
-      rhs_start = ARRAY_NOTATION_START (rhs);
-      rhs_length = ARRAY_NOTATION_LENGTH (rhs);
-      rhs_stride = ARRAY_NOTATION_STRIDE (rhs);
-      rhs_vector = true;
-      
-      /* if the stride value is variable (i.e. not constant) then assume the
-	 programmer knows what he is doing and keep on going */
-      if (!TREE_CONSTANT (rhs_length))
-	rhs_count_down = false; /* assume wwe count up */
-      else if (tree_int_cst_lt (rhs_length,
-				build_int_cst (TREE_TYPE (rhs_length), 0)))
-	rhs_count_down = true;
+      for (ii = 0; ii < rhs_rank; ii++)
+	{
+	  if (TREE_CODE (rhs_array[ii]) == ARRAY_NOTATION_REF)
+	    {
+	      rhs_value[ii] = ARRAY_NOTATION_ARRAY (rhs_array[ii]);
+	      rhs_start[ii] = ARRAY_NOTATION_START (rhs_array[ii]);
+	      rhs_length[ii] = ARRAY_NOTATION_LENGTH (rhs_array[ii]);
+	      rhs_stride[ii] = ARRAY_NOTATION_STRIDE (rhs_array[ii]);
+	      rhs_vector[ii] = true;
+	      /* If the stride value is variable (i.e. not constant) then
+	       * assume that the length is positive
+	       */
+	      if (!TREE_CONSTANT (rhs_length[ii]))
+		rhs_count_down[ii] = false;
+	      else if (tree_int_cst_lt
+		       (rhs_length[ii],
+			build_int_cst (TREE_TYPE (rhs_length[ii]), 0)))
+		rhs_count_down[ii] = true;
+	      else
+		rhs_count_down[ii] = false;	
+	    }
+	  else
+	    rhs_vector[ii] = false;
+	}
     }
-  else
-    rhs_vector = false;
 
   loop = push_stmt_list();
 
-  if (lhs_vector)
+  for (ii = 0; ii < lhs_rank; ii++)
     {
-      lhs_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE,
-			    TREE_TYPE (lhs_start));
-      temp = build_modify_expr
-	(UNKNOWN_LOCATION, lhs_var, TREE_TYPE (lhs_var), modifycode,
-	 UNKNOWN_LOCATION, build_int_cst (TREE_TYPE (lhs_start), 0),
-	 TREE_TYPE (lhs_start));
-      add_stmt (temp);
+      if (lhs_vector[ii])
+	{
+	  lhs_var[ii] = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE,
+				    TREE_TYPE (lhs_start[ii]));
+	  lhs_ind_init[ii] = build_modify_expr
+	    (UNKNOWN_LOCATION, lhs_var[ii], TREE_TYPE (lhs_var[ii]),
+	     modifycode,
+	     UNKNOWN_LOCATION, build_int_cst (TREE_TYPE (lhs_start[ii]), 0),
+	     TREE_TYPE (lhs_start[ii]));
+	  
+	}
     }
-  if (rhs_vector)
+  for (ii = 0; ii < rhs_rank; ii++)
     {
-      rhs_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE,
-			    TREE_TYPE (rhs_start));
-      add_stmt (build_modify_expr (UNKNOWN_LOCATION, rhs_var,
-				   TREE_TYPE (rhs_var), modifycode,
-				   UNKNOWN_LOCATION,
-				   build_int_cst (TREE_TYPE(rhs_start), 0),
-				   TREE_TYPE (rhs_start)));
+      if (rhs_vector[ii])
+	{
+	  rhs_var[ii] = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE,
+				    TREE_TYPE (rhs_start[ii]));
+	  rhs_ind_init[ii] = build_modify_expr
+	    (UNKNOWN_LOCATION, rhs_var[ii], TREE_TYPE (rhs_var[ii]),
+	     modifycode,
+	     UNKNOWN_LOCATION, build_int_cst (TREE_TYPE(rhs_start[ii]), 0),
+	     TREE_TYPE (rhs_start[ii]));
+	  
+	}
     }
 
-
-  /* this will create the if statement label */
-  if_stmt_label = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
-			      void_type_node);
-  DECL_CONTEXT (if_stmt_label) = current_function_decl;
-  DECL_ARTIFICIAL (if_stmt_label) = 0;
-  DECL_IGNORED_P (if_stmt_label) = 1;
+  for (ii = 0; ii < lhs_rank ; ii++)
+    {
+      /* this will create the if statement label */
+      if_stmt_label[ii] = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
+				      void_type_node);
+      DECL_CONTEXT (if_stmt_label[ii]) = current_function_decl;
+      DECL_ARTIFICIAL (if_stmt_label[ii]) = 0;
+      DECL_IGNORED_P (if_stmt_label[ii]) = 1;
   
-  /* this label statment will point to the loop body */
-  body_label = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
-			   void_type_node);
-  DECL_CONTEXT (body_label) = current_function_decl;
-  DECL_ARTIFICIAL (body_label) = 0;
-  DECL_IGNORED_P (body_label) = 1;
-  body_label_expr = build1 (LABEL_EXPR, void_type_node, body_label);
-
-  /* this will create the exit label..i.e. where the while loop will branch
-     out of
-  */
-  exit_label = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
-			   void_type_node);
-  DECL_CONTEXT (exit_label) = current_function_decl;
-  DECL_ARTIFICIAL (exit_label) = 0;
-  DECL_IGNORED_P (exit_label) = 1;
-  exit_label_expr = build1 (LABEL_EXPR, void_type_node, exit_label);
-
-  if (lhs_vector)
-    {
-      /* Array[start_index + (induction_var * stride)] */
-      array_expr_lhs = build_array_ref
-	(location, lhs_value, build2 (PLUS_EXPR, TREE_TYPE (lhs_var), lhs_start,
-				      build2 (MULT_EXPR, TREE_TYPE (lhs_var),
-					      lhs_var, lhs_stride)));
-      if (lhs_count_down)
-	lhs_expr_incr = build2 (MODIFY_EXPR, void_type_node, lhs_var,
-				build2 (PLUS_EXPR, TREE_TYPE (lhs_var), lhs_var,
-					build_int_cst (TREE_TYPE (lhs_var),
-						       -1)));
-      else 
-	lhs_expr_incr = build2 (MODIFY_EXPR, void_type_node, lhs_var,
-				build2 (PLUS_EXPR, TREE_TYPE (lhs_var), lhs_var,
-					build_int_cst (TREE_TYPE (lhs_var),
-						       1)));
-    }
-  if (rhs_vector)
+      /* this label statment will point to the loop body */
+      body_label[ii] = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
+				   void_type_node);
+      DECL_CONTEXT (body_label[ii]) = current_function_decl;
+      DECL_ARTIFICIAL (body_label[ii]) = 0;
+      DECL_IGNORED_P (body_label[ii]) = 1;
+      body_label_expr[ii] = build1 (LABEL_EXPR, void_type_node, body_label[ii]);
+
+      /* this will create the exit label..i.e. where the while loop will branch
+	 out of
+      */
+      exit_label[ii] = build_decl (UNKNOWN_LOCATION, LABEL_DECL, NULL_TREE,
+				   void_type_node);
+      DECL_CONTEXT (exit_label[ii]) = current_function_decl;
+      DECL_ARTIFICIAL (exit_label[ii]) = 0;
+      DECL_IGNORED_P (exit_label[ii]) = 1;
+      exit_label_expr[ii] = build1 (LABEL_EXPR, void_type_node, exit_label[ii]);
+    }
+
+  if (lhs_rank)
+    {
+      /* The last ARRAY_NOTATION element's ARRAY component should be the array's
+       * base value
+       */
+      array_expr_lhs = lhs_value[lhs_rank - 1];
+      for (ii = lhs_rank - 1; ii >= 0; ii--)
+	{
+	  /* Array[start_index + (induction_var * stride)] */
+	  array_expr_lhs = build_array_ref
+	    (location, array_expr_lhs,
+	     build2 (PLUS_EXPR, TREE_TYPE (lhs_var[ii]), lhs_start[ii],
+		     build2 (MULT_EXPR, TREE_TYPE (lhs_var[ii]), lhs_var[ii],
+			     lhs_stride[ii])));
+	  if (lhs_count_down[ii])
+	    lhs_expr_incr[ii] =
+	      build2 (MODIFY_EXPR, void_type_node, lhs_var[ii],
+		      build2 (PLUS_EXPR, TREE_TYPE (lhs_var[ii]), lhs_var[ii],
+			      build_int_cst (TREE_TYPE (lhs_var[ii]), -1)));
+	  else
+	    lhs_expr_incr[ii] =
+	      build2 (MODIFY_EXPR, void_type_node, lhs_var[ii],
+		      build2 (PLUS_EXPR, TREE_TYPE (lhs_var[ii]), lhs_var[ii],
+			      build_int_cst (TREE_TYPE (lhs_var[ii]), 1)));
+	}
+    }
+
+  if (rhs_rank)
     {
-      
-      array_expr_rhs = build_array_ref
-	(location, rhs_value, build2 (PLUS_EXPR, TREE_TYPE (rhs_var), rhs_start,
-				      build2 (MULT_EXPR, TREE_TYPE (rhs_var),
-					      rhs_var, rhs_stride)));
-      if (rhs_count_down)
-	rhs_expr_incr = build2 (MODIFY_EXPR, void_type_node, rhs_var,
-				build2 (PLUS_EXPR, TREE_TYPE (rhs_var), rhs_var,
-					build_int_cst (TREE_TYPE (rhs_var),
-						       -1)));
-      else 
-	rhs_expr_incr = build2 (MODIFY_EXPR, void_type_node, rhs_var,
-				build2 (PLUS_EXPR, TREE_TYPE (rhs_var), rhs_var,
-					build_int_cst (TREE_TYPE (rhs_var),
-						       1)));
+      /* The last ARRAY NOTATION element's ARRAY component should be the
+       * array's base value
+       */
+      array_expr_rhs = rhs_value[rhs_rank - 1];
+      for (ii = rhs_rank - 1; ii >= 0; ii--)
+	{
+	  /* Array[start_index + (induction_var * stride)] */
+	  array_expr_rhs = build_array_ref
+	    (location, array_expr_rhs,
+	     build2 (PLUS_EXPR, TREE_TYPE (rhs_var[ii]), rhs_start[ii],
+		     build2 (MULT_EXPR, TREE_TYPE (rhs_var[ii]), rhs_var[ii],
+			     rhs_stride[ii])));
+
+	  if (rhs_count_down[ii])
+	    rhs_expr_incr[ii] =
+	      build2 (MODIFY_EXPR, void_type_node, rhs_var[ii],
+		      build2 (PLUS_EXPR, TREE_TYPE (rhs_var[ii]), rhs_var[ii],
+			      build_int_cst (TREE_TYPE (rhs_var[ii]), -1)));
+	  else
+	    rhs_expr_incr[ii] =
+	      build2 (MODIFY_EXPR, void_type_node, rhs_var[ii],
+		      build2 (PLUS_EXPR, TREE_TYPE (rhs_var[ii]), rhs_var[ii],
+			      build_int_cst (TREE_TYPE (rhs_var[ii]), 1)));
+	}
     }
   else
     {
       array_expr_rhs = rhs;
-      rhs_expr_incr = NULL_TREE;
+      rhs_expr_incr[0] = NULL_TREE;
     }
 
   array_expr = build_modify_expr (location, array_expr_lhs,
 				  lhs_origtype, modifycode, rhs_loc,
 				  array_expr_rhs, rhs_origtype);
 
-  if (rhs_expr_incr)
+  for (ii = 0; ii < lhs_rank; ii++)
     {
-      tree lhs_compare, rhs_compare;
-      if (lhs_count_down)
-	lhs_compare = build2 (GE_EXPR, boolean_type_node, lhs_var,
-			      build2 (PLUS_EXPR, TREE_TYPE (lhs_length),
-				      lhs_length,
-				      build_int_cst (TREE_TYPE (lhs_length),
-						     1)));
-      else
-	lhs_compare = build2 (LE_EXPR, boolean_type_node, lhs_var,
-			      build2 (MINUS_EXPR, TREE_TYPE (lhs_length),
-				      lhs_length,
-				      build_int_cst (TREE_TYPE (lhs_length),
-						     1)));
-
-      if (rhs_count_down)
-	rhs_compare = build2 (GE_EXPR, boolean_type_node, rhs_var,
-			      build2 (PLUS_EXPR, TREE_TYPE (rhs_length),
-				      rhs_length,
-				      build_int_cst (TREE_TYPE (rhs_length),
-						     1)));
-      else
-	rhs_compare = build2 (LE_EXPR, boolean_type_node, rhs_var,
-			      build2 (MINUS_EXPR, TREE_TYPE (rhs_length),
-				      rhs_length,
-				      build_int_cst (TREE_TYPE (rhs_length),
-						     1)));
+      if (rhs_rank && rhs_expr_incr[ii])
+	{
+	  if (lhs_count_down[ii])
+	    lhs_compare[ii] = build2
+	      (GT_EXPR, boolean_type_node, lhs_var[ii], lhs_length[ii]);
+	  
+	  else
+	    lhs_compare[ii] = build2
+	      (LT_EXPR, boolean_type_node, lhs_var[ii], lhs_length[ii]);
+
+	  if (rhs_count_down[ii])
+	    rhs_compare[ii] = build2
+	      (GT_EXPR, boolean_type_node, rhs_var[ii], rhs_length[ii]);
+	  else
+	    rhs_compare[ii] = build2
+	      (LT_EXPR, boolean_type_node, rhs_var[ii], rhs_length[ii]);
       
-      cond_expr = build2 (TRUTH_ANDIF_EXPR, void_type_node, lhs_compare,
-			  rhs_compare);
-    }
-  else
-    {
-      if (lhs_count_down)
-	cond_expr = build2 (GE_EXPR, boolean_type_node, lhs_var,
-			    build2 (PLUS_EXPR, TREE_TYPE (lhs_length),
-				    lhs_length,
-				    build_int_cst (TREE_TYPE (lhs_length), 1)));
+	  cond_expr[ii] = build2 (TRUTH_ANDIF_EXPR, void_type_node,
+				  lhs_compare[ii], rhs_compare[ii]);
+	}
       else
-	cond_expr = build2 (LE_EXPR, boolean_type_node, lhs_var,
-			    fold_build2 (PLUS_EXPR, TREE_TYPE (lhs_length),
-				    lhs_length,
-				    build_int_cst (TREE_TYPE (lhs_length), -1)));
+	{
+	  if (lhs_count_down[ii])
+	    cond_expr[ii] = build2
+	      (GT_EXPR, boolean_type_node, lhs_var[ii], lhs_length[ii]);
+	  else
+	    cond_expr[ii] = build2
+	      (LT_EXPR, boolean_type_node, lhs_var[ii], lhs_length[ii]);
+	}
     }
   
   /* The following statements will do the following:
-   * <if_stmt_label>:
+   * <if_stmt_label>: (in order from outermost to innermost)
    *                  if (cond_expr) then go to body_label
    *                  else                go to exit_label
    * <body_label>:
    *                  array expression
+   *
+   *                  (the increment, goto and exit_label goes from innermost to
+   *                   outermost).
    *                  ii++ and jj++
    *                  go to if_stmt_label
    * <exit_label>:
    *                  <REST OF CODE>
    */
+
   
-  add_stmt (build1 (LABEL_EXPR, void_type_node, if_stmt_label));
-  add_stmt (build3 (COND_EXPR, void_type_node, cond_expr,
-		    build1 (GOTO_EXPR, void_type_node, body_label),
-		    build1 (GOTO_EXPR, void_type_node, exit_label)));
+  for (ii = 0; ii < lhs_rank; ii++)
+    {
+      add_stmt (lhs_ind_init [ii]);
+      if (rhs_rank)
+	add_stmt (rhs_ind_init[ii]);
+      add_stmt (build1 (LABEL_EXPR, void_type_node, if_stmt_label[ii]));
+      add_stmt (build3 (COND_EXPR, void_type_node, cond_expr[ii],
+			build1 (GOTO_EXPR, void_type_node, body_label[ii]),
+			build1 (GOTO_EXPR, void_type_node, exit_label[ii])));
 
-  add_stmt (body_label_expr);
+      add_stmt (body_label_expr[ii]);
+    }
+  
   add_stmt (array_expr);
-  add_stmt (lhs_expr_incr);
-  if (rhs_expr_incr)
-    add_stmt (rhs_expr_incr);
+
+  for (ii = lhs_rank - 1; ii >= 0; ii--)
+    {
+      add_stmt (lhs_expr_incr[ii]);
+      if (rhs_rank && rhs_expr_incr[ii])
+	add_stmt (rhs_expr_incr[ii]);
   
-  add_stmt (build1 (GOTO_EXPR, void_type_node, if_stmt_label));
-  add_stmt (exit_label_expr);
+      add_stmt (build1 (GOTO_EXPR, void_type_node, if_stmt_label[ii]));
+      add_stmt (exit_label_expr[ii]);
+    }
    
   pop_stmt_list (loop);