OSDN Git Service

* tree-ssa-dom.c (simplify_rhs_and_lookup_avail_expr): Do not
[pf3gnuchains/gcc-fork.git] / gcc / tree-data-ref.c
index 1848128..10a223e 100644 (file)
@@ -479,13 +479,11 @@ base_addr_differ_p (struct data_reference *dra,
 /* Returns true iff A divides B.  */
 
 static inline bool 
-tree_fold_divides_p (tree type, 
-                    tree a, 
+tree_fold_divides_p (tree a, 
                     tree b)
 {
   /* Determines whether (A == gcd (A, B)).  */
-  return integer_zerop 
-    (fold_build2 (MINUS_EXPR, type, a, tree_fold_gcd (a, b)));
+  return tree_int_cst_equal (a, tree_fold_gcd (a, b));
 }
 
 /* Compute the greatest common denominator of two numbers using
@@ -628,6 +626,7 @@ dump_data_dependence_relation (FILE *outf,
   else if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
     {
       unsigned int i;
+
       for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
        {
          fprintf (outf, "  access_fn_A: ");
@@ -636,15 +635,19 @@ dump_data_dependence_relation (FILE *outf,
          print_generic_stmt (outf, DR_ACCESS_FN (drb, i), 0);
          dump_subscript (outf, DDR_SUBSCRIPT (ddr, i));
        }
-      if (DDR_DIST_VECT (ddr))
+
+      for (i = 0; i < DDR_NUM_DIST_VECTS (ddr); i++)
        {
-         fprintf (outf, "  distance_vect: ");
-         print_lambda_vector (outf, DDR_DIST_VECT (ddr), DDR_SIZE_VECT (ddr));
+         fprintf (outf, "  distance_vector: ");
+         print_lambda_vector (outf, DDR_DIST_VECT (ddr, i),
+                              DDR_SIZE_VECT (ddr));
        }
-      if (DDR_DIR_VECT (ddr))
+
+      for (i = 0; i < DDR_NUM_DIR_VECTS (ddr); i++)
        {
-         fprintf (outf, "  direction_vect: ");
-         print_lambda_vector (outf, DDR_DIR_VECT (ddr), DDR_SIZE_VECT (ddr));
+         fprintf (outf, "  direction_vector: ");
+         print_lambda_vector (outf, DDR_DIR_VECT (ddr, i),
+                              DDR_SIZE_VECT (ddr));
        }
     }
 
@@ -702,7 +705,7 @@ dump_data_dependence_direction (FILE *file,
 void 
 dump_dist_dir_vectors (FILE *file, varray_type ddrs)
 {
-  unsigned int i;
+  unsigned int i, j;
 
   for (i = 0; i < VARRAY_ACTIVE_SIZE (ddrs); i++)
     {
@@ -712,12 +715,21 @@ dump_dist_dir_vectors (FILE *file, varray_type ddrs)
       if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE
          && DDR_AFFINE_P (ddr))
        {
-         fprintf (file, "DISTANCE_V (");
-         print_lambda_vector (file, DDR_DIST_VECT (ddr), DDR_SIZE_VECT (ddr));
-         fprintf (file, ")\n");
-         fprintf (file, "DIRECTION_V (");
-         print_lambda_vector (file, DDR_DIR_VECT (ddr), DDR_SIZE_VECT (ddr));
-         fprintf (file, ")\n");
+         for (j = 0; j < DDR_NUM_DIST_VECTS (ddr); j++)
+           {
+             fprintf (file, "DISTANCE_V (");
+             print_lambda_vector (file, DDR_DIST_VECT (ddr, j),
+                                  DDR_SIZE_VECT (ddr));
+             fprintf (file, ")\n");
+           }
+
+         for (j = 0; j < DDR_NUM_DIR_VECTS (ddr); j++)
+           {
+             fprintf (file, "DIRECTION_V (");
+             print_lambda_vector (file, DDR_DIR_VECT (ddr, j),
+                                  DDR_SIZE_VECT (ddr));
+             fprintf (file, ")\n");
+           }
        }
     }
   fprintf (file, "\n\n");
@@ -801,13 +813,16 @@ estimate_niter_from_size_of_data (struct loop *loop,
 /* Given an ARRAY_REF node REF, records its access functions.
    Example: given A[i][3], record in ACCESS_FNS the opnd1 function,
    i.e. the constant "3", then recursively call the function on opnd0,
-   i.e. the ARRAY_REF "A[i]".  The function returns the base name:
-   "A".  */
+   i.e. the ARRAY_REF "A[i]".  
+   If ESTIMATE_ONLY is true, we just set the estimated number of loop
+   iterations, we don't store the access function.
+   The function returns the base name: "A".  */
 
 static tree
 analyze_array_indexes (struct loop *loop,
                       VEC(tree,heap) **access_fns, 
-                      tree ref, tree stmt)
+                      tree ref, tree stmt,
+                      bool estimate_only)
 {
   tree opnd0, opnd1;
   tree access_fn;
@@ -822,20 +837,32 @@ analyze_array_indexes (struct loop *loop,
   access_fn = instantiate_parameters 
     (loop, analyze_scalar_evolution (loop, opnd1));
 
-  if (chrec_contains_undetermined (loop->estimated_nb_iterations))
+  if (estimate_only 
+      && chrec_contains_undetermined (loop->estimated_nb_iterations))
     estimate_niter_from_size_of_data (loop, opnd0, access_fn, stmt);
-  
-  VEC_safe_push (tree, heap, *access_fns, access_fn);
+
+  if (!estimate_only)
+    VEC_safe_push (tree, heap, *access_fns, access_fn);
   
   /* Recursively record other array access functions.  */
   if (TREE_CODE (opnd0) == ARRAY_REF)
-    return analyze_array_indexes (loop, access_fns, opnd0, stmt);
+    return analyze_array_indexes (loop, access_fns, opnd0, stmt, estimate_only);
   
   /* Return the base name of the data access.  */
   else
     return opnd0;
 }
 
+/* For an array reference REF contained in STMT, attempt to bound the
+   number of iterations in the loop containing STMT  */
+
+void 
+estimate_iters_using_array (tree stmt, tree ref)
+{
+  analyze_array_indexes (loop_containing_stmt (stmt), NULL, ref, stmt, 
+                        true);
+}
+  
 /* For a data reference REF contained in the statement STMT, initialize
    a DATA_REFERENCE structure, and return it.  IS_READ flag has to be
    set to true when REF is in the right hand side of an
@@ -861,7 +888,7 @@ analyze_array (tree stmt, tree ref, bool is_read)
   DR_REF (res) = ref;
   acc_fns = VEC_alloc (tree, heap, 3);
   DR_BASE_OBJECT (res) = analyze_array_indexes 
-    (loop_containing_stmt (stmt), &acc_fns, ref, stmt);
+    (loop_containing_stmt (stmt), &acc_fns, ref, stmt, false);
   DR_TYPE (res) = ARRAY_REF_TYPE;
   DR_SET_ACCESS_FNS (res, acc_fns);
   DR_IS_READ (res) = is_read;
@@ -1111,7 +1138,7 @@ analyze_offset_expr (tree expr,
        return false;
 
       init = initial_condition_in_loop_num (access_fn, loop->num);
-      if (init == expr && !expr_invariant_in_loop_p (loop, init))
+      if (!expr_invariant_in_loop_p (loop, init))
        /* Not enough information: may be not loop invariant.  
           E.g., for a[b[i]], we get a[D], where D=b[i]. EXPR is D, its 
           initial_condition is D, but it depends on i - loop's induction
@@ -1723,7 +1750,7 @@ analyze_offset (tree offset, tree *invariant, tree *constant)
   *constant = constant_0 ? constant_0 : constant_1;
   if (invariant_0 && invariant_1)
     *invariant = 
-      fold (build (code, TREE_TYPE (invariant_0), invariant_0, invariant_1));
+      fold_build2 (code, TREE_TYPE (invariant_0), invariant_0, invariant_1);
   else
     *invariant = invariant_0 ? invariant_0 : invariant_1;
 }
@@ -1805,8 +1832,8 @@ create_data_ref (tree memref, tree stmt, bool is_read)
       if (constant)
        {
          DR_INIT (dr) = fold_convert (ssizetype, constant);
-         init_cond = fold (build (TRUNC_DIV_EXPR, TREE_TYPE (constant), 
-                                  constant, type_size));
+         init_cond = fold_build2 (TRUNC_DIV_EXPR, TREE_TYPE (constant), 
+                                  constant, type_size);
        }
       else
        DR_INIT (dr) = init_cond = ssize_int (0);;
@@ -1986,9 +2013,9 @@ initialize_data_dependence_relation (struct data_reference *a,
   DDR_ARE_DEPENDENT (res) = NULL_TREE;
   DDR_SUBSCRIPTS_VECTOR_INIT (res, DR_NUM_DIMENSIONS (a));
   DDR_SIZE_VECT (res) = 0;
-  DDR_DIST_VECT (res) = NULL;
-  DDR_DIR_VECT (res) = NULL;
-      
+  DDR_DIR_VECTS (res) = NULL;
+  DDR_DIST_VECTS (res) = NULL;
+
   for (i = 0; i < DR_NUM_DIMENSIONS (a); i++)
     {
       struct subscript *subscript;
@@ -2140,6 +2167,22 @@ analyze_ziv_subscript (tree chrec_a,
     fprintf (dump_file, ")\n");
 }
 
+/* Get the real or estimated number of iterations for LOOPNUM, whichever is
+   available. Return the number of iterations as a tree, or NULL_TREE if
+   we don't know.  */
+
+static tree
+get_number_of_iters_for_loop (int loopnum)
+{
+  tree numiter = number_of_iterations_in_loop (current_loops->parray[loopnum]);
+
+  if (TREE_CODE (numiter) != INTEGER_CST)
+    numiter = current_loops->parray[loopnum]->estimated_nb_iterations;
+  if (chrec_contains_undetermined (numiter))
+    return NULL_TREE;
+  return numiter;
+}
+    
 /* Analyze a SIV (Single Index Variable) subscript where CHREC_A is a
    constant, and CHREC_B is an affine function.  *OVERLAPS_A and
    *OVERLAPS_B are initialized to the functions that describe the
@@ -2186,9 +2229,11 @@ analyze_siv_subscript_cst_affine (tree chrec_a,
                     chrec_b = {10, +, 1}
                  */
                  
-                 if (tree_fold_divides_p 
-                     (integer_type_node, CHREC_RIGHT (chrec_b), difference))
+                 if (tree_fold_divides_p (CHREC_RIGHT (chrec_b), difference))
                    {
+                     tree numiter;
+                     int loopnum = CHREC_VARIABLE (chrec_b);
+
                      *overlaps_a = integer_zero_node;
                      *overlaps_b = fold_build2 (EXACT_DIV_EXPR, integer_type_node,
                                                 fold_build1 (ABS_EXPR,
@@ -2196,10 +2241,25 @@ analyze_siv_subscript_cst_affine (tree chrec_a,
                                                              difference),
                                                 CHREC_RIGHT (chrec_b));
                      *last_conflicts = integer_one_node;
+                     
+
+                     /* Perform weak-zero siv test to see if overlap is
+                        outside the loop bounds.  */
+                     numiter = get_number_of_iters_for_loop (loopnum);
+
+                     if (numiter != NULL_TREE
+                         && TREE_CODE (*overlaps_b) == INTEGER_CST
+                         && tree_int_cst_lt (numiter, *overlaps_b))
+                       {
+                         *overlaps_a = chrec_known;
+                         *overlaps_b = chrec_known;
+                         *last_conflicts = integer_zero_node;
+                         return;
+                       }               
                      return;
                    }
                  
-                 /* When the step does not divides the difference, there are
+                 /* When the step does not divide the difference, there are
                     no overlaps.  */
                  else
                    {
@@ -2241,18 +2301,34 @@ analyze_siv_subscript_cst_affine (tree chrec_a,
                     chrec_a = 3
                     chrec_b = {10, +, -1}
                  */
-                 if (tree_fold_divides_p 
-                     (integer_type_node, CHREC_RIGHT (chrec_b), difference))
+                 if (tree_fold_divides_p (CHREC_RIGHT (chrec_b), difference))
                    {
+                     tree numiter;
+                     int loopnum = CHREC_VARIABLE (chrec_b);
+
                      *overlaps_a = integer_zero_node;
-                     *overlaps_b = fold 
-                       (build (EXACT_DIV_EXPR, integer_type_node, difference, 
-                               CHREC_RIGHT (chrec_b)));
+                     *overlaps_b = fold_build2 (EXACT_DIV_EXPR,
+                                                integer_type_node, difference, 
+                                                CHREC_RIGHT (chrec_b));
                      *last_conflicts = integer_one_node;
+
+                     /* Perform weak-zero siv test to see if overlap is
+                        outside the loop bounds.  */
+                     numiter = get_number_of_iters_for_loop (loopnum);
+
+                     if (numiter != NULL_TREE
+                         && TREE_CODE (*overlaps_b) == INTEGER_CST
+                         && tree_int_cst_lt (numiter, *overlaps_b))
+                       {
+                         *overlaps_a = chrec_known;
+                         *overlaps_b = chrec_known;
+                         *last_conflicts = integer_zero_node;
+                         return;
+                       }       
                      return;
                    }
                  
-                 /* When the step does not divides the difference, there
+                 /* When the step does not divide the difference, there
                     are no overlaps.  */
                  else
                    {
@@ -2372,29 +2448,12 @@ compute_overlap_steps_for_affine_1_2 (tree chrec_a, tree chrec_b,
   step_y = int_cst_value (CHREC_RIGHT (chrec_a));
   step_z = int_cst_value (CHREC_RIGHT (chrec_b));
 
-  numiter_x = number_of_iterations_in_loop 
-    (current_loops->parray[CHREC_VARIABLE (CHREC_LEFT (chrec_a))]);
-  numiter_y = number_of_iterations_in_loop 
-    (current_loops->parray[CHREC_VARIABLE (chrec_a)]);
-  numiter_z = number_of_iterations_in_loop 
-    (current_loops->parray[CHREC_VARIABLE (chrec_b)]);
-
-  if (TREE_CODE (numiter_x) != INTEGER_CST)
-    numiter_x = current_loops->parray[CHREC_VARIABLE (CHREC_LEFT (chrec_a))]
-      ->estimated_nb_iterations;
-  if (TREE_CODE (numiter_y) != INTEGER_CST)
-    numiter_y = current_loops->parray[CHREC_VARIABLE (chrec_a)]
-      ->estimated_nb_iterations;
-  if (TREE_CODE (numiter_z) != INTEGER_CST)
-    numiter_z = current_loops->parray[CHREC_VARIABLE (chrec_b)]
-      ->estimated_nb_iterations;
-
-  if (chrec_contains_undetermined (numiter_x)
-      || chrec_contains_undetermined (numiter_y)
-      || chrec_contains_undetermined (numiter_z)
-      || TREE_CODE (numiter_x) != INTEGER_CST
-      || TREE_CODE (numiter_y) != INTEGER_CST
-      || TREE_CODE (numiter_z) != INTEGER_CST)
+  numiter_x = get_number_of_iters_for_loop (CHREC_VARIABLE (CHREC_LEFT (chrec_a)));
+  numiter_y = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_a));
+  numiter_z = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_b));
+  
+  if (numiter_x == NULL_TREE || numiter_y == NULL_TREE 
+      || numiter_z == NULL_TREE)
     {
       *overlaps_a = chrec_dont_know;
       *overlaps_b = chrec_dont_know;
@@ -2487,7 +2546,17 @@ analyze_subscript_affine_affine (tree chrec_a,
   int init_a, init_b, gamma, gcd_alpha_beta;
   int tau1, tau2;
   lambda_matrix A, U, S;
+  tree difference = chrec_fold_minus (integer_type_node, chrec_a, chrec_b);
 
+  if (integer_zerop (difference))
+    {
+      /* The difference is equal to zero: the accessed index
+        overlaps for each iteration in the loop.  */
+      *overlaps_a = integer_zero_node;
+      *overlaps_b = integer_zero_node;
+      *last_conflicts = chrec_dont_know;
+      return;
+    }
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "(analyze_subscript_affine_affine \n");
   
@@ -2531,21 +2600,9 @@ analyze_subscript_affine_affine (tree chrec_a,
          int niter, niter_a, niter_b;
          tree numiter_a, numiter_b;
 
-         numiter_a = number_of_iterations_in_loop 
-           (current_loops->parray[CHREC_VARIABLE (chrec_a)]);
-         numiter_b = number_of_iterations_in_loop 
-           (current_loops->parray[CHREC_VARIABLE (chrec_b)]);
-
-         if (TREE_CODE (numiter_a) != INTEGER_CST)
-           numiter_a = current_loops->parray[CHREC_VARIABLE (chrec_a)]
-             ->estimated_nb_iterations;
-         if (TREE_CODE (numiter_b) != INTEGER_CST)
-           numiter_b = current_loops->parray[CHREC_VARIABLE (chrec_b)]
-             ->estimated_nb_iterations;
-         if (chrec_contains_undetermined (numiter_a)
-             || chrec_contains_undetermined (numiter_b)
-             || TREE_CODE (numiter_a) != INTEGER_CST
-             || TREE_CODE (numiter_b) != INTEGER_CST)
+         numiter_a = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_a));
+         numiter_b = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_b));
+         if (numiter_a == NULL_TREE || numiter_b == NULL_TREE)
            {
              *overlaps_a = chrec_dont_know;
              *overlaps_b = chrec_dont_know;
@@ -2635,21 +2692,10 @@ analyze_subscript_affine_affine (tree chrec_a,
          int niter, niter_a, niter_b;
          tree numiter_a, numiter_b;
 
-         numiter_a = number_of_iterations_in_loop 
-           (current_loops->parray[CHREC_VARIABLE (chrec_a)]);
-         numiter_b = number_of_iterations_in_loop 
-           (current_loops->parray[CHREC_VARIABLE (chrec_b)]);
-
-         if (TREE_CODE (numiter_a) != INTEGER_CST)
-           numiter_a = current_loops->parray[CHREC_VARIABLE (chrec_a)]
-             ->estimated_nb_iterations;
-         if (TREE_CODE (numiter_b) != INTEGER_CST)
-           numiter_b = current_loops->parray[CHREC_VARIABLE (chrec_b)]
-             ->estimated_nb_iterations;
-         if (chrec_contains_undetermined (numiter_a)
-             || chrec_contains_undetermined (numiter_b)
-             || TREE_CODE (numiter_a) != INTEGER_CST
-             || TREE_CODE (numiter_b) != INTEGER_CST)
+         numiter_a = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_a));
+         numiter_b = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_b));
+
+         if (numiter_a == NULL_TREE || numiter_b == NULL_TREE)
            {
              *overlaps_a = chrec_dont_know;
              *overlaps_b = chrec_dont_know;
@@ -2705,15 +2751,27 @@ analyze_subscript_affine_affine (tree chrec_a,
                      tau1 = (x0 - i0)/i1;
                      last_conflict = tau2 - tau1;
 
-                     *overlaps_a = build_polynomial_chrec
-                       (1,
-                        build_int_cst (NULL_TREE, x0),
-                        build_int_cst (NULL_TREE, i1));
-                     *overlaps_b = build_polynomial_chrec
-                       (1,
-                        build_int_cst (NULL_TREE, y0),
-                        build_int_cst (NULL_TREE, j1));
-                     *last_conflicts = build_int_cst (NULL_TREE, last_conflict);
+                     /* If the overlap occurs outside of the bounds of the
+                        loop, there is no dependence.  */
+                     if (x0 > niter || y0  > niter)
+
+                       {
+                         *overlaps_a = chrec_known;
+                         *overlaps_b = chrec_known;
+                         *last_conflicts = integer_zero_node;
+                       }
+                     else
+                       {
+                         *overlaps_a = build_polynomial_chrec
+                           (1,
+                            build_int_cst (NULL_TREE, x0),
+                            build_int_cst (NULL_TREE, i1));
+                         *overlaps_b = build_polynomial_chrec
+                           (1,
+                            build_int_cst (NULL_TREE, y0),
+                            build_int_cst (NULL_TREE, j1));
+                         *last_conflicts = build_int_cst (NULL_TREE, last_conflict);
+                       }
                    }
                  else
                    {
@@ -2816,7 +2874,7 @@ chrec_steps_divide_constant_p (tree chrec,
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
-      return (tree_fold_divides_p (integer_type_node, CHREC_RIGHT (chrec), cst)
+      return (tree_fold_divides_p (CHREC_RIGHT (chrec), cst)
              && chrec_steps_divide_constant_p (CHREC_LEFT (chrec), cst));
       
     default:
@@ -2860,8 +2918,8 @@ analyze_miv_subscript (tree chrec_a,
         in the same order.  */
       *overlaps_a = integer_zero_node;
       *overlaps_b = integer_zero_node;
-      *last_conflicts = number_of_iterations_in_loop 
-       (current_loops->parray[CHREC_VARIABLE (chrec_a)]);
+      *last_conflicts = get_number_of_iters_for_loop (CHREC_VARIABLE (chrec_a));
+      
     }
   
   else if (evolution_function_is_constant_p (difference)
@@ -3034,8 +3092,8 @@ subscript_dependence_tester (struct data_dependence_relation *ddr)
    NB_LOOPS is the total number of loops we are considering.
    FIRST_LOOP_DEPTH is the loop->depth of the first loop in the analyzed
    loop nest.  
-   Return FALSE if the dependence relation is outside of the loop nest
-   starting at FIRST_LOOP_DEPTH. 
+   Return FALSE when fail to represent the data dependence as a distance
+   vector.
    Return TRUE otherwise.  */
 
 static bool
@@ -3044,7 +3102,9 @@ build_classic_dist_vector (struct data_dependence_relation *ddr,
 {
   unsigned i;
   lambda_vector dist_v, init_v;
+  bool init_b = false;
   
+  DDR_SIZE_VECT (ddr) = nb_loops;
   dist_v = lambda_vector_new (nb_loops);
   init_v = lambda_vector_new (nb_loops);
   lambda_vector_clear (dist_v, nb_loops);
@@ -3142,9 +3202,38 @@ build_classic_dist_vector (struct data_dependence_relation *ddr,
 
          dist_v[loop_depth] = dist;
          init_v[loop_depth] = 1;
+         init_b = true;
        }
     }
-  
+
+  /* Save the distance vector if we initialized one.  */
+  if (init_b)
+    {
+      lambda_vector save_v;
+
+      /* Verify a basic constraint: classic distance vectors should always
+        be lexicographically positive.  */
+      if (!lambda_vector_lexico_pos (dist_v, DDR_SIZE_VECT (ddr)))
+       {
+         if (DDR_SIZE_VECT (ddr) == 1)
+           /* This one is simple to fix, and can be fixed.
+              Multidimensional arrays cannot be fixed that simply.  */
+           lambda_vector_negate (dist_v, dist_v, DDR_SIZE_VECT (ddr));
+         else
+           /* This is not valid: we need the delta test for properly
+              fixing all this.  */
+           return false;
+       }
+
+      save_v = lambda_vector_new (DDR_SIZE_VECT (ddr));
+      lambda_vector_copy (dist_v, save_v, DDR_SIZE_VECT (ddr));
+      VEC_safe_push (lambda_vector, heap, DDR_DIST_VECTS (ddr), save_v);
+
+      /* There is nothing more to do when there are no outer loops.  */
+      if (DDR_SIZE_VECT (ddr) == 1)
+       goto classic_dist_done;
+    }
+
   /* There is a distance of 1 on all the outer loops: 
      
      Example: there is a dependence of distance 1 on loop_1 for the array A.
@@ -3162,44 +3251,65 @@ build_classic_dist_vector (struct data_dependence_relation *ddr,
     
     /* Get the common ancestor loop.  */
     lca = find_common_loop (loop_a, loop_b); 
-    
-    lca_depth = lca->depth;
-    lca_depth -= first_loop_depth;
+    lca_depth = lca->depth - first_loop_depth;
+
     gcc_assert (lca_depth >= 0);
     gcc_assert (lca_depth < nb_loops);
-
+    
     /* For each outer loop where init_v is not set, the accesses are
        in dependence of distance 1 in the loop.  */
-    if (lca != loop_a
-       && lca != loop_b
-       && init_v[lca_depth] == 0)
-      dist_v[lca_depth] = 1;
-    
-    lca = lca->outer;
-    
-    if (lca)
+    while (lca->depth != 0)
       {
-       lca_depth = lca->depth - first_loop_depth;
-       while (lca->depth != 0)
-         {
-           /* If we're considering just a sub-nest, then don't record
-              any information on the outer loops.  */
-           if (lca_depth < 0)
-             break;
+       /* If we're considering just a sub-nest, then don't record
+          any information on the outer loops.  */
+       if (lca_depth < 0)
+         break;
 
-           gcc_assert (lca_depth < nb_loops);
+       gcc_assert (lca_depth < nb_loops);
 
-           if (init_v[lca_depth] == 0)
-             dist_v[lca_depth] = 1;
-           lca = lca->outer;
-           lca_depth = lca->depth - first_loop_depth;
-         
+       /* If we haven't yet determined a distance for this outer
+          loop, push a new distance vector composed of the previous
+          distance, and a distance of 1 for this outer loop.
+          Example:
+
+          | loop_1
+          |   loop_2
+          |     A[10]
+          |   endloop_2
+          | endloop_1
+
+          Saved vectors are of the form (dist_in_1, dist_in_2).
+          First, we save (0, 1), then we have to save (1, 0).  */
+       if (init_v[lca_depth] == 0)
+         {
+           lambda_vector save_v = lambda_vector_new (DDR_SIZE_VECT (ddr));
+
+           lambda_vector_copy (dist_v, save_v, DDR_SIZE_VECT (ddr));
+           save_v[lca_depth] = 1;
+           VEC_safe_push (lambda_vector, heap, DDR_DIST_VECTS (ddr), save_v);
          }
+
+       lca = lca->outer;
+       lca_depth = lca->depth - first_loop_depth;
       }
   }
-  
-  DDR_DIST_VECT (ddr) = dist_v;
-  DDR_SIZE_VECT (ddr) = nb_loops;
+
+ classic_dist_done:;
+
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "(build_classic_dist_vector\n");
+
+      for (i = 0; i < DDR_NUM_DIST_VECTS (ddr); i++)
+       {
+         fprintf (dump_file, "  dist_vector = (");
+         print_lambda_vector (dump_file, DDR_DIST_VECT (ddr, i),
+                              DDR_SIZE_VECT (ddr));
+         fprintf (dump_file, "  )\n");
+       }
+      fprintf (dump_file, ")\n");
+    }
+
   return true;
 }
 
@@ -3219,11 +3329,14 @@ build_classic_dir_vector (struct data_dependence_relation *ddr,
 {
   unsigned i;
   lambda_vector dir_v, init_v;
+  bool init_b = false;
   
   dir_v = lambda_vector_new (nb_loops);
   init_v = lambda_vector_new (nb_loops);
   lambda_vector_clear (dir_v, nb_loops);
   lambda_vector_clear (init_v, nb_loops);
+
+  DDR_SIZE_VECT (ddr) = nb_loops;
   
   if (DDR_ARE_DEPENDENT (ddr) != NULL_TREE)
     return true;
@@ -3327,9 +3440,19 @@ build_classic_dir_vector (struct data_dependence_relation *ddr,
          
          dir_v[loop_depth] = dir;
          init_v[loop_depth] = 1;
+         init_b = true;
        }
     }
-  
+
+  /* Save the direction vector if we initialized one.  */
+  if (init_b)
+    {
+      lambda_vector save_v = lambda_vector_new (DDR_SIZE_VECT (ddr));
+
+      lambda_vector_copy (dir_v, save_v, DDR_SIZE_VECT (ddr));
+      VEC_safe_push (lambda_vector, heap, DDR_DIR_VECTS (ddr), save_v);
+    }
+
   /* There is a distance of 1 on all the outer loops: 
      
      Example: there is a dependence of distance 1 on loop_1 for the array A.
@@ -3352,37 +3475,30 @@ build_classic_dir_vector (struct data_dependence_relation *ddr,
     gcc_assert (lca_depth >= 0);
     gcc_assert (lca_depth < nb_loops);
 
-    /* For each outer loop where init_v is not set, the accesses are
-       in dependence of distance 1 in the loop.  */
-    if (lca != loop_a
-       && lca != loop_b
-       && init_v[lca_depth] == 0)
-      dir_v[lca_depth] = dir_positive;
-    
-    lca = lca->outer;
-    if (lca)
+    while (lca->depth != 0)
       {
-       lca_depth = lca->depth - first_loop_depth;
-       while (lca->depth != 0)
+       /* If we're considering just a sub-nest, then don't record
+          any information on the outer loops.  */
+       if (lca_depth < 0)
+         break;
+
+       gcc_assert (lca_depth < nb_loops);
+
+       if (init_v[lca_depth] == 0)
          {
-           /* If we're considering just a sub-nest, then don't record
-              any information on the outer loops.  */
-           if (lca_depth < 0)
-             break;
+           lambda_vector save_v = lambda_vector_new (DDR_SIZE_VECT (ddr));
 
-           gcc_assert (lca_depth < nb_loops);
+           lambda_vector_copy (dir_v, save_v, DDR_SIZE_VECT (ddr));
+           save_v[lca_depth] = dir_positive;
+           VEC_safe_push (lambda_vector, heap, DDR_DIR_VECTS (ddr), save_v);
+         }
 
-           if (init_v[lca_depth] == 0)
-             dir_v[lca_depth] = dir_positive;
-           lca = lca->outer;
-           lca_depth = lca->depth - first_loop_depth;
+       lca = lca->outer;
+       lca_depth = lca->depth - first_loop_depth;
           
-         }
       }
   }
-  
-  DDR_DIR_VECT (ddr) = dir_v;
-  DDR_SIZE_VECT (ddr) = nb_loops;
+
   return true;
 }