https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128437

--- Comment #17 from Uroš Bizjak <ubizjak at gmail dot com> ---
The fix committed for this PR (r17-6003, ix86_remove_dead_tls_ld_base in
ix86_reorg) is not sufficient, as comment #16 shows: the original source
still ICEs.

The helper deletes a dead UNSPEC_TLS_LD_BASE call only if it carries a
REG_UNUSED note on %rax. That note is often missing:

- As the reporter's dump shows, the call result may have been stored to a
  spill slot (insn 80: [sp+8] = ax) whose reload was deleted later. DCE
  never deletes non-register stores, so the dead store keeps the call's
  result "used", and the call has no REG_UNUSED.  Removing the store would
  need DSE, and pass_rtl_dse2 runs before sched2.
- Sashiko's review of the commit points out that x86_cse hoists the call
  together with a copy from %rax. After the sched2 DCE, REG_UNUSED can end
  up on the copy's destination and REG_DEAD on %rax, not on the call.
- REG_UNUSED notes are only recomputed where DF notes are alive.  Sashiko
  argues that they are gone after pass_cprop_hardreg (TODO_df_finish), and
  that at -O1, with -fno-schedule-insns2 or with -fno-dce nothing
  recomputes them, while cleanup_cfg in pass_reorder_blocks can delete
  unreachable blocks holding the last @dtpoff use without any DCE.

The last point shows that the ICE does not depend on sched2 DCE at all: any
pass that removes the last @dtpoff reference can trigger it.  Trying to
delete the leftover call is therefore not a complete fix, and a second DCE
pass would not be either, since DCE keeps the spill store.

So, make the output independent of what other passes deleted.

'%&' needs a local-dynamic TLS symbol only because the insn template prints
it. The only users of the LD base are the "base + sym@dtpoff" forms built
in legitimize_tls_address, and all of them contain the symbol. So if
get_some_local_dynamic_name () finds no symbol, nothing can use the base,
and the insn's result is dead.  In that case the LD base patterns need not
print the lea and call.  They only have to define the result register:

  /* The last local-dynamic TLS reference can be deleted after RA while
     this insn survives (DCE doesn't delete calls in sched2, and a dead
     spill store may still use the result).  Then '%&' has no symbol to
     print and nobody uses the base; only define the result register.  */
  if (!get_some_local_dynamic_name ())
    return "xor{l}\t%k0, %k0";

The check goes into *tls_local_dynamic_base_64_<mode>,
*tls_local_dynamic_base_64_largepic and *tls_local_dynamic_base_32_gnu.

Reply via email to