On 05/24/2011 03:34 PM, Jeff Law wrote: > > This has gone latent on the trunk, but the underlying issue hasn't been > resolved. > > ira.c::update_equiv_regs can create REG_EQUIV notes for equivalences > which are local to a block rather than the traditional function-wide > equivalences we typically work with. > > This occurs when we have an insn that loads a pseudo from a MEM and the > pseudo is used within only a single block and the MEM remains unchanged > through the life of the pseudo. > > Starting with the assumption that we're going to create a block local > pseudo under the rules noted above, consider this RTL: > > (set (reg X) (some address)) > (set (reg Y) (mem (reg X))) > (use Y) > > > We're going to create an equivalence between (reg Y) and its memory > location in update_equiv_regs. Assume IRA is able to allocate a hard > reg for reg X, but not reg Y. > > reload's strategy in this situation will be to remove the insn which > creates the equivalence between reg Y and the memory location. Uses of > reg Y will be replaced with the equivalent memory location. > > That's all fine and good, except reload uses delete_dead_insn, which > deletes the equivalencing insn, but also recursively tries to remove the > prior insn if it becomes dead as a result of removing the equivalencing > insn. > > Anyway, continuing with our example, reg X gets a hard reg, so our RTL > will look something like > > (set (reg 0) (some address)) > (set (reg Y) (mem (reg 0))) > (use Y) > > Then we remove the equivalencing insn resulting in > > (set (reg 0) (some address) > (use Y) > > And we recurse from delete_dead_insn and determine that the first insn > was dead as well, so it gets removed leaving: > > (use Y) > > We then replace Y with its equivalent memory location > > (use (mem (reg 0)) > > At which point we lose because hard reg 0 is no longer initialized. > > > The code in question is literally 20 years old and predates running any > real dead code elimination after reload. ISTM the right thing to do is > stop using delete_dead_insn in this code and let the post-reload DCE > pass do its job. That allows us to continue to record the block local > equivalence.
Sounds like the right thing to do. OK. (Can we eliminate the other caller?) I've looked at code generation; it appears unchanged on i686-linux, which I think is the expected result. There are minor differences in assembly output on mips64-linux. If you want to look at it, I'm attaching a testcase - compile with "-O2 -fno-reorder-blocks". Bernd
typedef _Bool bool; typedef struct { volatile int counter; } atomic_t; struct list_head { struct list_head *next, *prev; }; typedef void (*ctor_fn_t)(void); struct kref { atomic_t refcount; }; struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; struct kobj_type *ktype; struct sysfs_dirent *sd; struct kref kref; unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1; }; static inline __attribute__((always_inline)) void _do_trace_module_get (void (*probe)(char *name, bool wait, unsigned long ip)) { return -38; } struct module_kobject { struct kobject kobj; struct module *mod; struct kobject *drivers_dir; struct module_param_attrs *mp; }; enum module_state { MODULE_STATE_LIVE, MODULE_STATE_COMING, MODULE_STATE_GOING, }; struct module { enum module_state state; struct list_head list; char name[(64 - sizeof(unsigned long))]; struct module_kobject mkobj; struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; struct kobject *holders_dir; const struct kernel_symbol *syms; const unsigned long *crcs; unsigned int num_syms; struct kernel_param *kp; unsigned int num_kp; unsigned int num_gpl_syms; const struct kernel_symbol *gpl_syms; const unsigned long *gpl_crcs; struct list_head modules_which_use_me; struct task_struct *waiter; void (*exit)(void); struct module_ref { unsigned int incs; unsigned int decs; } *refptr; ctor_fn_t *ctors; unsigned int num_ctors; }; static inline __attribute__((always_inline)) int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len) { if (len > 0) len += scnprintf(buf + len, buflen - len, ","); if (rbot == rtop) len += scnprintf(buf + len, buflen - len, "%d", rbot); else len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop); return len; } int bitmap_scnlistprintf(char *buf, unsigned int buflen, const unsigned long *maskp, int nmaskbits) { int len = 0; int cur, rbot, rtop; if (buflen == 0) return 0; buf[0] = 0; rbot = cur = find_next_bit((maskp), (nmaskbits), 0); while (cur < nmaskbits) { rtop = cur; cur = find_next_bit(maskp, nmaskbits, cur+1); if (cur >= nmaskbits || cur > rtop + 1) { len = bscnl_emit(buf, buflen, rbot, rtop, len); rbot = cur; } } return len; }