Patch with the amendments to the commit message as requested. best regards, Julian
>From e8e742b1f809af2c1a9697c31335e184738b258a Mon Sep 17 00:00:00 2001 From: Julian Waters <tanksherma...@gmail.com> Date: Tue, 15 Oct 2024 20:56:22 +0800 Subject: [PATCH] Implement Windows TLS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements native Thread Local Storage access on Windows, as motivated by PR80881. Currently, Thread Local Storage accesses on Windows relies on emulation, which is detrimental to performance in certain applications, notably the Python Interpreter and the gcc port of the Java Virtual Machine. This patch was heavily inspired by Daniel Green's original work on native Windows Thread Local Storage from over a decade ago, which can be found at https://github.com/venix1/MinGW-GDC/blob/master/patches/mingw-tls-gcc-4.8.patch as a reference. gcc/ChangeLog: * config/i386/i386.cc (ix86_legitimate_constant_p): Handle new UNSPEC. (legitimate_pic_operand_p): Handle new UNSPEC. (legitimate_pic_address_disp_p): Handle new UNSPEC. (ix86_legitimate_address_p): Handle new UNSPEC. (ix86_tls_index_symbol): New symbol for _tls_index. (ix86_tls_index): Handle creation of _tls_index symbol. (legitimize_tls_address): Create thread local access sequence. (output_pic_addr_const): Handle new UNSPEC. (i386_output_dwarf_dtprel): Handle new UNSPEC. (i386_asm_output_addr_const_extra): Handle new UNSPEC. * config/i386/i386.h (TARGET_WIN32_TLS): Define. * config/i386/i386.md: New UNSPEC. * config/i386/predicates.md: Handle new UNSPEC. * config/mingw/mingw32.h (TARGET_WIN32_TLS): Define. (TARGET_ASM_SELECT_SECTION): Define. (DEFAULT_TLS_SEG_REG): Define. * config/mingw/winnt.cc (mingw_pe_select_section): Select proper TLS section. (mingw_pe_unique_section): Handle TLS section. * config/mingw/winnt.h (mingw_pe_select_section): Declare. * configure: Regenerate. * configure.ac: New check for broken linker thread local support Co-authored-by: Eric Botcazou <botca...@adacore.com> Co-authored-by: Uroš Bizjak <ubiz...@gmail.com> Co-authored-by: Liu Hao <lh_mo...@126.com> Signed-off-by: Julian Waters <tanksherma...@gmail.com> --- gcc/config/i386/i386.cc | 61 ++++++++++++++++++++++++++++++++++- gcc/config/i386/i386.h | 1 + gcc/config/i386/i386.md | 1 + gcc/config/i386/predicates.md | 1 + gcc/config/mingw/mingw32.h | 9 ++++++ gcc/config/mingw/winnt.cc | 14 ++++++++ gcc/config/mingw/winnt.h | 1 + gcc/configure | 29 +++++++++++++++++ gcc/configure.ac | 29 +++++++++++++++++ 9 files changed, 145 insertions(+), 1 deletion(-) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 473e4cbf10e..304189bd947 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -11170,6 +11170,9 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x) x = XVECEXP (x, 0, 0); return (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC); + case UNSPEC_SECREL32: + x = XVECEXP (x, 0, 0); + return GET_CODE (x) == SYMBOL_REF; default: return false; } @@ -11306,6 +11309,9 @@ legitimate_pic_operand_p (rtx x) x = XVECEXP (inner, 0, 0); return (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_EXEC); + case UNSPEC_SECREL32: + x = XVECEXP (inner, 0, 0); + return GET_CODE (x) == SYMBOL_REF; case UNSPEC_MACHOPIC_OFFSET: return legitimate_pic_address_disp_p (x); default: @@ -11486,6 +11492,9 @@ legitimate_pic_address_disp_p (rtx disp) disp = XVECEXP (disp, 0, 0); return (GET_CODE (disp) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (disp) == TLS_MODEL_LOCAL_DYNAMIC); + case UNSPEC_SECREL32: + disp = XVECEXP (disp, 0, 0); + return GET_CODE (disp) == SYMBOL_REF; } return false; @@ -11763,6 +11772,7 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict, case UNSPEC_INDNTPOFF: case UNSPEC_NTPOFF: case UNSPEC_DTPOFF: + case UNSPEC_SECREL32: break; default: @@ -11788,7 +11798,8 @@ ix86_legitimate_address_p (machine_mode, rtx addr, bool strict, || GET_CODE (XEXP (XEXP (disp, 0), 0)) != UNSPEC || !CONST_INT_P (XEXP (XEXP (disp, 0), 1)) || (XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_DTPOFF - && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_NTPOFF)) + && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_NTPOFF + && XINT (XEXP (XEXP (disp, 0), 0), 1) != UNSPEC_SECREL32)) /* Non-constant pic memory reference. */ return false; } @@ -12112,6 +12123,22 @@ get_thread_pointer (machine_mode tp_mode, bool to_reg) return tp; } +/* Construct the SYMBOL_REF for the _tls_index symbol. */ + +static GTY(()) rtx ix86_tls_index_symbol; + +static rtx +ix86_tls_index (void) +{ + if (!ix86_tls_index_symbol) + ix86_tls_index_symbol = gen_rtx_SYMBOL_REF (SImode, "_tls_index"); + + if (flag_pic) + return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, ix86_tls_index_symbol), UNSPEC_PCREL)); + else + return ix86_tls_index_symbol; +} + /* Construct the SYMBOL_REF for the tls_get_addr function. */ static GTY(()) rtx ix86_tls_symbol; @@ -12170,6 +12197,26 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) machine_mode tp_mode = Pmode; int type; +#if TARGET_WIN32_TLS + off = gen_const_mem (SImode, ix86_tls_index ()); + set_mem_alias_set (off, GOT_ALIAS_SET); + + tp = gen_const_mem (Pmode, GEN_INT (TARGET_64BIT ? 88 : 44)); + set_mem_addr_space (tp, DEFAULT_TLS_SEG_REG); + + if (TARGET_64BIT) + off = convert_to_mode (Pmode, off, 1); + + base = force_reg (Pmode, off); + tp = copy_to_mode_reg (Pmode, tp); + + tp = gen_const_mem (Pmode, gen_rtx_PLUS (Pmode, tp, gen_rtx_MULT (Pmode, base, GEN_INT (UNITS_PER_WORD)))); + set_mem_alias_set (tp, GOT_ALIAS_SET); + + base = force_reg (Pmode, tp); + + return gen_rtx_PLUS (Pmode, base, gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, x), UNSPEC_SECREL32))); +#else /* Fall back to global dynamic model if tool chain cannot support local dynamic. */ if (TARGET_SUN_TLS && !TARGET_64BIT @@ -12403,6 +12450,7 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) } return dest; +#endif } /* Return true if the TLS address requires insn using integer registers. @@ -12872,6 +12920,9 @@ output_pic_addr_const (FILE *file, rtx x, int code) case UNSPEC_INDNTPOFF: fputs ("@indntpoff", file); break; + case UNSPEC_SECREL32: + fputs ("@secrel32", file); + break; #if TARGET_MACHO case UNSPEC_MACHOPIC_OFFSET: putc ('-', file); @@ -12897,7 +12948,11 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x) { fputs (ASM_LONG, file); output_addr_const (file, x); +#if TARGET_WIN32_TLS + fputs ("@secrel32", file); +#else fputs ("@dtpoff", file); +#endif switch (size) { case 4: @@ -14650,6 +14705,10 @@ i386_asm_output_addr_const_extra (FILE *file, rtx x) output_addr_const (file, op); fputs ("@indntpoff", file); break; + case UNSPEC_SECREL32: + output_addr_const (file, op); + fputs ("@secrel32", file); + break; #if TARGET_MACHO case UNSPEC_MACHOPIC_OFFSET: output_addr_const (file, op); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 51934400951..a10a368a5f7 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -510,6 +510,7 @@ extern unsigned char ix86_prefetch_sse; #define TARGET_GNU2_TLS (ix86_tls_dialect == TLS_DIALECT_GNU2) #define TARGET_ANY_GNU_TLS (TARGET_GNU_TLS || TARGET_GNU2_TLS) #define TARGET_SUN_TLS 0 +#define TARGET_WIN32_TLS 0 #ifndef TARGET_64BIT_DEFAULT #define TARGET_64BIT_DEFAULT 0 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index effab299349..865bf29d853 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -79,6 +79,7 @@ UNSPEC_MACHOPIC_OFFSET UNSPEC_PCREL UNSPEC_SIZEOF + UNSPEC_SECREL32 ;; Prologue support UNSPEC_STACK_ALLOC diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 053312bbe27..d83b27355cc 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -218,6 +218,7 @@ case UNSPEC_DTPOFF: case UNSPEC_GOTNTPOFF: case UNSPEC_NTPOFF: + case UNSPEC_SECREL32: return true; default: break; diff --git a/gcc/config/mingw/mingw32.h b/gcc/config/mingw/mingw32.h index 0dfe8e995b6..251271901a3 100644 --- a/gcc/config/mingw/mingw32.h +++ b/gcc/config/mingw/mingw32.h @@ -308,6 +308,15 @@ do { \ #undef TARGET_N_FORMAT_TYPES #define TARGET_N_FORMAT_TYPES 3 +#undef TARGET_WIN32_TLS +#define TARGET_WIN32_TLS 1 + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION mingw_pe_select_section + +#undef DEFAULT_TLS_SEG_REG +#define DEFAULT_TLS_SEG_REG (TARGET_64BIT ? ADDR_SPACE_SEG_GS : ADDR_SPACE_SEG_FS) + #define HAVE_ENABLE_EXECUTE_STACK #undef CHECK_EXECUTE_STACK_ENABLED #define CHECK_EXECUTE_STACK_ENABLED flag_setstackexecutable diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc index 9d433daaf5a..8453965f625 100644 --- a/gcc/config/mingw/winnt.cc +++ b/gcc/config/mingw/winnt.cc @@ -392,6 +392,15 @@ i386_pe_strip_name_encoding_full (const char *str) return name; } +section * +mingw_pe_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) +{ + if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl)) + return get_named_section (decl, ".tls$", reloc); + else + return default_select_section (decl, reloc, align); +} + void mingw_pe_unique_section (tree decl, int reloc) { @@ -416,6 +425,8 @@ mingw_pe_unique_section (tree decl, int reloc) prefix = ".text$"; else if (decl_readonly_section (decl, reloc)) prefix = ".rdata$"; + else if (DECL_THREAD_LOCAL_P (decl)) + prefix = ".tls$"; else prefix = ".data$"; len = strlen (name) + strlen (prefix); @@ -490,6 +501,9 @@ mingw_pe_asm_named_section (const char *name, unsigned int flags, *f++ = 'e'; #endif + if (strcmp (name, ".tls$") == 0) + *f++ = 'd'; + if ((flags & (SECTION_CODE | SECTION_WRITE)) == 0) /* readonly data */ { diff --git a/gcc/config/mingw/winnt.h b/gcc/config/mingw/winnt.h index 97fefbcebca..525ac3691f4 100644 --- a/gcc/config/mingw/winnt.h +++ b/gcc/config/mingw/winnt.h @@ -30,6 +30,7 @@ extern void mingw_pe_file_end (void); extern void mingw_pe_maybe_record_exported_symbol (tree, const char *, int); extern void mingw_pe_record_stub (const char *); extern unsigned int mingw_pe_section_type_flags (tree, const char *, int); +extern section *mingw_pe_select_section (tree, int, unsigned HOST_WIDE_INT); extern void mingw_pe_unique_section (tree, int); extern bool mingw_pe_valid_dllimport_attribute_p (const_tree); diff --git a/gcc/configure b/gcc/configure index 150ab616414..cd0afa829bb 100755 --- a/gcc/configure +++ b/gcc/configure @@ -27730,6 +27730,35 @@ if test $gcc_cv_as_tls = yes; then fi fi +case $target_os in + win32 | pe | cygwin* | mingw32*) + if test $set_have_as_tls = yes; then + # Hack to check whether ld breaks on @secrel32 for Windows + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 44 -o "$gcc_cv_gld_major_version" -gt 2; then + : # ld support for @secrel32 was fixed in this version + else + as_fn_error $? "ld version is known to have broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error" "$LINENO" 5 + fi + elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then + echo '.text' > conftest.s + echo 'foo: nop' >> conftest.s + echo '.data' >> conftest.s + echo '.secrel32 foo' >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1 && $gcc_cv_ld -o conftest.exe conftest.o > /dev/null; then + if $gcc_cv_objdump -h conftest.exe | grep '\.reloc\>' > /dev/null; then + as_fn_error $? "ld has broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error" "$LINENO" 5 + fi + else + as_fn_error $? "Error occurred while checking for broken secrel32 relocations" "$LINENO" 5 + fi + rm -f conftest.s conftest.o conftest.exe + else + as_fn_error $? "Cannot check for broken secrel32 relocations to determine support for --enable-tls" "$LINENO" 5 + fi + fi + ;; +esac if test $set_have_as_tls = yes ; then $as_echo "#define HAVE_AS_TLS 1" >>confdefs.h diff --git a/gcc/configure.ac b/gcc/configure.ac index bdb22d53e2c..00bfa452691 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -4166,6 +4166,35 @@ else [$tls_as_opt], [$conftest_s],, [set_have_as_tls=yes]) fi +case $target_os in + win32 | pe | cygwin* | mingw32*) + if test $set_have_as_tls = yes; then + # Hack to check whether ld breaks on @secrel32 for Windows + if test $in_tree_ld = yes; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 44 -o "$gcc_cv_gld_major_version" -gt 2; then + : # ld support for @secrel32 was fixed in this version + else + AC_MSG_ERROR([ld version is known to have broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error]) + fi + elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x -a x$gcc_cv_objdump != x; then + echo '.text' > conftest.s + echo 'foo: nop' >> conftest.s + echo '.data' >> conftest.s + echo '.secrel32 foo' >> conftest.s + if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1 && $gcc_cv_ld -o conftest.exe conftest.o > /dev/null; then + if $gcc_cv_objdump -h conftest.exe | grep '\.reloc\>' > /dev/null; then + AC_MSG_ERROR([ld has broken secrel32 relocations, configure without --enable-tls or with --disable-tls to remove this error]) + fi + else + AC_MSG_ERROR([Error occurred while checking for broken secrel32 relocations]) + fi + rm -f conftest.s conftest.o conftest.exe + else + AC_MSG_ERROR([Cannot check for broken secrel32 relocations to determine support for --enable-tls]) + fi + fi + ;; +esac if test $set_have_as_tls = yes ; then AC_DEFINE(HAVE_AS_TLS, 1, [Define if your assembler and linker support thread-local storage.]) -- 2.45.2