diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md index 87cceac4cfb..6b291a02d88 100644 --- a/gcc/config/i386/constraints.md +++ b/gcc/config/i386/constraints.md @@ -186,6 +186,11 @@ (and (match_operand 0 "memory_operand") (match_test "constant_address_p (XEXP (op, 0))"))) +(define_memory_constraint "Bk" + "@internal TLS address that allows insn using non-integer registers." + (and (match_operand 0 "memory_operand") + (not (match_test "ix86_gpr_tls_address_pattern_p (op)")))) + (define_special_memory_constraint "Bn" "@internal Memory operand without REX prefix." (match_operand 0 "norex_memory_operand")) diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 7e05510c679..1cd219798e3 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -243,6 +243,7 @@ extern unsigned int ix86_get_callcvt (const_tree); #endif extern rtx ix86_tls_module_base (void); +extern bool ix86_gpr_tls_address_pattern_p (rtx); extern bool ix86_tls_address_pattern_p (rtx); extern rtx ix86_rewrite_tls_address (rtx); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 7fe271b1b94..10bfa0e7459 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -11628,6 +11628,36 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov) return dest; } +/* Return true if the TLS address requires insn using integer registers. + It's used to prevent KMOV/VMOV in TLS code sequences which require integer + MOV instructions, refer to PR103275. */ +bool +ix86_gpr_tls_address_pattern_p (rtx mem) +{ + gcc_assert (MEM_P (mem)); + + rtx addr = XEXP (mem, 0); + subrtx_var_iterator::array_type array; + FOR_EACH_SUBRTX_VAR (iter, array, addr, ALL) + { + rtx op = *iter; + if (GET_CODE (op) == UNSPEC) + switch (XINT (op, 1)) + { + case UNSPEC_GOTNTPOFF: + return true; + case UNSPEC_TPOFF: + if (!TARGET_64BIT) + return true; + break; + default: + break; + } + } + + return false; +} + /* Return true if OP refers to a TLS address. */ bool ix86_tls_address_pattern_p (rtx op) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7b2de60706d..03d401efff8 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -2164,9 +2164,9 @@ (define_insn "*movdi_internal" [(set (match_operand:DI 0 "nonimmediate_operand" - "=r ,o ,r,r ,r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,m,?r ,?*Yd,?r,?*v,?*y,?*x,*k,*k ,*r,*m,*k") + "=r ,o ,r,r ,r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,m,?r ,?*Yd,?r,?*v,?*y,?*x,*k,*k ,*r,*m,*k") (match_operand:DI 1 "general_operand" - "riFo,riF,Z,rem,i,re,C ,*y,m ,*y,*y,r ,C ,*v,m ,*v,v,*Yd,r ,*v,r ,*x ,*y ,*r,*km,*k,*k,CBC"))] + "riFo,riF,Z,rem,i,re,C ,*y,Bk ,*y,*y,r ,C ,*v,Bk,*v,v,*Yd,r ,*v,r ,*x ,*y ,*r,*kBk,*k,*k,CBC"))] "!(MEM_P (operands[0]) && MEM_P (operands[1])) && ix86_hardreg_mov_ok (operands[0], operands[1])" { @@ -2385,9 +2385,9 @@ (define_insn "*movsi_internal" [(set (match_operand:SI 0 "nonimmediate_operand" - "=r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,?r,?*v,*k,*k ,*rm,*k") + "=r,m ,*y,*y,?*y,?m,?r,?*y,*v,*v,*v,m ,?r,?*v,*k,*k ,*rm,*k") (match_operand:SI 1 "general_operand" - "g ,re,C ,*y,m ,*y,*y,r ,C ,*v,m ,*v,*v,r ,*r,*km,*k ,CBC"))] + "g ,re,C ,*y,Bk ,*y,*y,r ,C ,*v,Bk,*v,*v,r ,*r,*kBk,*k ,CBC"))] "!(MEM_P (operands[0]) && MEM_P (operands[1])) && ix86_hardreg_mov_ok (operands[0], operands[1])" { diff --git a/gcc/testsuite/gcc.target/i386/pr103275.c b/gcc/testsuite/gcc.target/i386/pr103275.c new file mode 100644 index 00000000000..c93413f3cde --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr103275.c @@ -0,0 +1,83 @@ +/* { dg-do compile { target ia32 } } */ +/* { dg-options "-O2 -march=tigerlake -fPIC" } */ +/* { dg-final { scan-assembler-not {(?n)kmovd.*@gotntpoff} } } */ + +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef uint32_t in_addr_t; +struct in_addr { in_addr_t s_addr; }; + +extern __thread const uint16_t * __libc_tsd_CTYPE_B __attribute__ ((tls_model ("initial-exec"))); +extern __thread int __libc_errno __attribute__ ((tls_model ("initial-exec"))); + +extern unsigned long strtoul (const char*, char**, int); +extern uint32_t __bswap_32 (in_addr_t); +int +inet_aton_end (const char *cp, struct in_addr *addr, const char **endp) +{ + static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff }; + in_addr_t val; + char c; + union iaddr + { + uint8_t bytes[4]; + uint32_t word; + } res; + uint8_t *pp = res.bytes; + int digit; + + int saved_errno = __libc_errno; + __libc_errno = 0; + res.word = 0; + c = *cp; + + for (;;) + { + if (c < '0' || c > '9') + goto ret_0; + { + char *endp; + unsigned long ul = strtoul (cp, &endp, 0); + if (ul == 0x7fffffffL && __libc_errno == 34) + goto ret_0; + if (ul > 0xfffffffful) + goto ret_0; + val = ul; + digit = cp != endp; + cp = endp; + } + c = *cp; + if (c == '.') + { + if (pp > res.bytes + 2 || val > 0xff) + goto ret_0; + *pp++ = val; + c = *++cp; + } + else + break; + } + + if (!(__libc_tsd_CTYPE_B[(int)c] & 8192)) + goto ret_0; + + if (!digit) + goto ret_0; + + if (val > max[pp - res.bytes]) + goto ret_0; + + if (addr != 0) + addr->s_addr = res.word | __bswap_32 (val); + *endp = cp; + + __libc_errno = saved_errno; + return 1; + + ret_0: + __libc_errno = saved_errno; + return 0; +}