On Mon, Aug 04, 2025 at 02:57:39PM +0800, Hongtao Liu wrote:
> > > > > +  rtx_insn *before = nullptr;
> > > > > +  rtx_insn *after = nullptr;
> > > > > +  if (insn == BB_HEAD (bb))
> > > > > +    before = insn;
> > > > > +  else
> > > > > +    after = insn ? PREV_INSN (insn) : BB_END (bb);
> > > > > +
> > > > > +  /* TLS_GD and TLS_LD_BASE instructions are normal functions which
> > > > > +     clobber caller-saved registers.  TLSDESC instructions are 
> > > > > special
> > > > > +     functions which only clobber RAX.  If any registers clobbered by
> > > > > +     the TLS instruction are live in this basic block, we must insert
> > > > > +     the TLS instruction after all live registers clobbered by the 
> > > > > TLS
> > > > > +     instruction are dead.  */
> > > > > +
> > > > > +  auto_bitmap live_caller_saved_regs;
> > > > > +  bitmap in = df_live ? DF_LIVE_IN (bb) : DF_LR_IN (bb);
> > > > > +
> > > > > +  bool flags_live_p = bitmap_bit_p (in, FLAGS_REG);
> > > > > +
> > > > > +  unsigned int i;
> > > > > +
> > > > > +  /* Get all live caller-saved registers.  */
> > > > > +  if (kind == X86_CSE_TLSDESC)
> > > > > +    {
> > > > > +      if (bitmap_bit_p (in, AX_REG))
> > > > > +       bitmap_set_bit (live_caller_saved_regs, AX_REG);
> > > >
> > > > And we don't need to check for those hard registers here and below?
> > >
> > > TLS_GD and TLS_LD_BASE instructions are normal functions which
> > > clobber caller-saved registers.  TLSDESC instructions are special
> > > functions which only clobber RAX.  live_caller_saved_regs captures
> > > live caller-saved registers for these TLS instructions.
> 
> I notice those insns are CALL_INSN, and for ABI, rax/rdi/rsi is
> caller_saved registers, so even we explicitly use (clobber (reg: RAX))

Since a single TLS call will clobber caller-saved registers, it must
be placed where all caller-saved registers are dead.   Otherwise, the
TLS call will clobber some live registers.

> RA will help save and restore the register?

This is unrelated to RA.

> > >
> > >   rtx tls_symbol = XVECEXP (src, 0, 0);
> > >   src = XVECEXP (src, 0, 1);
> > > ...
> > >           rtx tls_set = PATTERN (set_insn);
> > >           rtx tls_src = XVECEXP (SET_SRC (tls_set), 0, 0);
> > >           if (!rtx_equal_p (tls_symbol, tls_src))
> > >             {
> > >               set_insn = nullptr;
> > >               break;
> > >             }
> 
> According to @tls_dynamic_gnu2_64_<mode>, tls_src must be equal to
> tls_symbol, Do we really need to go through def-use chain to check
> that?

This verifies that checks the same pseudo register isn't assigned
to different tls_symbols.

> We may record the VAL as tls_symbol.
> > >
> > > >
> > > > > +       {
> > > > > +         if (DF_REF_IS_ARTIFICIAL (ref))
> > > > > +           break;
> > > > > +
> > > > > +         set_insn = DF_REF_INSN (ref);
> > > > > +         tls64 = get_attr_tls64 (set_insn);
> > > > > +         if (tls64 != TLS64_LEA)
> > > > > +           {
> > > > > +             set_insn = nullptr;
> > > > > +             break;
> > > > > +           }
> > > > > +
> > > > > +         rtx tls_set = PATTERN (set_insn);
> > > > > +         if (!tls_src)
> > > > > +           tls_src = SET_SRC (tls_set);
> > > > > +         else if (!rtx_equal_p (tls_src, SET_SRC (tls_set)))
> > > > > +           {
> > > > > +             set_insn = nullptr;
> > > > > +             break;
> > > > > +           }
> > > > > +       }
> > > > > +
> > > > > +      if (!set_insn)
> > > > > +       return false;
> > > > > +
> > > > > +      def_insn = set_insn;
> > > > > +    }
> > > > > +  else if (GET_CODE (src) == UNSPEC
> > > > > +          && XINT (src, 1) == UNSPEC_TLSDESC
> > > > > +          && SYMBOL_REF_P (XVECEXP (src, 0, 0)))
> > > > > +    def_insn = nullptr;
> > > >
> > > > Similar for here, it's supposed to handle
> > > > "*tls_dynamic_gnu2_combine_64_<mode>", according to the splitter
> > > > pattern, the output value can also be CSEd with tls64_call when ever
> > > > symbol_ref in the second operand of PLUS is the same.
> > >
> > > v4 is changed to
> > >
> > >   rtx tls_symbol = XVECEXP (src, 0, 0);
> > >   src = XVECEXP (src, 0, 1);
> > >   scalar_mode = mode = GET_MODE (src);
> > >   gcc_assert (REG_P (src));
> >
> > Since this triggered the assert on
> >
> > (set (reg/f:DI 103)
> >     (plus:DI (unspec:DI [
> >                 (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> >                 (unspec:DI [
> >                         (symbol_ref:DI ("_TLS_MODULE_BASE_") [flags 0x10])
> >                     ] UNSPEC_TLSDESC)
> >                 (reg/f:DI 7 sp)
> >             ] UNSPEC_TLSDESC)
> >         (const:DI (unspec:DI [
> >                     (symbol_ref:DI ("foo") [flags 0x1a] <var_decl 
> > 0x7fffe99dbe40 foo>)
> >                 ] UNSPEC_DTPOFF))))
> >
> > I added a testcase and kept the v3 code.
> 
> For tls64 combine, tls_symbol should be second operand of the original src, 
> .i.e
>          (const:DI (unspec:DI [
>                      (symbol_ref:DI ("foo") [flags 0x1a] <var_decl
> 0x7fffe99dbe40 foo>)  <--- this
>                  ] UNSPEC_DTPOFF))))
> 
> Not this   (symbol_ref:DI ("_TLS_MODULE_BASE_"), and no need for
> gcc_assert (REG_P (src)).


This has been changed to

  if (REG_P (src))
    {
      ....
    }
  else if (GET_CODE (src) == UNSPEC
           && XINT (src, 1) == UNSPEC_TLSDESC
           && SYMBOL_REF_P (XVECEXP (src, 0, 0)))
    def_insn = nullptr;
  else
    gcc_unreachable ();

in v5:

https://patchwork.sourceware.org/project/gcc/list/?series=50446


H.J.

Reply via email to