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.