Do we need to do a loop invariant motion after loop interchange ?

Li Jia He helijia@linux.ibm.com
Thu Feb 13 02:42:00 GMT 2020


Hi,

On 2019/11/25 5:55 PM, Bin.Cheng wrote:
> On Mon, Nov 25, 2019 at 5:29 PM Li Jia He <helijia@linux.ibm.com> wrote:
>>
>>
>>
>> On 2019/11/24 2:26 PM, Bin.Cheng wrote:
>>> On Fri, Nov 22, 2019 at 3:23 PM Bin.Cheng <amker.cheng@gmail.com> wrote:
>>>>
>>>> On Fri, Nov 22, 2019 at 3:19 PM Richard Biener
>>>> <richard.guenther@gmail.com> wrote:
>>>>>
>>>>> On November 22, 2019 6:51:38 AM GMT+01:00, Li Jia He <helijia@linux.ibm.com> wrote:
>>>>>>
>>>>>>
>>>>>> On 2019/11/21 8:10 PM, Richard Biener wrote:
>>>>>>> On Thu, Nov 21, 2019 at 10:22 AM Li Jia He <helijia@linux.ibm.com>
>>>>>> wrote:
>>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> I found for the follow code:
>>>>>>>>
>>>>>>>> #define N 256
>>>>>>>> int a[N][N][N], b[N][N][N];
>>>>>>>> int d[N][N], c[N][N];
>>>>>>>> void __attribute__((noinline))
>>>>>>>> double_reduc (int n)
>>>>>>>> {
>>>>>>>>       for (int k = 0; k < n; k++)
>>>>>>>>       {
>>>>>>>>         for (int l = 0; l < n; l++)
>>>>>>>>          {
>>>>>>>>            c[k][l] = 0;
>>>>>>>>             for (int m = 0; m < n; m++)
>>>>>>>>               c[k][l] += a[k][m][l] * d[k][m] + b[k][m][l] * d[k][m];
>>>>>>>>          }
>>>>>>>>       }
>>>>>>>> }
>>>>>>>>
>>>>>>>> I dumped the file after loop interchange and got the following
>>>>>> information:
>>>>>>>>
>>>>>>>> <bb 3> [local count: 118111600]:
>>>>>>>>       # m_46 = PHI <0(7), m_45(11)>
>>>>>>>>       # ivtmp_44 = PHI <_42(7), ivtmp_43(11)>
>>>>>>>>       _39 = _49 + 1;
>>>>>>>>
>>>>>>>>       <bb 4> [local count: 955630224]:
>>>>>>>>       # l_48 = PHI <0(3), l_47(12)>
>>>>>>>>       # ivtmp_41 = PHI <_39(3), ivtmp_40(12)>
>>>>>>>>       c_I_I_lsm.5_18 = c[k_28][l_48];
>>>>>>>>       c_I_I_lsm.5_53 = m_46 != 0 ? c_I_I_lsm.5_18 : 0;
>>>>>>>>       _2 = a[k_28][m_46][l_48];
>>>>>>>>       _3 = d[k_28][m_46];
>>>>>>>>       _4 = _2 * _3;
>>>>>>>>       _5 = b[k_28][m_46][l_48];
>>>>>>>>       _6 = _3 * _5;
>>>>>>>>       _7 = _4 + _6;
>>>>>>>>       _8 = _7 + c_I_I_lsm.5_53;
>>>>>>>>       c[k_28][l_48] = _8;
>>>>>>>>       l_47 = l_48 + 1;
>>>>>>>>       ivtmp_40 = ivtmp_41 - 1;
>>>>>>>>       if (ivtmp_40 != 0)
>>>>>>>>         goto <bb 12>; [89.00%]
>>>>>>>>       else
>>>>>>>>         goto <bb 5>; [11.00%]
>>>>>>>>
>>>>>>>> we can see '_3 = d[k_28][m_46];'  is a loop invariant.
>>>>>>>> Do we need to add a loop invariant motion pass after the loop
>>>>>> interchange?
>>>>>>>
>>>>>>> There is one at the end of the loop pipeline.
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> The one at the end of the loop pipeline may miss some optimization
>>>>>> opportunities.  If we vectorize the above code (a.c.158t.vect), we
>>>>>> can get information similar to the following:
>>>>>>
>>>>>> bb 3:
>>>>>>    # m_46 = PHI <0(7), m_45(11)>  // loop m, outer loop
>>>>>>     if (_59 <= 2)
>>>>>>       goto bb 20;
>>>>>>     else
>>>>>>       goto bb 15;
>>>>>>
>>>>>> bb 15:
>>>>>>     _89 = d[k_28][m_46];
>>>>>>     vect_cst__90 = {_89, _89, _89, _89};
>>>>>>
>>>>>> bb 4:
>>>>>>      # l_48 = PHI <l_47(12), 0(15)> // loop l, inner loop
>>>>>>     vect__6.23_100 = vect_cst__99 * vect__5.22_98;
>>>>>>      if (ivtmp_110 < bnd.8_1)
>>>>>>       goto bb 12;
>>>>>>     else
>>>>>>       goto bb 17;
>>>>>>
>>>>>> bb 20:
>>>>>> bb 18:
>>>>>>      _27 = d[k_28][m_46];
>>>>>> if (ivtmp_12 != 0)
>>>>>>       goto bb 19;
>>>>>>     else
>>>>>>       goto bb 21;
>>>>>>
>>>>>> Vectorization will do some conversions in this case.  We can see
>>>>>> ‘ _89 = d[k_28][m_46];’ and ‘_27 = d[k_28][m_46];’ are loop invariant
>>>>>> relative to loop l.  We can move ‘d[k_28][m_46]’ to the front of
>>>>>> ‘if (_59 <= 2)’ to get rid of loading data from memory in both
>>>>>> branches.
>>>>>>
>>>>>> The one at at the end of the loop pipeline can't handle this situation.
>>>>>> If we move d[k_28][m_46] from loop l to loop m before doing
>>>>>> vectorization, we can get rid of this situation.
>>>>>
>>>>> But we can't run every pass after every other. With multiple passes having ordering issues is inevitable.
>>>>>
>>>>> Now - interchange could trigger a region based invariant motion just for the nest it interchanged. But that doesn't exist right now.
>>>> With data reference/dependence information in the pass, I think it
>>>> could be quite straightforward.  Didn't realize that we need it
>>>> before.
>>> FYI, attachment is a simple fix in loop interchange for the reported
>>> issue. It's untested, neither for GCC10.
>>
>> Hi,
>>
>> Thank you for providing a patch so quickly. I did some tests for this
>> patch.
>> I found it will cause some test cases failed such as
>> testsuite/gfortran.dg/vect/pr81303.f.
> My bad. It fails because the patch only hoists memory reference, but
> not variables used by it.
> 

I have made some improvements on this basis, and will mention the variables
needed for memroy reference to the preheader.  The specific ideas are as
follows: We start from the offset of the memory reference, then search the
definition of the offset.  From the use of the variable to search the
definition of the variable until all the definitions of the variable are
outside of the loop or encounter a situation that cannot be handled.
<bb 13>:
     # l_32 = PHI <1(12), l_54(21)>  // loop l
     _36 = (integer(kind=8)) m_55;
     _37 = _36 * stride.88_111;
     _38 = _35 + _37;
     _39 = _26 + _38;
     _40 = (*a_137(D))[_39];
Suppose _40 is the memroy reference that needs to be processed.  The 
variables
searched here are _39, _26, _38, _35, _37, _36. And move them to the 
preheader
respectively.  The order is _36, _37, _35, _38, _39 (_26 not moved 
because its
definition is already outside the loop).

In addition, we may need to deal with the problem of memroy reference being
accessed multiple times in a loop.  The following is an example:
<bb 10>:
      # ivtmp_58 = PHI <_60(9), ivtmp_59(10)>
      _12 = i_52 + -1;
      _8 = (integer(kind=8)) _12;
      _4 = MEM[(integer(kind=4)[32] *)_18][_8];
      _16 = _4 + 1;
      MEM[(integer(kind=4)[32] *)_18][_8] = _16;
      ivtmp_59 = ivtmp_58 - 1;
      if (ivtmp_59 == 0)
         goto <bb 12>; [3.12%]
      else
          goto <bb 10>; [96.88%]
The variables used by MEM [(integer (kind = 4) [32] *) _ 18] [_ 8] are all
loop-independent.  It seems we can do code motion for this statement. 
However,
the value of MEM [(integer (kind = 4) [32] *) _ 18] [_ 8] will be read 
into _4
first, and its value will plus 1, then write its value back to
MEM [(integer ( kind = 4) [32] *) _ 18] [_ 8].  In this case, we should 
give up
doing code motion.

I'm not sure if this is the correct tracking of the issue.  Would you 
like to
give some suggestions ?  Thank you in advance.  Attachment is my fix 
based on
bin.cheng.

-- 
BR,
Lijia He
> Thanks,
> bin
>> And I also found that this patch can’t do loop invariant motion in some
>> cases.
>> Take pr81303.f as an example
>>
>> <bb 12> [local count: 118111600]:
>>     # m_55 = PHI <1(9), m_81(20)> // loop m, outer loop
>>     # ivtmp_82 = PHI <_167(9), ivtmp_169(20)>
>>     inv_temp_439 = (*x_138(D))[_94];
>>     inv_temp_440 = (*x_138(D))[_85];
>>     inv_temp_441 = (*x_138(D))[_76];
>>     inv_temp_442 = (*x_138(D))[_68];
>>     inv_temp_443 = (*x_138(D))[_58];
>>     inv_temp_444 = (*x_138(D))[_49];
>>     inv_temp_445 = (*x_138(D))[_41];
>>     _446 = _21 + 1;
>>
>>     <bb 13> [local count: 955630224]:
>>     # l_32 = PHI <1(12), l_54(21)>  // loop l, inner loop
>>     # ivtmp_165 = PHI <_446(12), ivtmp_155(21)>
>>     _26 = (integer(kind=8)) l_32;
>>     _27 = _25 + _26;
>>     y__I_lsm.119_136 = (*y_135(D))[_27];
>>     y__I_lsm.119_90 = m_55 != 1 ? y__I_lsm.119_136 : 0.0;
>>     _36 = (integer(kind=8)) m_55;
>>     _37 = _36 * stride.88_111;
>>     _38 = _35 + _37;
>>     _39 = _26 + _38;
>>     _40 = (*a_137(D))[_39];
>>     _41 = _25 + _36;
>>     _42 = inv_temp_445;
>>     _43 = _40 * _42;
>>     _45 = (*axp_139(D))[_39];
>>
>> We can see that variables such as inv_temp_439 moved to outer loop m.
>> However, loop invariants such as _36, _37 do not moved to outer loop m.
>>
>> --
>> BR,
>> Lijia He
>>
>>>
>>> Thanks,
>>> bin
>>>>
>>>> Thanks,
>>>> bin
>>>>>
>>>>> Richard.
>>
>>

-- 
BR,
Lijia He
-------------- next part --------------
diff --git a/gcc/gimple-loop-interchange.cc b/gcc/gimple-loop-interchange.cc
index 2379848808f..53fa199bf98 100644
--- a/gcc/gimple-loop-interchange.cc
+++ b/gcc/gimple-loop-interchange.cc
@@ -41,6 +41,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-dce.h"
 #include "tree-data-ref.h"
 #include "tree-vectorizer.h"
+#include "tree-eh.h"
 
 /* This pass performs loop interchange: for example, the loop nest
 
@@ -959,11 +960,13 @@ public:
   bool interchange (vec<data_reference_p>, vec<ddr_p>);
 
 private:
-  void update_data_info (unsigned, unsigned, vec<data_reference_p>, vec<ddr_p>);
+  void update_data_info (unsigned, unsigned, vec<data_reference_p>, vec<ddr_p>,
+			 bool);
   bool valid_data_dependences (unsigned, unsigned, vec<ddr_p>);
   void interchange_loops (loop_cand &, loop_cand &);
   void map_inductions_to_loop (loop_cand &, loop_cand &);
   void move_code_to_inner_loop (class loop *, class loop *, basic_block *);
+  void invariant_dataref_motion (vec<data_reference_p>);
 
   /* The whole loop nest in which interchange is ongoing.  */
   vec<class loop *> m_loop_nest;
@@ -978,13 +981,14 @@ private:
 };
 
 /* Update data refs' access stride and dependence information after loop
-   interchange.  I_IDX/O_IDX gives indices of interchanged loops in loop
-   nest.  DATAREFS are data references.  DDRS are data dependences.  */
+   interchange.  I_IDX/O_IDX gives indices of interchanged loops in loop nest.
+   DATAREFS are data references.  DDRS are data dependences which are only
+   updated if UPDATE_DDR_P is true.  */
 
 void
 tree_loop_interchange::update_data_info (unsigned i_idx, unsigned o_idx,
 					 vec<data_reference_p> datarefs,
-					 vec<ddr_p> ddrs)
+					 vec<ddr_p> ddrs, bool update_ddr_p)
 {
   struct data_reference *dr;
   struct data_dependence_relation *ddr;
@@ -996,6 +1000,10 @@ tree_loop_interchange::update_data_info (unsigned i_idx, unsigned o_idx,
       gcc_assert (stride->length () > i_idx);
       std::swap ((*stride)[i_idx], (*stride)[o_idx]);
     }
+
+  if (!update_ddr_p)
+    return;
+
   /* Update data dependences.  */
   for (unsigned i = 0; ddrs.iterate (i, &ddr); ++i)
     if (DDR_ARE_DEPENDENT (ddr) != chrec_known)
@@ -1268,6 +1276,296 @@ tree_loop_interchange::move_code_to_inner_loop (class loop *outer,
     }
 }
 
+/* If there is a simple load or store to a memory reference in STMT, returns
+   the location of the memory reference, and sets IS_STORE according to whether
+   it is a store or load.  Otherwise, returns NULL.  */
+
+static tree *
+simple_mem_ref_in_stmt (gimple *stmt, bool *is_store)
+{
+  tree *lhs, *rhs;
+
+  /* Recognize SSA_NAME = MEM and MEM = (SSA_NAME | invariant) patterns.  */
+  if (!gimple_assign_single_p (stmt))
+    return NULL;
+
+  lhs = gimple_assign_lhs_ptr (stmt);
+  rhs = gimple_assign_rhs1_ptr (stmt);
+
+  if (TREE_CODE (*lhs) == SSA_NAME && gimple_vuse (stmt))
+    {
+      *is_store = false;
+      return rhs;
+    }
+  else if (gimple_vdef (stmt)
+	   && (TREE_CODE (*rhs) == SSA_NAME || is_gimple_min_invariant (*rhs)))
+    {
+      *is_store = true;
+      return lhs;
+    }
+  else
+    return NULL;
+}
+
+/* If tree code of T is SSA_NAME return true.  Otherwise returns false.  If the
+   defination of T belongs to the LOOP, put its value to WORKLIST and VARIABLES.
+   */
+
+static bool
+can_search_definition (tree t, class loop *loop, vec<tree> *worklist,
+		       vec<tree> *variables)
+{
+  if (TREE_CODE (t) != SSA_NAME)
+    return false;
+  if (flow_bb_inside_loop_p (loop, gimple_bb (SSA_NAME_DEF_STMT (t))))
+    {
+      worklist->safe_push (t);
+      variables->safe_push (t);
+    }
+  return true;
+}
+
+
+/* This function is to search all variables used by memory references.  We start
+   from the offset of the memory reference, and then search the definition of
+   the offset. From the use of the variable to search the definition of the
+   variable until all the definitions of the variable are outside the loop or
+   encounter a situation that cannot be handled.  The follow is a example.
+   <bb 13>:
+    # l_32 = PHI <1(12), l_54(21)>  // loop l
+    _36 = (integer(kind=8)) m_55;
+    _37 = _36 * stride.88_111;
+    _38 = _35 + _37;
+    _39 = _26 + _38;
+    _40 = (*a_137(D))[_39];
+   We want to find all variables used by _40.  First, we find _40's offset is
+   _39.  Second, we search _39's definition which is _39 = _26 + _38. Do the
+   same search operations to _26 and _38 until all the variable definitions are
+   outside the loop or encounter a situation that cannot be handled.  */
+
+static bool
+search_variables_used_by_mem_ref (tree *mem, class loop *loop,
+				  vec<tree> *variables)
+{
+  gcc_assert (TREE_CODE (*mem) == ARRAY_REF);
+
+  tree ptr = TREE_OPERAND (*mem, 0);
+  tree off = TREE_OPERAND (*mem, 1);
+  if (TREE_CODE (ptr) != MEM_REF || TREE_CODE (off) != SSA_NAME)
+    return false;
+
+  /* Special case, the definition of offset is already outside of the loop.  */
+  if (!flow_bb_inside_loop_p (loop, gimple_bb (SSA_NAME_DEF_STMT (off))))
+    return true;
+
+  auto_vec<tree> worklist;
+  worklist.safe_push (off);
+  variables->safe_push (off);
+  while (!worklist.is_empty ())
+    {
+      tree t = worklist.pop ();
+      if (TREE_CODE (t) != SSA_NAME)
+	return false;
+
+      gimple *stmt = SSA_NAME_DEF_STMT (t);
+      if (!stmt
+	  || gimple_has_volatile_ops (stmt)
+	  || gimple_has_side_effects (stmt)
+	  || stmt_could_throw_p (cfun, stmt))
+	return false;
+
+      gassign *assign = dyn_cast<gassign *> (stmt);
+      if (!assign)
+	return false;
+
+      tree_code code = gimple_assign_rhs_code (assign);
+      switch (TREE_CODE_CLASS (code))
+	{
+	  case tcc_unary:
+	    {
+	      tree rhs1 = gimple_assign_rhs1 (assign);
+	      if (!can_search_definition (rhs1, loop, &worklist, variables))
+		return false;
+	    }
+	    break;
+	  case tcc_binary:
+	    {
+	      tree rhs1 = gimple_assign_rhs1 (assign);
+	      if (!can_search_definition (rhs1, loop, &worklist, variables))
+		return false;
+	      tree rhs2 = gimple_assign_rhs2 (assign);
+	      if (!can_search_definition (rhs2, loop, &worklist, variables))
+		return false;
+	    }
+	    break;
+	  default:
+	    return false;
+	}
+    }
+  return true;
+}
+
+/* Description of a memory reference.  */
+
+struct mem_ref
+{
+  tree *mem;
+  bool is_store;
+};
+
+static void
+init_mem_ref (mem_ref *m_ref, tree *mem, bool is_store)
+{
+  m_ref->mem = mem;
+  m_ref->is_store = is_store;
+}
+
+static void
+record_mem_ref (vec<mem_ref> *vec_mem_ref, tree *mem, bool is_store)
+{
+  mem_ref m_ref;
+  init_mem_ref (&m_ref, mem, is_store);
+  vec_mem_ref->safe_push (m_ref);
+}
+
+/* Calculate all memory references in LOOP.  */
+
+static void
+calculate_mem_ref_in_loop (class loop *loop, vec<mem_ref> *vec_mem_ref)
+{
+  basic_block *bbs = get_loop_body (loop);
+  for (unsigned i = 0; i < loop->num_nodes; i++)
+    {
+      basic_block bb = bbs[i];
+      for (gimple_stmt_iterator gsi = gsi_start_nondebug_bb (bb);
+	   !gsi_end_p (gsi); gsi_next_nondebug (&gsi))
+	{
+	  bool is_store = false;
+	  tree *mem = simple_mem_ref_in_stmt (gsi_stmt (gsi), &is_store);
+	  if (mem)
+	    record_mem_ref (vec_mem_ref, mem, is_store);
+	}
+    }
+  free (bbs);
+}
+
+/* Returns false if M_REF1 and M_REF2 are same memory reference.  Return true
+   if M_REF1 and M_REF2 may be aliases and at least one write to memory.
+   Otherwise, returns false.  */
+
+static bool
+mem_ref_may_dependent_p (mem_ref *m_ref1, mem_ref *m_ref2)
+{
+  /* Same memory reference.  */
+  if (m_ref1 == m_ref2)
+    return false;
+  return refs_may_alias_p (*m_ref1->mem, *m_ref2->mem, true)
+	 && (m_ref1->is_store || m_ref2->is_store);
+}
+
+/* Returns true if M_REF and all memory references in loop are independent.  */
+
+static bool
+mem_ref_indep_loop (mem_ref *m_ref, vec<mem_ref> *vec_mem_ref_in_loop)
+{
+  for (unsigned int i = 0; i < vec_mem_ref_in_loop->length (); i++)
+    if (mem_ref_may_dependent_p (m_ref, &((*vec_mem_ref_in_loop)[i])))
+      return false;
+  return true;
+}
+
+/* Do code motion for invariant dataref in DATAREFS after loop interchange.  */
+
+void
+tree_loop_interchange::invariant_dataref_motion (vec<data_reference_p> datarefs)
+{
+  struct data_reference *dr;
+
+  auto_vec<vec<mem_ref> > mem_ref_in_loops (m_loop_nest.length ());
+  for (unsigned i = 0; i < m_loop_nest.length (); i++)
+    {
+      vec<mem_ref> *vec_mem_ref_p = new vec<mem_ref> ();
+      mem_ref_in_loops.safe_insert (i, *vec_mem_ref_p);
+    }
+
+  for (unsigned i = 0; datarefs.iterate (i, &dr); ++i)
+    {
+      /* For now we only handle unconditional loads.  This could be easily
+	 extended to handle stores if needed.  */
+      if (DR_IS_WRITE (dr) | DR_IS_CONDITIONAL_IN_STMT (dr))
+	continue;
+
+      unsigned loop_idx = m_loop_nest.length ();
+      vec<tree> *stride = DR_ACCESS_STRIDE (dr);
+
+      gcc_assert (stride->length () == loop_idx);
+
+      while (loop_idx > 0 && integer_zerop ((*stride)[loop_idx - 1]))
+	--loop_idx;
+
+      if (loop_idx == m_loop_nest.length ())
+	continue;
+
+      /* Get preheader block of the outmost loop in which the data reference is
+	 an invariant.  */
+      basic_block preheader = loop_preheader_edge (m_loop_nest[loop_idx])->src;
+
+      bool is_store = false;
+      tree *mem = simple_mem_ref_in_stmt (DR_STMT (dr), &is_store);
+
+      if (mem)
+	{
+	  /* Now only deal with the case of ARRAY_REF.  */
+	  if (TREE_CODE (*mem) != ARRAY_REF)
+	    continue;
+
+	  if (mem_ref_in_loops[loop_idx].is_empty ())
+	    calculate_mem_ref_in_loop (m_loop_nest[loop_idx],
+				       &mem_ref_in_loops[loop_idx]);
+
+	  mem_ref m_ref;
+	  init_mem_ref (&m_ref, mem, is_store);
+	  /* Check if m_ref has the same memory access in the loop.  */
+	  if (!mem_ref_indep_loop (&m_ref, &mem_ref_in_loops[loop_idx]))
+	    continue;
+
+	  auto_vec<tree> variables;
+	  if (!search_variables_used_by_mem_ref (mem, m_loop_nest[loop_idx],
+						 &variables))
+	    continue;
+
+	  unsigned int i;
+	  tree t;
+	  /* Move variables to preheader by order of use of variables.  */
+	  FOR_EACH_VEC_ELT_REVERSE (variables, i, t)
+	    {
+	      gimple_stmt_iterator from = gsi_for_stmt (SSA_NAME_DEF_STMT (t));
+	      gsi_move_to_bb_end (&from, preheader);
+	    }
+	}
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "Move invariant data ref (ref: ");
+	  print_generic_expr (dump_file, DR_REF (dr), TDF_SLIM);
+	  fprintf (dump_file, ") to outer loop (idx: %d)\n", loop_idx);
+	}
+
+      gimple_stmt_iterator bsi = gsi_last_bb (preheader);
+      tree inv = make_temp_ssa_name (TREE_TYPE (DR_REF (dr)), DR_STMT (dr),
+				     "inv_temp");
+      gimple *init_stmt = gimple_build_assign (inv, DR_REF (dr));
+      gsi_insert_after (&bsi, init_stmt, GSI_NEW_STMT);
+
+      bsi = gsi_for_stmt (DR_STMT (dr));
+      gimple_assign_set_rhs_from_tree (&bsi, inv);
+      update_stmt (DR_STMT (dr));
+    }
+
+  for (unsigned i = 0; i < m_loop_nest.length (); i++)
+    mem_ref_in_loops[i].release();
+}
+
 /* Given data reference DR in LOOP_NEST, the function computes DR's access
    stride at each level of loop from innermost LOOP to outer.  On success,
    it saves access stride at each level loop in a vector which is pointed
@@ -1641,9 +1939,9 @@ tree_loop_interchange::interchange (vec<data_reference_p> datarefs,
 
 	  changed_p = true;
 	  interchange_loops (iloop, oloop);
-	  /* No need to update if there is no further loop interchange.  */
-	  if (o_idx > 0)
-	    update_data_info (i_idx, o_idx, datarefs, ddrs);
+	  /* No need to update data dependence relation if there is no further
+	     loop interchange.  */
+	  update_data_info (i_idx, o_idx, datarefs, ddrs, o_idx > 0);
 	}
       else
 	{
@@ -1655,9 +1953,14 @@ tree_loop_interchange::interchange (vec<data_reference_p> datarefs,
     }
   simple_dce_from_worklist (m_dce_seeds);
 
-  if (changed_p && dump_enabled_p ())
-    dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
-		     "loops interchanged in loop nest\n");
+  if (changed_p)
+    {
+      if (dump_enabled_p ())
+	dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+			 "loops interchanged in loop nest\n");
+
+      invariant_dataref_motion (datarefs);
+    }
 
   return changed_p;
 }


More information about the Gcc mailing list