(steven, you spent a fair amount of time in gcse.c, which is why i've copied you to see if you knew what was up)
In record_mem_last_set_info, we have if (CALL_P (insn)) { /* Note that traversals of this loop (other than for free-ing) will break after encountering a CALL_INSN. So, there's no need to insert a pair of items, as canon_list_insert does. */ canon_modify_mem_list[bb] = alloc_INSN_LIST (insn, canon_modify_mem_list[bb]); bitmap_set_bit (blocks_with_calls, bb); } The *only* traversal of canon_modify_mem_list that isn't freeing now looks like this: /* First handle all the blocks with calls. We don't need to do any list walking for them. */ EXECUTE_IF_SET_IN_BITMAP (blocks_with_calls, 0, bb_index, bi) { if (set_p) SET_BIT (bmap[bb_index], indx); else RESET_BIT (bmap[bb_index], indx); } /* Now iterate over the blocks which have memory modifications but which do not have any calls. */ EXECUTE_IF_AND_COMPL_IN_BITMAP (modify_mem_list_set, blocks_with_calls, 0, bb_index, bi) { rtx list_entry = canon_modify_mem_list[bb_index]; Note that it won't iterate over any blocks that have calls anymore. 1. Why are we bothering to allocate anything in the lists for basic blocks with calls in them, at all, if we aren't going to ever walk them? Seems like a waste of time and space The second we see a call, we could just blow away the canon_modify_mem_list for that block, mark the block as having a call, and go about our way, instead of continuing to put both calls, and memory instructions on the list. 2. ISTM we could probably handle blocks with pure and const calls, if we really wanted to.