https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62077
--- Comment #12 from Richard Biener <rguenth at gcc dot gnu.org> --- Ok, so there is one thing that changed (but only very recently) on trunk which is improved hashing of SCCs and thus more consistent ordering. Especially I'm talking about the fact that at compile-time (!) we sort via static int scc_entry_compare (const void *p1_, const void *p2_) { const scc_entry *p1 = (const scc_entry *) p1_; const scc_entry *p2 = (const scc_entry *) p2_; if (p1->hash < p2->hash) return -1; else if (p1->hash > p2->hash) return 1; return 0; } static hashval_t hash_scc (struct streamer_tree_cache_d *cache, unsigned first, unsigned size) { /* Compute hash values for the SCC members. */ for (unsigned i = 0; i < size; ++i) sccstack[first+i].hash = hash_tree (cache, sccstack[first+i].t); if (size == 1) return sccstack[first].hash; /* Sort the SCC of type, hash pairs so that when we mix in all members of the SCC the hash value becomes independent on the order we visited the SCC. Disregard hashes equal to the hash of the tree we mix into because we cannot guarantee a stable sort for those across different TUs. */ qsort (&sccstack[first], size, sizeof (scc_entry), scc_entry_compare); which means returning 0 from the qsort compare function for hash collisions. In theory the qsort implementation can randomly permute stuff here leading to comparison fails. I'm checking if breaking the tie via the DFS number fixes the miscompare I saw. Note that I assumed that "sane" implementations would behave consistently here, but of course with address-space randomization and friends and an implementation that breaks tie itself via addresses would break. (I'd choose a simpler tie breaker - first argument to compare is less than second arg to compare). Well. Not sure what glibc msort does here. That said, the smallest object I observe differences is build/genconfig.o which has differences in the size(!) of the LTO_section_decls section and differences already in the decl-state refs part.