I have a bug I'm trying to investigate where, starting in gcc-4.2.x, the loop invariant pass considers a computation involving a global register variable as invariant across a call. The basic structure of the code is:
register unsigned long regvar asm ("foo"); func(arg) { for (...) { call(); *arg = expression(regvar); } } The code is built with "-ffixed-foo". Actually the specific case is 64-bit sparc, and the register being used is "%g5" so global_regs[%g5], call_used_regs[%g5] and fixed_regs[%g5] will all be true. loop-invariant.c decides that expression(regvar) is invariant and can be moved outside of the loop, which is an illegal transformation because calls clobber global register variables. When I noticed this I said to myself, "Hmmm, that's peculiar..." I then checked to see what changed in the loop invariant pass between gcc-4.1.x and gcc-4.2.x, and mainly it was changed to use the dataflow layer. So I started looking at how the dataflow layer handles global register variables wrt. calls. When a CALL is encountered, df_insn_refs_record() only marks them as used by going: for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (global_regs[i]) df_uses_record (... I thought initially that this coude should be using "df_defs_record (...", but the next few lines take care of that issue by iterating over df_invalidated_by_call, which is initialized with the contents of regs_invalidated_by_call and I validated that the global register in use is included in the invalidation list by making some df_dump() calls in a debugging session. So the dataflow problem should show the loop-invariant pass that the call inside the loop potentially changes 'regvar' and thus expressions involving 'regvar' are not invariant. But for some reason that isn't happening. I'm wondering if there is a bad interaction between how df-scan.c cooks up these fake insn "locations" for things like df_invalidated_by_call. In such cases, DF_REF_LOC will be ®no_reg_rtx[], and in loop-invariant.c it will: 1) Records the DF_REF_LOCs, via record_uses(), in the ->pos member of it's "struct use" data-structure. 2) Later writes directly to *u->pos in move_invariant_reg(). But perhaps we shouldn't even get that far with such fake location expressions. I'm trying to debug this further, but if anyone sees anything obvious or has some suggestions for debugging this, let me know. Thanks.