--- /dev/null
+/* { dg-do run } */
+/* { dg-additional-options "-fno-tree-pre -fpredictive-commoning" } */
+
+static __attribute__ ((noipa)) void
+next_set(int *x, int n, int k)
+{
+ int j = k - 1;
+ int tmp = x[j]++;
+ while (j > 0)
+ {
+ if (x[j] < n - (k - 1 -j))
+ break;
+ j--;
+ x[j]++;
+ tmp = x[j];
+ }
+ if (tmp != 2 || j != 1 || x[0] != 0 || x[1] != 2 || x[2] != 5)
+ __builtin_abort ();
+}
+
+int main()
+{
+ int x[3] = {0, 1, 4};
+ next_set(x, 5, 3);
+ return 0;
+}
pcom_worker::find_looparound_phi (dref ref, dref root)
{
tree name, init, init_ref;
- gphi *phi = NULL;
gimple *init_stmt;
edge latch = loop_latch_edge (m_loop);
struct data_reference init_dr;
if (!name)
return NULL;
+ tree entry_vuse = NULL_TREE;
+ gphi *phi = NULL;
for (psi = gsi_start_phis (m_loop->header); !gsi_end_p (psi); gsi_next (&psi))
{
- phi = psi.phi ();
- if (PHI_ARG_DEF_FROM_EDGE (phi, latch) == name)
+ gphi *p = psi.phi ();
+ if (PHI_ARG_DEF_FROM_EDGE (p, latch) == name)
+ phi = p;
+ else if (virtual_operand_p (gimple_phi_result (p)))
+ entry_vuse = PHI_ARG_DEF_FROM_EDGE (p, loop_preheader_edge (m_loop));
+ if (phi && entry_vuse)
break;
}
-
- if (gsi_end_p (psi))
+ if (!phi || !entry_vuse)
return NULL;
init = PHI_ARG_DEF_FROM_EDGE (phi, loop_preheader_edge (m_loop));
if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
return NULL;
+ /* Make sure nothing clobbers the location we re-use the initial value
+ from. */
+ if (entry_vuse != gimple_vuse (init_stmt))
+ {
+ ao_ref ref;
+ ao_ref_init (&ref, init_ref);
+ unsigned limit = param_sccvn_max_alias_queries_per_access;
+ tree vdef = entry_vuse;
+ do
+ {
+ gimple *def = SSA_NAME_DEF_STMT (vdef);
+ if (limit-- == 0 || gimple_code (def) == GIMPLE_PHI)
+ return NULL;
+ if (stmt_may_clobber_ref_p_1 (def, &ref))
+ /* When the stmt is an assign to init_ref we could in theory
+ use its RHS for the initial value of the looparound PHI
+ we replace in prepare_initializers_chain, but we have
+ no convenient place to store this info at the moment. */
+ return NULL;
+ vdef = gimple_vuse (def);
+ }
+ while (vdef != gimple_vuse (init_stmt));
+ }
+
return phi;
}