On Mon, Aug 4, 2025 at 11:33 PM H.J. Lu <hjl.to...@gmail.com> wrote:
>
> 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.
I saw in legitimize_tls_address, it doesn't check the liveness of
RAX/RDI(or call clobber registers) even with explicit use of RDI/RAX.
I'm wondering if we can reuse that code to do similar things.

617      if (TARGET_GNU2_TLS)
12618        {
12619          rtx tmp = ix86_tls_module_base ();
12620
12621          base = gen_reg_rtx (ptr_mode);
12622          if (TARGET_64BIT)
12623            emit_insn (gen_tls_dynamic_gnu2_64 (ptr_mode, base,
tmp));
12624          else
12625            emit_insn (gen_tls_dynamic_gnu2_32 (base, tmp, pic));
12626
12627          tp = get_thread_pointer (ptr_mode, true);

and

12632      else
12633        {
12634          rtx caddr = ix86_tls_get_addr ();
12635
12636          base = gen_reg_rtx (Pmode);
12637          if (TARGET_64BIT)
12638            {
12639              rtx rax = gen_rtx_REG (Pmode, AX_REG);
12640              rtx rdi = gen_rtx_REG (Pmode, DI_REG);
12641              rtx_insn *insns;
12642              rtx eqv;
12643
12644              start_sequence ();
12645              emit_call_insn
12646                (gen_tls_local_dynamic_base_64 (Pmode, rax,
caddr, rdi));
12647              insns = end_sequence ();
12648
12649              /* Attach a unique REG_EQUAL, to allow the RTL
optimizers to
12650                 share the LD_BASE result with other LD model
accesses.  */
12651              eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1,
const0_rtx),
12652                                    UNSPEC_TLS_LD_BASE);
12653
12654              RTL_CONST_CALL_P (insns) = 1;
12655              emit_libcall_block (insns, base, rax, eqv);
12656            }
12657          else
12658            emit_insn (gen_tls_local_dynamic_base_32 (base, pic,
caddr));
12659        }

>
> > 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.
I see.
>
> > 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.



-- 
BR,
Hongtao

Reply via email to