------- Comment #11 from wilson at gcc dot gnu dot org 2005-10-12 02:52 ------- My earlier guess was correct. It is a problem with the sched_insn_condition_mutex_p code. Also, there is the problem that the code for handling serialization points for dependencies is confused.
sched-deps creates dependencies for a jump_insn by making it a serialization point. It is added to last_pending_memory_flush. This insn will depend on all previous instructions that use memory, and the previous memory flush insn. All following instructions that use memory will depend on this insn. This effectively serializes insn dependencies at this point. The code that fails looks like this (jump_insn ... (eq p6 0) ...) (note ... NOTE_INSN_LOOP_BEG) (cond_exec (eq p8 0) ...) (jump_insn ... (ne p8 0) ...) The first jump_insn goes in last_pending_memory_flush because it is a serialization point for dependencies. An instruction immediately after a LOOP_BEG note is treated as a serialization point, so we can preserve reg_n_refs info. So we create a dependency from the cond_exec to the jump_insn, remove the jump_insn from last_pending_memory_flush, and then put the cond_exec in last_pending_memory_flush. The second jump is another another serialization point, but it is mutex on the cond_exec insn, so we don't create any dependencies. And now we have a problem, because the the second jump insn has no dependencies, there is nothing to prevent it from being scheduled before the first jump insn. This would result in bad code, but fortunately (so to speak) we ICE before we finish because this corrupts the basic block info. So there are two problems here. The first problem is that we aren't handling serialization points correctly. We must always create a dependency for a serialization point, even if the two instructions are mutex. Otherwise, it will not function correctly as a serialization point. Thus there must be a dependency between the second jump insn and the cond_exec. The second problem is that the current code tries to create a list of serialization points, which makes no sense. Since all instructions before the last serialization point depend on the last serialization point, there is no point in keeping track of more than one of them. Only the last one is useful. However, the code is trying to maintain a list of branch instructions as our serialization points. This can not work. While it does make some sense to keep a list of branch insns for the purposes of handling dependencies, it does not make sense to also make them serialization points. The code is trying to use last_pending_memory_flush for too different incompatible purposes. I've got a patch that fixes this, though I am not entirely happy with it. I added a "uncond" argument to add_dependence_list so I can force dependencies to be emitted for last_pending_memory_flush. I also removed the code that was handling last_pending_memory_flush as if it was a list. It is not possible for this to be a list and still work correctly as a serialization point. In theory, this makes the field pending_flush_length obsolete. Unfortunately, sched-rgn.c is using it in a strange way I don't understand. It is trying to concatenate lists of last_pending_memory_flush, but we can never have more than one from sched-deps.c's point of view. I left it alone. Maybe this does work if you call sched-dep separately for individual basic blocks. Another downside to my patch is that it creates more serialization points than is necessary or ideal, but this can't be fixed without more work. Ideally, the code for handling jump_insns should be a separate list from last_pending_memory_flush. Just like we have a list of pending reads and a list for pending writes, we can have a list for pending jump_insns. And then when we need a serialization point for real, because the lists got too big or whatever, then we use last_pending_memory_flush, and there is only ever one entry in last_pending_memory_flush. -- http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24232