diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 770112f3d7f..0b812c18a53 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2002-12-09 Richard Henderson + + * target.h (gcc_target): Add cannot_force_const_mem. + * target-def.h (TARGET_CANNOT_FORCE_CONST_MEM): New. + (TARGET_INITIALIZER): Add it. + * varasm.c (force_const_mem): Fail if cannot_force_const_mem. + * expr.c (emit_move_insn): Be prepared for force_const_mem to fail. + * reload1.c (reload): Likewise. + * hooks.c (hook_bool_rtx_false): New. + * hooks.h: Declare it. + + * config/i386/i386.c (ix86_cannot_force_const_mem): New. + (TARGET_CANNOT_FORCE_CONST_MEM): New. + (ix86_expand_move): Remove de-const-pooling hack. + Mon Dec 9 21:33:38 CET 2002 Jan Hubicka * toplev.c (dump_file): Fix order to match reality. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 7337312ac8e..42f6d93d3c3 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -763,6 +763,7 @@ struct ix86_address }; static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *)); +static bool ix86_cannot_force_const_mem PARAMS ((rtx)); static void ix86_encode_section_info PARAMS ((tree, int)) ATTRIBUTE_UNUSED; static const char *ix86_strip_name_encoding PARAMS ((const char *)) @@ -900,6 +901,8 @@ static enum x86_64_reg_class merge_classes PARAMS ((enum x86_64_reg_class, #undef TARGET_HAVE_TLS #define TARGET_HAVE_TLS true #endif +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM ix86_cannot_force_const_mem #undef TARGET_ASM_OUTPUT_MI_THUNK #define TARGET_ASM_OUTPUT_MI_THUNK x86_output_mi_thunk @@ -5050,6 +5053,17 @@ legitimate_constant_p (x) return true; } +/* Determine if it's legal to put X into the constant pool. This + is not possible for the address of thread-local symbols, which + is checked above. */ + +static bool +ix86_cannot_force_const_mem (x) + rtx x; +{ + return !legitimate_constant_p (x); +} + /* Determine if a given RTX is a valid constant address. */ bool @@ -7686,29 +7700,6 @@ ix86_expand_move (mode, operands) op0 = operands[0]; op1 = operands[1]; - /* ??? We have a slight problem. We need to say that tls symbols are - not legitimate constants so that reload does not helpfully reload - these constants from a REG_EQUIV, which we cannot handle. (Recall - that general- and local-dynamic address resolution requires a - function call.) - - However, if we say that tls symbols are not legitimate constants, - then emit_move_insn helpfully drop them into the constant pool. - - It is far easier to work around emit_move_insn than reload. Recognize - the MEM that we would have created and extract the symbol_ref. */ - - if (mode == Pmode - && GET_CODE (op1) == MEM - && RTX_UNCHANGING_P (op1)) - { - tmp = maybe_get_pool_constant (op1); - /* Note that we only care about symbolic constants here, which - unlike CONST_INT will always have a proper mode. */ - if (tmp && GET_MODE (tmp) == Pmode) - op1 = tmp; - } - if (tls_symbolic_operand (op1, Pmode)) { op1 = legitimize_address (op1, op1, VOIDmode); diff --git a/gcc/expr.c b/gcc/expr.c index 85d329f9ffc..f1b2271edd8 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -3146,6 +3146,12 @@ emit_move_insn (x, y) { y_cst = y; y = force_const_mem (mode, y); + + /* If the target's cannot_force_const_mem prevented the spill, + assume that the target's move expanders will also take care + of the non-legitimate constant. */ + if (!y) + y = y_cst; } } diff --git a/gcc/hooks.c b/gcc/hooks.c index 6569a38d7a0..3f212ef3e1b 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -114,3 +114,10 @@ hook_bool_tree_false (a) { return false; } + +bool +hook_bool_rtx_false (a) + rtx a ATTRIBUTE_UNUSED; +{ + return false; +} diff --git a/gcc/hooks.h b/gcc/hooks.h index 4e09da932a3..8c28194f6ac 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -28,6 +28,7 @@ bool hook_bool_tree_hwi_hwi_tree_false PARAMS ((tree, HOST_WIDE_INT, HOST_WIDE_INT, tree)); bool hook_bool_tree_hwi_hwi_tree_true PARAMS ((tree, HOST_WIDE_INT, HOST_WIDE_INT, tree)); +bool hook_bool_rtx_false PARAMS ((rtx)); void hook_void_tree_int PARAMS ((tree, int)); void hook_void_void PARAMS ((void)); diff --git a/gcc/reload1.c b/gcc/reload1.c index 2704dadab4d..0f5d688c8a5 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -817,8 +817,12 @@ reload (first, global) else if (LEGITIMATE_CONSTANT_P (x)) reg_equiv_constant[i] = x; else - reg_equiv_memory_loc[i] - = force_const_mem (GET_MODE (SET_DEST (set)), x); + { + reg_equiv_memory_loc[i] + = force_const_mem (GET_MODE (SET_DEST (set)), x); + if (!reg_equiv_memory_loc[i]) + continue; + } } else continue; diff --git a/gcc/target-def.h b/gcc/target-def.h index b866c858de7..154d58d47e9 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -241,6 +241,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /* In hook.c. */ #define TARGET_CANNOT_MODIFY_JUMPS_P hook_bool_void_false +#define TARGET_CANNOT_FORCE_CONST_MEM hook_bool_rtx_false #define TARGET_COMP_TYPE_ATTRIBUTES hook_int_tree_tree_1 #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES hook_void_tree #define TARGET_INSERT_ATTRIBUTES hook_void_tree_treeptr @@ -272,6 +273,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_EXPAND_BUILTIN, \ TARGET_SECTION_TYPE_FLAGS, \ TARGET_CANNOT_MODIFY_JUMPS_P, \ + TARGET_CANNOT_FORCE_CONST_MEM, \ TARGET_IN_SMALL_DATA_P, \ TARGET_BINDS_LOCAL_P, \ TARGET_ENCODE_SECTION_INFO, \ diff --git a/gcc/target.h b/gcc/target.h index d9475625414..0ac1c5aa17b 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -262,6 +262,9 @@ struct gcc_target not, at the current point in the compilation. */ bool (* cannot_modify_jumps_p) PARAMS ((void)); + /* True if the constant X cannot be placed in the constant pool. */ + bool (* cannot_force_const_mem) PARAMS ((rtx)); + /* True if EXP should be placed in a "small data" section. */ bool (* in_small_data_p) PARAMS ((tree)); diff --git a/gcc/testsuite/gcc.dg/tls/opt-4.c b/gcc/testsuite/gcc.dg/tls/opt-4.c new file mode 100644 index 00000000000..3a95688963b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tls/opt-4.c @@ -0,0 +1,53 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +struct A +{ + int a1; + int a2; +}; + +extern __thread const unsigned char *tcc1, **tcc2; + +extern inline const unsigned char ** __attribute__ ((const)) +foo (void) +{ + const unsigned char **a = &tcc1; + if (*a == 0) + *a = *tcc2 + 128; + return a; +} + +extern inline int +bar (const struct A *x) +{ + int a; + + if (x->a2 & 8) + return 0; + a = x->a1; + return a > 0 && ((*foo ())[a] & 64); +} + +int +baz (const struct A *x, char *y) +{ + const struct A *a; + + for (a = x; !!a->a1; a++) + if (! (x->a2 & 8)) + if (bar (a)) + { + *y++ = a->a1; + if (x->a1) + *y++ = ':'; + *y = '\0'; + } + return 0; +} + +/* Verify tcc1 and tcc2 variables show up only in the TLS access sequences. */ +/* { dg-final { scan-assembler "tcc1@" { target i?86-*-* x86_64-*-* } } } */ +/* { dg-final { scan-assembler "tcc2@" { target i?86-*-* x86_64-*-* } } } */ +/* { dg-final { scan-assembler-not "tcc1\[^@\]" { target i?86-*-* x86_64-*-* } } } */ +/* { dg-final { scan-assembler-not "tcc2\[^@\]" { target i?86-*-* x86_64-*-* } } } */ diff --git a/gcc/varasm.c b/gcc/varasm.c index 2ac3da5338c..f8b33d080a6 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -3209,6 +3209,10 @@ force_const_mem (mode, x) struct pool_constant *pool; unsigned int align; + /* If we're not allowed to drop X into the constant pool, don't. */ + if ((*targetm.cannot_force_const_mem) (x)) + return NULL_RTX; + /* Compute hash code of X. Search the descriptors for that hash code to see if any of them describes X. If yes, we have an rtx to use. */ hash = const_hash_rtx (mode, x);