diff options
Diffstat (limited to 'gcc/tree-predcom.cc')
-rw-r--r-- | gcc/tree-predcom.cc | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/gcc/tree-predcom.cc b/gcc/tree-predcom.cc index bb3a1cb68fc..fb457250bbd 100644 --- a/gcc/tree-predcom.cc +++ b/gcc/tree-predcom.cc @@ -1377,7 +1377,6 @@ gphi * 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; @@ -1395,14 +1394,19 @@ pcom_worker::find_looparound_phi (dref ref, dref root) 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)); @@ -1430,6 +1434,30 @@ pcom_worker::find_looparound_phi (dref ref, dref root) 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; } |