On Wed, 23 Oct 2013, Jakub Jelinek wrote: > On Tue, Oct 22, 2013 at 12:47:41PM -0600, Jeff Law wrote: > > On 10/22/13 07:09, Jakub Jelinek wrote: > > >I've spent over two days looking at reassoc, fixing spots where > > >we invalidly reused SSA_NAMEs (this results in wrong-debug, as the added > > >guality testcases show, even some ICEs (pr58791-3.c) and wrong range info > > >for SSA_NAMEs) > > > This is something we all need to remember, directly reusing an > > existing SSA_NAME for a new value and the like this is bad. It's > > far better to release the name back to the manager and grab a new > > one. > > For debug info quality it actually isn't just about using different > SSA_NAME, but also not reusing the defining stmt; only then the code > will magically try to create debug temporaries and expressions from the old > dead defining stmt. > > > >-/* Returns the UID of STMT if it is non-NULL. Otherwise return 1. */ > > >+/* Returns true if statement S1 dominates statement S2. Like > > >+ stmt_dominates_stmt_p, but uses stmt UIDs to optimize. */ > > > > > >-static inline unsigned > > >-get_stmt_uid_with_default (gimple stmt) > > >+static bool > > >+reassoc_stmt_dominates_stmt_p (gimple s1, gimple s2) > > >+{ > > >+ basic_block bb1 = gimple_bb (s1), bb2 = gimple_bb (s2); > > >+ > > >+ if (!bb1 || s1 == s2) > > >+ return true; > > >+ > > >+ if (!bb2) > > >+ return false; > > Maybe this was carried over from somewhere else, but that looks > > awful strange. When !bb1 you return true, but if !bb2 you return > > false. At the least it deserves a comment. > > bb{1,2} == NULL means a default definition of the corresponding lhs. > If bb2 is NULL and bb1 is not, then s2 (assumed to be at the beginning of > function) certainly doesn't dominate s1, if bb2 is not NULL and bb1 is, then > s1 (assumed to be at the beginning of function) dominates s2, if both bb1 > and bb2 are NULL, then both are assumed to be at the same spot, so like the > s1 == s2 case. > > Note, the if (!bb1 || s1 == s2) return true; comes from the > tree-ssa-loop-niter.c origin, if (!bb2) return false; does not. > > > >+ if (bb1 == bb2) > > >+ { > > >+ if (gimple_code (s2) == GIMPLE_PHI) > > >+ return false; > > >+ > > >+ if (gimple_code (s1) == GIMPLE_PHI) > > >+ return true; > > Deserves a comment. I know what's going on here, but it's easier to > > read it in a comment rather than recalling the all-phis-in-parallel > > rule and verifying this handles that correctly. > > Ok. > > > >+ if (gimple_uid (s1) < gimple_uid (s2)) > > >+ return true; > > >+ > > >+ if (gimple_uid (s1) > gimple_uid (s2)) > > >+ return false; > > So if one (but not both) of the UIDs isn't set yet, one of these two > > statements will return, which seems wrong since we don't know where > > the statement without a UID is relative to the statement with a UID. > > Am I missing something? > > Right now we shouldn't see an unset uid here at all, unless it is a PHI, > which is handled earlier. break_up_subtract_bb initializes them for > all preexisting stmts, and the various places which add new stmts are > responsible for setting uid to either the uid of the immediately preceeding > or following stmt that has uid set (or 1 if the bb was previously empty). > > > >+ gimple_stmt_iterator gsi = gsi_for_stmt (s1); > > >+ unsigned int uid = gimple_uid (s1); > > >+ for (gsi_next (&gsi); !gsi_end_p (gsi); gsi_next (&gsi)) > > >+ { > > >+ gimple s = gsi_stmt (gsi); > > >+ if (gimple_uid (s) != uid) > > >+ break; > > >+ if (s == s2) > > >+ return true; > > >+ } > > Don't we only get here if both UIDs are zero (or the same by other > > means)? If so does this code even make sense? > > Both UIDs zero should not happen, both UIDs the same can happen, we don't > renumber the whole bb upon inserting something into the bb. > > > > > > >+ > > >+/* Insert STMT after INSERT_POINT. */ > > >+ > > >+static void > > >+insert_stmt_after (gimple stmt, gimple insert_point) > > > { > > >- return stmt ? gimple_uid (stmt) : 1; > > >+ gimple_stmt_iterator gsi; > > >+ basic_block bb; > > >+ > > >+ if (gimple_code (insert_point) == GIMPLE_PHI) > > >+ bb = gimple_bb (insert_point); > > >+ else if (!stmt_ends_bb_p (insert_point)) > > >+ { > > >+ gsi = gsi_for_stmt (insert_point); > > >+ gimple_set_uid (stmt, gimple_uid (insert_point)); > > >+ gsi_insert_after (&gsi, stmt, GSI_NEW_STMT); > > >+ return; > > >+ } > > >+ else > > >+ bb = find_fallthru_edge (gimple_bb (insert_point)->succs)->dest; > > >+ gsi = gsi_after_labels (bb); > > >+ if (gsi_end_p (gsi)) > > >+ { > > >+ gimple_stmt_iterator gsi2 = gsi_last_bb (bb); > > >+ gimple_set_uid (stmt, > > >+ gsi_end_p (gsi2) ? 1 : gimple_uid (gsi_stmt (gsi2))); > > >+ } > > >+ else > > >+ gimple_set_uid (stmt, gimple_uid (gsi_stmt (gsi))); > > >+ gsi_insert_before (&gsi, stmt, GSI_SAME_STMT); > > So from reading the name of the function, it's not clear that this > > inserts on the fallthru edge in the case where INSERT_POINT is the > > end of a block. And does that make sense? ISTM you'd want it on > > all the outgoing edges. And you have to worry about things like > > abnormals, critical edges, etc. > > Note the above isn't in any way a new code, just a cleanup of the > preexisting, just earlier the thing was done in more than one place > and could mishandle the uid setting. > > Anyway, from my understanding, insert_point is always a SSA_NAME setter (the > only reason to insert something after it is because the something uses the > SSA_NAME as one of it's operands), so it can't be say > GIMPLE_COND/GIMPLE_SWITCH with multiple edges, it can be IMHO only a call > with LHS that could throw, or some assignment with LHS that could throw. > But, given that if a statement throws, the return value/result of operation > isn't really assigned, I believe it is safe to insert only on the fallthru > edge, one can't insert on abnormal edges anyway and the EH/abnormal edge > destination shouldn't use the SSA_NAME anyway, because it will not have any > meaningful value.
I'm ok with the patch. Not sure if we want to backport it at all - we will only have wrong-debug issues (well, "only"). Thanks, Richard.