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