On Mon, Aug 11, 2025 at 11:13 PM Hongtao Liu <crazy...@gmail.com> wrote:
>
> 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.

Before RA, hard registers are only used as scratch registers:

insn 20 set rax ....
insn 21 set r300 rax  # rax is dead after this.

Now we are inserting another rax usage in the same basic block.

set rax ...
set r400 rax

we must insert them where rax isn't alive.  We can't insert them
between insn 20 and insn 21.  My patch inserts them where all
caller-saved registers are dead.

> 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



-- 
H.J.

Reply via email to