--- /dev/null
+--- gcc/ada/link.c.jj Tue May 7 12:50:23 2002
++++ gcc/ada/link.c Wed Jun 5 14:45:32 2002
+@@ -158,11 +158,11 @@ const char *object_library_extension = "
+
+ #elif defined (linux)
+ const char *object_file_option = "";
+-const char *run_path_option = "-Wl,-rpath,";
+-char shared_libgnat_default = STATIC;
++const char *run_path_option = "";
++char shared_libgnat_default = SHARED;
+ int link_max = 2147483647;
+ unsigned char objlist_file_supported = 0;
+-unsigned char using_gnu_linker = 0;
++unsigned char using_gnu_linker = 1;
+ const char *object_library_extension = ".a";
+
+ #elif defined (__svr4__) && defined (i386)
+--- gcc/ada/Makefile.in.jj Wed Jun 5 16:06:56 2002
++++ gcc/ada/Makefile.in Wed Jun 5 16:27:33 2002
+@@ -134,7 +134,7 @@ MISCLIB =
+ objext = .o
+ exeext =
+ arext = .a
+-soext = .so
++soext = .so.1
+ shext =
+
+ HOST_CC=$(CC)
+@@ -1214,6 +1214,33 @@ ifeq ($(strip $(filter-out %86 linux%,$(
+ endif
+ endif
+
++ifeq ($(strip $(filter-out alpha% linux%,$(arch) $(osys))),)
++ MLIB_TGT=5lml-tgt
++ MISCLIB=
++ THREADSLIB=-lpthread
++ GNATLIB_SHARED=gnatlib-shared-dual
++ GMEM_LIB=gmemlib
++ LIBRARY_VERSION := $(strip $(shell grep Library_Version $(fsrcpfx)gnatvsn.ads | sed -e 's/.*GNAT Lib v\(.*\)[ "].*/\1/'))
++endif
++
++ifeq ($(strip $(filter-out sparc% linux%,$(arch) $(osys))),)
++ MLIB_TGT=5lml-tgt
++ MISCLIB=
++ THREADSLIB=-lpthread
++ GNATLIB_SHARED=gnatlib-shared-dual
++ GMEM_LIB=gmemlib
++ LIBRARY_VERSION := $(strip $(shell grep Library_Version $(fsrcpfx)gnatvsn.ads | sed -e 's/.*GNAT Lib v\(.*\)[ "].*/\1/'))
++endif
++
++ifeq ($(strip $(filter-out ia64 linux%,$(arch) $(osys))),)
++ MLIB_TGT=5lml-tgt
++ MISCLIB=
++ THREADSLIB=-lpthread
++ GNATLIB_SHARED=gnatlib-shared-dual
++ GMEM_LIB=gmemlib
++ LIBRARY_VERSION := $(strip $(shell grep Library_Version $(fsrcpfx)gnatvsn.ads | sed -e 's/.*GNAT Lib v\(.*\)[ "].*/\1/'))
++endif
++
+ ifeq ($(strip $(filter-out mips sgi irix%,$(targ))),)
+ ifeq ($(strip $(filter-out mips sgi irix6%,$(targ))),)
+ LIBGNAT_TARGET_PAIRS = \
+@@ -2179,6 +2179,9 @@ endif
+
+ gnatlib: ../stamp-gnatlib1 ../stamp-gnatlib2
+ # ../xgcc -B../ -dD -E ../tconfig.h $(INCLUDES) > rts/tconfig.h
++ $(RMDIR) save
++ $(MKDIR) save
++ $(MV) *.o save/
+ $(MAKE) -C rts CC="../../xgcc -B../../" \
+ INCLUDES="$(INCLUDES_FOR_SUBDIR) -I./../.." \
+ CFLAGS="$(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS) -DIN_RTS" \
+@@ -2192,6 +2195,8 @@ gnatlib: ../stamp-gnatlib1 ../stamp-gnat
+ srcdir=$(fsrcdir) \
+ -f ../Makefile \
+ $(GNATRTL_OBJS)
++ $(MV) save/*.o .
++ $(RMDIR) save
+ $(RM) rts/libgnat$(arext) rts/libgnarl$(arext)
+ $(AR) $(AR_FLAGS) rts/libgnat$(arext) \
+ $(addprefix rts/,$(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS))
+@@ -2315,12 +2315,12 @@ gnatlib-shared-default:
+ THREAD_KIND="$(THREAD_KIND)" \
+ gnatlib
+ $(RM) rts/libgnat$(soext) rts/libgnarl$(soext)
+- cd rts; ../../xgcc -B../../ -shared $(TARGET_LIBGCC2_CFLAGS) \
++ cd rts; ../../xgcc -B../../ -shared -shared-libgcc $(TARGET_LIBGCC2_CFLAGS) \
+ -o libgnat-$(LIBRARY_VERSION)$(soext) $(SO_OPTS)libgnat-$(LIBRARY_VERSION)$(soext) \
+ $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) $(MISCLIB) -lm
+ cd rts; ../../xgcc -B../../ -shared $(TARGET_LIBGCC2_CFLAGS) \
+ -o libgnarl-$(LIBRARY_VERSION)$(soext) $(SO_OPTS)libgnarl-$(LIBRARY_VERSION)$(soext) \
+- $(GNATRTL_TASKING_OBJS) $(THREADSLIB)
++ $(GNATRTL_TASKING_OBJS) $(THREADSLIB) ./libgnat-$(LIBRARY_VERSION)$(soext)
+ cd rts; $(LN) libgnat-$(LIBRARY_VERSION)$(soext) libgnat$(soext)
+ cd rts; $(LN) libgnarl-$(LIBRARY_VERSION)$(soext) libgnarl$(soext)
+
+@@ -2358,62 +2363,62 @@ TREE_H = $(srcdir)/../tree.h $(srcdir)/.
+
+ ada_extra_files : treeprs.ads einfo.h sinfo.h nmake.adb nmake.ads
+
+-b_gnat1.c : $(GNAT1_ADA_OBJS)
++b_gnat1.c : $(GNAT1_ADA_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnat1.c -n gnat1drv.ali
+ b_gnat1.o : b_gnat1.c
+
+-b_gnatb.c : $(GNATBIND_OBJS)
++b_gnatb.c : $(GNATBIND_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatb.c gnatbind.ali
+ b_gnatb.o : b_gnatb.c
+
+-b_gnatc.c : $(GNATCMD_OBJS)
++b_gnatc.c : $(GNATCMD_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatc.c gnatcmd.ali
+ b_gnatc.o : b_gnatc.c
+
+-b_gnatch.c : $(GNATCHOP_OBJS)
++b_gnatch.c : $(GNATCHOP_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatch.c gnatchop.ali
+ b_gnatch.o : b_gnatch.c
+
+-b_gnatkr.c : $(GNATKR_OBJS)
++b_gnatkr.c : $(GNATKR_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatkr.c gnatkr.ali
+ b_gnatkr.o : b_gnatkr.c
+
+-b_gnatl.c : $(GNATLINK_OBJS)
++b_gnatl.c : $(GNATLINK_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatl.c gnatlink.ali
+ b_gnatl.o : b_gnatl.c
+
+-b_gnatls.c : $(GNATLS_OBJS)
++b_gnatls.c : $(GNATLS_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatls.c gnatls.ali
+
+-b_gnatm.c : $(GNATMAKE_OBJS)
++b_gnatm.c : $(GNATMAKE_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatm.c gnatmake.ali
+ b_gnatm.o : b_gnatm.c
+
+-b_gnatmem.c : $(GNATMEM_OBJS)
++b_gnatmem.c : $(GNATMEM_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatmem.c gnatmem.ali
+ b_gnatmem.o : b_gnatmem.c
+
+-b_gnatp.c : $(GNATPREP_OBJS)
++b_gnatp.c : $(GNATPREP_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatp.c gnatprep.ali
+ b_gnatp.o : b_gnatp.c
+
+-b_gnatpa.c : $(GNATPSTA_OBJS)
++b_gnatpa.c : $(GNATPSTA_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatpa.c gnatpsta.ali
+ b_gnatpa.o : b_gnatpa.c
+
+-b_gnatps.c : $(GNATPSYS_OBJS)
++b_gnatps.c : $(GNATPSYS_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatps.c gnatpsys.ali
+ b_gnatps.o : b_gnatps.c
+
+-b_gnatxref.c : $(GNATXREF_OBJS)
++b_gnatxref.c : $(GNATXREF_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatxref.c gnatxref.ali
+ b_gnatxref.o : b_gnatxref.c
+
+-b_gnatfind.c : $(GNATFIND_OBJS)
++b_gnatfind.c : $(GNATFIND_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatfind.c gnatfind.ali
+ b_gnatfind.o : b_gnatfind.c
+
+-b_gnatdll.c : $(GNATDLL_OBJS)
++b_gnatdll.c : $(GNATDLL_OBJS) interfac.o
+ $(GNATBIND) $(ADA_INCLUDES) -o b_gnatdll.c gnatdll.ali
+ b_gnatdll.o : b_gnatdll.c
+
+--- gcc/ada/gnat_rm.texi.jj Tue Apr 23 20:27:39 2002
++++ gcc/ada/gnat_rm.texi Thu Jun 6 14:30:21 2002
+@@ -31,6 +31,10 @@
+ @settitle GNAT Reference Manual
+ @setchapternewpage odd
+ @syncodeindex fn cp
++@dircategory Programming
++@direntry
++* gnat_rm: (gnat_rm). GNAT Reference Manual
++@end direntry
+
+ @titlepage
+
+--- gcc/ada/gnat_ug.texi.jj Tue May 7 12:50:03 2002
++++ gcc/ada/gnat_ug.texi Thu Jun 6 14:30:33 2002
+@@ -75,6 +75,11 @@
+ @syncodeindex fn cp
+ @c %**end of header
+
++@dircategory Programming
++@direntry
++* gnat_ug: (gnat_ug). GNAT User's Guide
++@end direntry
++
+ @titlepage
+
+ @ifset vms
--- /dev/null
+2002-02-26 Jakub Jelinek <jakub@redhat.com>
+
+ * attribs.c (c_common_attribute_table): Add visibility.
+ (handle_visibility_attribute): New function.
+ * varasm.c (assemble_visibility): New function.
+ * output.h (assemble_visibility): Add prototype.
+ * tree.h (MODULE_LOCAL_P): Define.
+ * crtstuff.c (__dso_handle): Use visibility attribute.
+ * config/i386/i386.h (ENCODE_SECTION_INFO): Set SYMBOL_REF_FLAG
+ for MODULE_LOCAL_P symbols too.
+ * config/ia64/ia64.c (ia64_encode_section_info): Handle
+ MODULE_LOCAL_P symbols the same way as local symbols.
+ Add SDATA_NAME_FLAG_CHAR even if decl was explicitely forced
+ into .sdata/.sbss by the user.
+ * doc/extend.texi (Function Attributes): Document visibility
+ attribute.
+
+ * gcc.dg/ia64-visibility-1.c: New test.
+
+--- gcc/attribs.c 2002/02/25 22:38:52 1.14
++++ gcc/attribs.c 2002/02/26 21:17:14 1.15
+@@ -75,6 +75,8 @@ static tree handle_weak_attribute PARAMS
+ bool *));
+ static tree handle_alias_attribute PARAMS ((tree *, tree, tree, int,
+ bool *));
++static tree handle_visibility_attribute PARAMS ((tree *, tree, tree, int,
++ bool *));
+ static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
+ tree, int,
+ bool *));
+@@ -148,6 +150,8 @@ static const struct attribute_spec c_com
+ handle_deprecated_attribute },
+ { "vector_size", 1, 1, false, true, false,
+ handle_vector_size_attribute },
++ { "visibility", 1, 1, true, false, false,
++ handle_visibility_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+ };
+
+@@ -1061,6 +1065,50 @@ handle_alias_attribute (node, name, args
+ return NULL_TREE;
+ }
+
++/* Handle an "visibility" attribute; arguments as in
++ struct attribute_spec.handler. */
++
++static tree
++handle_visibility_attribute (node, name, args, flags, no_add_attrs)
++ tree *node;
++ tree name;
++ tree args;
++ int flags ATTRIBUTE_UNUSED;
++ bool *no_add_attrs;
++{
++ tree decl = *node;
++
++ if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
++ {
++ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
++ *no_add_attrs = true;
++ }
++ else
++ {
++ tree id;
++
++ id = TREE_VALUE (args);
++ if (TREE_CODE (id) != STRING_CST)
++ {
++ error ("visibility arg not a string");
++ *no_add_attrs = true;
++ return NULL_TREE;
++ }
++ if (strcmp (TREE_STRING_POINTER (id), "hidden")
++ && strcmp (TREE_STRING_POINTER (id), "protected")
++ && strcmp (TREE_STRING_POINTER (id), "internal"))
++ {
++ error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\"");
++ *no_add_attrs = true;
++ return NULL_TREE;
++ }
++
++ assemble_visibility (decl, TREE_STRING_POINTER (id));
++ }
++
++ return NULL_TREE;
++}
++
+ /* Handle a "no_instrument_function" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+--- gcc/varasm.c 2002/02/20 23:19:19 1.250
++++ gcc/varasm.c 2002/02/26 21:17:14 1.251
+@@ -5160,6 +5160,25 @@ assemble_alias (decl, target)
+ #endif
+ }
+
++/* Emit an assembler directive to set symbol for DECL visibility to
++ VISIBILITY_TYPE. */
++
++void
++assemble_visibility (decl, visibility_type)
++ tree decl;
++ const char *visibility_type ATTRIBUTE_UNUSED;
++{
++ const char *name;
++
++ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
++
++#ifdef HAVE_GAS_HIDDEN
++ fprintf (asm_out_file, "\t.%s\t%s\n", visibility_type, name);
++#else
++ warning ("visibility attribute not supported in this configuration; ignored");
++#endif
++}
++
+ /* Returns 1 if the target configuration supports defining public symbols
+ so that one of them will be chosen at link time instead of generating a
+ multiply-defined symbol error, whether through the use of weak symbols or
+--- gcc/output.h 2002/02/17 14:23:50 1.94
++++ gcc/output.h 2002/02/26 21:17:14 1.95
+@@ -255,6 +255,8 @@ extern void assemble_constant_align PARA
+
+ extern void assemble_alias PARAMS ((tree, tree));
+
++extern void assemble_visibility PARAMS ((tree, const char *));
++
+ /* Output a string of literal assembler code
+ for an `asm' keyword used between functions. */
+ extern void assemble_asm PARAMS ((tree));
+--- gcc/tree.h 2002/02/20 00:19:33 1.308
++++ gcc/tree.h 2002/02/26 21:17:14 1.309
+@@ -2283,6 +2283,11 @@ extern tree merge_attributes PARAMS ((t
+ extern tree merge_dllimport_decl_attributes PARAMS ((tree, tree));
+ #endif
+
++/* Return true if DECL will be always resolved to a symbol defined in the
++ same module (shared library or program). */
++#define MODULE_LOCAL_P(DECL) \
++ (lookup_attribute ("visibility", DECL_ATTRIBUTES (DECL)) != NULL)
++
+ /* Return a version of the TYPE, qualified as indicated by the
+ TYPE_QUALS, if one exists. If no qualified version exists yet,
+ return NULL_TREE. */
+--- gcc/crtstuff.c 2002/02/05 10:31:01 1.54
++++ gcc/crtstuff.c 2002/02/26 21:17:14 1.55
+@@ -213,13 +213,9 @@ STATIC void *__JCR_LIST__[]
+ in one DSO or the main program is not used in another object. The
+ dynamic linker takes care of this. */
+
+-/* XXX Ideally the following should be implemented using
+- __attribute__ ((__visibility__ ("hidden")))
+- but the __attribute__ support is not yet there. */
+ #ifdef HAVE_GAS_HIDDEN
+-asm (".hidden\t__dso_handle");
++extern void *__dso_handle __attribute__ ((__visibility__ ("hidden")));
+ #endif
+-
+ #ifdef CRTSTUFFS_O
+ void *__dso_handle = &__dso_handle;
+ #else
+--- gcc/config/i386/i386.h 2002/02/17 07:52:12 1.243
++++ gcc/config/i386/i386.h 2002/02/26 21:17:18 1.244
+@@ -2266,7 +2266,9 @@ do { \
+ \
+ SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
+ = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
+- || ! TREE_PUBLIC (DECL)); \
++ || ! TREE_PUBLIC (DECL) \
++ || (TREE_CODE (DECL) == VAR_DECL \
++ && MODULE_LOCAL_P (DECL))); \
+ } \
+ } \
+ } while (0)
+--- gcc/config/ia64/ia64.c 2002/01/21 02:24:02 1.139
++++ gcc/config/ia64/ia64.c 2002/02/26 22:41:48 1.141
+@@ -6897,13 +6904,14 @@ ia64_encode_section_info (decl)
+ statically allocated, but the space is allocated somewhere else. Such
+ decls can not be own data. */
+ if (! TARGET_NO_SDATA
+- && TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)
+- && ! (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+- && ! (TREE_PUBLIC (decl)
+- && (flag_pic
+- || (DECL_COMMON (decl)
+- && (DECL_INITIAL (decl) == 0
+- || DECL_INITIAL (decl) == error_mark_node))))
++ && ((TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)
++ && ! (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
++ && ! (TREE_PUBLIC (decl)
++ && (flag_pic
++ || (DECL_COMMON (decl)
++ && (DECL_INITIAL (decl) == 0
++ || DECL_INITIAL (decl) == error_mark_node)))))
++ || MODULE_LOCAL_P (decl))
+ /* Either the variable must be declared without a section attribute,
+ or the section must be sdata or sbss. */
+ && (DECL_SECTION_NAME (decl) == 0
+@@ -6923,9 +6931,12 @@ ia64_encode_section_info (decl)
+ ;
+
+ /* If this is an incomplete type with size 0, then we can't put it in
+- sdata because it might be too big when completed. */
+- else if (size > 0
+- && size <= (HOST_WIDE_INT) ia64_section_threshold
++ sdata because it might be too big when completed.
++ Objects bigger than threshold should have SDATA_NAME_FLAG_CHAR
++ added if they are in .sdata or .sbss explicitely. */
++ else if (((size > 0
++ && size <= (HOST_WIDE_INT) ia64_section_threshold)
++ || DECL_SECTION_NAME (decl))
+ && symbol_str[0] != SDATA_NAME_FLAG_CHAR)
+ {
+ size_t len = strlen (symbol_str);
+--- gcc/doc/extend.texi 2002/02/23 12:59:07 1.64
++++ gcc/doc/extend.texi 2002/02/26 21:17:17 1.65
+@@ -2198,7 +2198,7 @@ The @code{alias} attribute causes the de
+ alias for another symbol, which must be specified. For instance,
+
+ @smallexample
+-void __f () @{ /* do something */; @}
++void __f () @{ /* @r{Do something.} */; @}
+ void f () __attribute__ ((weak, alias ("__f")));
+ @end smallexample
+
+@@ -2206,6 +2206,19 @@ declares @samp{f} to be a weak alias for
+ mangled name for the target must be used.
+
+ Not all target machines support this attribute.
++
++@item visibility ("@var{visibility_type}")
++@cindex @code{visibility} attribute
++The @code{visibility} attribute on ELF targets causes the declaration
++to be emitted with hidden, protected or internal visibility.
++
++@smallexample
++void __attribute__ ((visibility ("protected")))
++f () @{ /* @r{Do something.} */; @}
++int i __attribute__ ((visibility ("hidden")));
++@end smallexample
++
++Not all ELF targets support this attribute.
+
+ @item regparm (@var{number})
+ @cindex functions that are passed arguments in registers on the 386
+--- gcc/testsuite/gcc.dg/ia64-visibility-1.c.jj Tue Feb 26 12:30:32 2002
++++ gcc/testsuite/gcc.dg/ia64-visibility-1.c Tue Feb 26 12:33:26 2002
+@@ -0,0 +1,36 @@
++/* Test visibility attribute. */
++/* { dg-do compile { target ia64*-*-linux* } } */
++/* { dg-options "-O2 -fpic" } */
++/* { dg-final { scan-assembler "\\.hidden.*variable_j" } } */
++/* { dg-final { scan-assembler "\\.hidden.*variable_m" } } */
++/* { dg-final { scan-assembler "\\.protected.*baz" } } */
++/* { dg-final { scan-assembler "gprel.*variable_i" } } */
++/* { dg-final { scan-assembler "gprel.*variable_j" } } */
++/* { dg-final { scan-assembler "ltoff.*variable_k" } } */
++/* { dg-final { scan-assembler "gprel.*variable_l" } } */
++/* { dg-final { scan-assembler "gprel.*variable_m" } } */
++/* { dg-final { scan-assembler "ltoff.*variable_n" } } */
++
++static int variable_i;
++int variable_j __attribute__((visibility ("hidden")));
++int variable_k;
++struct A { char a[64]; };
++static struct A variable_l __attribute__((section (".sbss")));
++struct A variable_m __attribute__((visibility ("hidden"), section(".sbss")));
++struct A variable_n __attribute__((section (".sbss")));
++
++int foo (void)
++{
++ return variable_i + variable_j + variable_k;
++}
++
++void bar (void)
++{
++ variable_l.a[10] = 0;
++ variable_m.a[10] = 0;
++ variable_n.a[10] = 0;
++}
++
++void __attribute__((visibility ("protected"))) baz (void)
++{
++}
--- /dev/null
+2002-03-06 Jakub Jelinek <jakub@redhat.com>
+
+ * config/i386/i386.h (REDO_SECTION_INFO_P): Define.
+
+2002-03-02 Richard Henderson <rth@redhat.com>
+
+ * config/i386/i386.h (ENCODE_SECTION_INFO): MODULE_LOCAL_P applies
+ to functions as well.
+
+2002-03-02 Richard Henderson <rth@redhat.com>
+
+ * attribs.c (handle_visibility_attribute): Don't call
+ assemble_visibility.
+ * varasm.c (maybe_assemble_visibility): New.
+ (assemble_start_function, assemble_variable, assemble_alias): Use it.
+
+--- gcc/config/i386/i386.h.jj Tue Jun 4 18:54:32 2002
++++ gcc/config/i386/i386.h Tue Jun 4 18:54:42 2002
+@@ -2268,12 +2268,13 @@ do { \
+ SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
+ = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
+ || ! TREE_PUBLIC (DECL) \
+- || (TREE_CODE (DECL) == VAR_DECL \
+- && MODULE_LOCAL_P (DECL))); \
++ || MODULE_LOCAL_P (DECL)); \
+ } \
+ } \
+ } while (0)
+
++#define REDO_SECTION_INFO_P(DECL) 1
++
+ /* The `FINALIZE_PIC' macro serves as a hook to emit these special
+ codes once the function is being compiled into assembly code, but
+ not before. (It is not done before, because in the case of
+--- gcc/varasm.c.jj Tue Jun 4 18:54:32 2002
++++ gcc/varasm.c Tue Jun 4 18:54:42 2002
+@@ -167,6 +167,7 @@ static unsigned min_align PARAMS ((unsi
+ static void output_constructor PARAMS ((tree, HOST_WIDE_INT,
+ unsigned int));
+ static void globalize_decl PARAMS ((tree));
++static void maybe_assemble_visibility PARAMS ((tree));
+ static int in_named_entry_eq PARAMS ((const PTR, const PTR));
+ static hashval_t in_named_entry_hash PARAMS ((const PTR));
+ #ifdef ASM_OUTPUT_BSS
+@@ -1238,6 +1239,8 @@ assemble_start_function (decl, fnname)
+ }
+
+ globalize_decl (decl);
++
++ maybe_assemble_visibility (decl);
+ }
+
+ /* Do any machine/system dependent processing of the function name */
+@@ -1591,6 +1594,9 @@ assemble_variable (decl, top_level, at_e
+ DECL_ALIGN (decl) = align;
+ set_mem_align (decl_rtl, align);
+
++ if (TREE_PUBLIC (decl))
++ maybe_assemble_visibility (decl);
++
+ /* Handle uninitialized definitions. */
+
+ if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+@@ -5167,7 +5173,11 @@ assemble_alias (decl, target)
+ #ifdef ASM_OUTPUT_DEF
+ /* Make name accessible from other files, if appropriate. */
+ if (TREE_PUBLIC (decl))
+- globalize_decl (decl);
++ {
++ globalize_decl (decl);
++
++ maybe_assemble_visibility (decl);
++ }
+
+ #ifdef ASM_OUTPUT_DEF_FROM_DECLS
+ ASM_OUTPUT_DEF_FROM_DECLS (asm_out_file, decl, target);
+@@ -5213,6 +5223,21 @@ assemble_visibility (decl, visibility_ty
+ #endif
+ }
+
++/* A helper function to call assemble_visibility when needed for a decl. */
++
++static void
++maybe_assemble_visibility (decl)
++ tree decl;
++{
++ tree visibility = lookup_attribute ("visibility", DECL_ATTRIBUTES (decl));
++ if (visibility)
++ {
++ const char *type
++ = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (visibility)));
++ assemble_visibility (decl, type);
++ }
++}
++
+ /* Returns 1 if the target configuration supports defining public symbols
+ so that one of them will be chosen at link time instead of generating a
+ multiply-defined symbol error, whether through the use of weak symbols or
+--- gcc/attribs.c.jj Tue Jun 4 18:54:32 2002
++++ gcc/attribs.c Tue Jun 4 18:54:42 2002
+@@ -1101,8 +1101,6 @@ handle_visibility_attribute (node, name,
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+-
+- assemble_visibility (decl, TREE_STRING_POINTER (id));
+ }
+
+ return NULL_TREE;
--- /dev/null
+2002-07-31 Jakub Jelinek <jakub@redhat.com>
+
+ * varasm.c (assemble_visibility): Strip name encoding.
+
+ * gcc.dg/ia64-visibility-2.c: New test.
+
+--- gcc/testsuite/gcc.dg/ia64-visibility-2.c.jj 2002-07-31 16:31:50.000000000 +0200
++++ gcc/testsuite/gcc.dg/ia64-visibility-2.c 2002-07-31 16:32:36.000000000 +0200
+@@ -0,0 +1,15 @@
++/* Test visibility attribute. */
++/* { dg-do link { target ia64*-*-linux* } } */
++/* { dg-options "-O2 -fpic" } */
++
++int foo (int x);
++int bar (int x) __asm__ ("foo") __attribute__ ((visibility ("hidden")));
++int bar (int x)
++{
++ return x;
++}
++
++int main ()
++{
++ return 0;
++}
+--- gcc/varasm.c.jj 2002-07-30 12:49:45.000000000 +0200
++++ gcc/varasm.c 2002-07-31 16:20:22.000000000 +0200
+@@ -5227,7 +5227,7 @@ assemble_visibility (decl, visibility_ty
+ {
+ const char *name;
+
+- name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
++ STRIP_NAME_ENCODING (name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+
+ #ifdef HAVE_GAS_HIDDEN
+ fprintf (asm_out_file, "\t.%s\t%s\n", visibility_type, name);
--- /dev/null
+2002-08-23 Jakub Jelinek <jakub@redhat.com>
+
+ * config/alpha/alpha.c (alpha_encode_section_info): Use
+ MODULE_LOCAL_P.
+
+--- gcc/config/alpha/alpha.c.jj 2002-05-30 11:12:20.000000000 +0200
++++ gcc/config/alpha/alpha.c 2002-08-23 12:05:30.000000000 +0200
+@@ -1594,7 +1594,7 @@ alpha_encode_section_info (decl)
+ /* Linkonce and weak data is never local. */
+ else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+ is_local = false;
+- else if (! TREE_PUBLIC (decl))
++ else if (! TREE_PUBLIC (decl) || MODULE_LOCAL_P (decl))
+ is_local = true;
+ /* If PIC, then assume that any global name can be overridden by
+ symbols resolved from other modules. */
--- /dev/null
+2002-08-28 Jakub Jelinek <jakub@redhat.com>
+
+ * config/alpha/alpha.c (alpha_encode_section_info): Check static and
+ visibility before DECL_EXTERNAL.
+
+--- gcc/config/alpha/alpha.c.jj 2002-08-28 11:20:29.000000000 +0200
++++ gcc/config/alpha/alpha.c 2002-08-28 21:50:55.000000000 +0200
+@@ -1589,13 +1589,13 @@ alpha_encode_section_info (decl)
+
+ /* A variable is considered "local" if it is defined in this module. */
+
+- if (DECL_EXTERNAL (decl))
++ if (! TREE_PUBLIC (decl) || MODULE_LOCAL_P (decl))
++ is_local = true;
++ else if (DECL_EXTERNAL (decl))
+ is_local = false;
+ /* Linkonce and weak data is never local. */
+ else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+ is_local = false;
+- else if (! TREE_PUBLIC (decl) || MODULE_LOCAL_P (decl))
+- is_local = true;
+ /* If PIC, then assume that any global name can be overridden by
+ symbols resolved from other modules. */
+ else if (flag_pic)
--- /dev/null
+--- boehm-gc/configure.in.jj Tue Dec 18 01:27:56 2001
++++ boehm-gc/configure.in Fri Jan 25 14:10:17 2002
+@@ -57,11 +57,18 @@ AC_ARG_ENABLE(parallel-mark,
+ esac]
+ )
+
++AC_CHECK_LIB(dl, dlopen, [
++EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
++LIBGCJGC_EXTRA_LDFLAGS="-ldl"
++])
++AC_SUBST(EXTRA_TEST_LIBS)
++
+ INCLUDES=-I${srcdir}/include
+ THREADLIBS=
+ case "$THREADS" in
+ no | none | single)
+ THREADS=none
++ LIBGCJGC_EXTRA_LDFLAGS=
+ ;;
+ posix | pthreads)
+ THREADS=posix
+@@ -105,6 +112,7 @@ case "$THREADS" in
+ ;;
+ *-*-cygwin*)
+ THREADLIBS=
++ LIBGCJGC_EXTRA_LDFLAGS=
+ ;;
+ esac
+ ;;
+@@ -116,9 +124,7 @@ case "$THREADS" in
+ ;;
+ esac
+ AC_SUBST(THREADLIBS)
+-
+-AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
+-AC_SUBST(EXTRA_TEST_LIBS)
++AC_SUBST(LIBGCJGC_EXTRA_LDFLAGS)
+
+ target_all=libgcjgc.la
+ AC_SUBST(target_all)
+--- boehm-gc/configure.jj Thu Jan 3 14:25:13 2002
++++ boehm-gc/configure Fri Jan 25 14:10:36 2002
+@@ -2647,11 +2647,57 @@ if test "${enable_parallel_mark+set}" =
+ fi
+
+
++echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
++echo "configure:2635: checking for dlopen in -ldl" >&5
++ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
++if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
++ echo $ac_n "(cached) $ac_c" 1>&6
++else
++ ac_save_LIBS="$LIBS"
++LIBS="-ldl $LIBS"
++cat > conftest.$ac_ext <<EOF
++#line 2643 "configure"
++#include "confdefs.h"
++/* Override any gcc2 internal prototype to avoid an error. */
++/* We use char because int might match the return type of a gcc2
++ builtin and then its argument prototype would still apply. */
++char dlopen();
++
++int main() {
++dlopen()
++; return 0; }
++EOF
++if { (eval echo configure:2654: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
++ rm -rf conftest*
++ eval "ac_cv_lib_$ac_lib_var=yes"
++else
++ echo "configure: failed program was:" >&5
++ cat conftest.$ac_ext >&5
++ rm -rf conftest*
++ eval "ac_cv_lib_$ac_lib_var=no"
++fi
++rm -f conftest*
++LIBS="$ac_save_LIBS"
++
++fi
++if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
++ echo "$ac_t""yes" 1>&6
++
++EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
++LIBGCJGC_EXTRA_LDFLAGS="-ldl"
++
++else
++ echo "$ac_t""no" 1>&6
++fi
++
++
++
+ INCLUDES=-I${srcdir}/include
+ THREADLIBS=
+ case "$THREADS" in
+ no | none | single)
+ THREADS=none
++ LIBGCJGC_EXTRA_LDFLAGS=
+ ;;
+ posix | pthreads)
+ THREADS=posix
+@@ -2736,6 +2782,7 @@ EOF
+ ;;
+ *-*-cygwin*)
+ THREADLIBS=
++ LIBGCJGC_EXTRA_LDFLAGS=
+ ;;
+ esac
+ ;;
+@@ -2758,48 +2805,6 @@ EOF
+ esac
+
+
+-echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+-echo "configure:2763: checking for dlopen in -ldl" >&5
+-ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
+-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+- echo $ac_n "(cached) $ac_c" 1>&6
+-else
+- ac_save_LIBS="$LIBS"
+-LIBS="-ldl $LIBS"
+-cat > conftest.$ac_ext <<EOF
+-#line 2771 "configure"
+-#include "confdefs.h"
+-/* Override any gcc2 internal prototype to avoid an error. */
+-/* We use char because int might match the return type of a gcc2
+- builtin and then its argument prototype would still apply. */
+-char dlopen();
+-
+-int main() {
+-dlopen()
+-; return 0; }
+-EOF
+-if { (eval echo configure:2782: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+- rm -rf conftest*
+- eval "ac_cv_lib_$ac_lib_var=yes"
+-else
+- echo "configure: failed program was:" >&5
+- cat conftest.$ac_ext >&5
+- rm -rf conftest*
+- eval "ac_cv_lib_$ac_lib_var=no"
+-fi
+-rm -f conftest*
+-LIBS="$ac_save_LIBS"
+-
+-fi
+-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+- echo "$ac_t""yes" 1>&6
+- EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
+-else
+- echo "$ac_t""no" 1>&6
+-fi
+-
+-
+-
+ target_all=libgcjgc.la
+
+
+@@ -3215,8 +3220,9 @@ s%@OBJEXT@%$OBJEXT%g
+ s%@STRIP@%$STRIP%g
+ s%@LIBTOOL@%$LIBTOOL%g
+ s%@CXXCPP@%$CXXCPP%g
+-s%@THREADLIBS@%$THREADLIBS%g
+ s%@EXTRA_TEST_LIBS@%$EXTRA_TEST_LIBS%g
++s%@THREADLIBS@%$THREADLIBS%g
++s%@LIBGCJGC_EXTRA_LDFLAGS@%$LIBGCJGC_EXTRA_LDFLAGS%g
+ s%@target_all@%$target_all%g
+ s%@INCLUDES@%$INCLUDES%g
+ s%@CXXINCLUDES@%$CXXINCLUDES%g
+--- boehm-gc/Makefile.am.jj Mon Oct 22 11:06:57 2001
++++ boehm-gc/Makefile.am Fri Jan 25 14:11:35 2002
+@@ -37,7 +37,8 @@ solaris_pthreads.c solaris_threads.c spe
+ # linuxthread semaphore functions get linked:
+ libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
+ libgcjgc_la_DEPENDENCIES = @addobjs@
+-libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir)
++libgcjgc_la_LDFLAGS = @LIBGCJGC_EXTRA_LDFLAGS@ -version-info 1:1:0 \
++ -rpath $(toolexeclibdir)
+
+ EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s \
+ mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
+--- boehm-gc/Makefile.in.jj Thu Jan 3 14:25:13 2002
++++ boehm-gc/Makefile.in Fri Jan 25 14:12:03 2002
+@@ -118,7 +118,8 @@ libgcjgc_la_SOURCES = allchblk.c alloc.c
+ # linuxthread semaphore functions get linked:
+ libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
+ libgcjgc_la_DEPENDENCIES = @addobjs@
+-libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir)
++libgcjgc_la_LDFLAGS = @LIBGCJGC_EXTRA_LDFLAGS@ -version-info 1:1:0 \
++ -rpath $(toolexeclibdir)
+
+ EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s rs6000_mach_dep.s sparc_mach_dep.s sparc_netbsd_mach_dep.s sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+
--- /dev/null
+2001-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * tree-inline.c (initialize_inlined_parameters): Fail if less
+ arguments are passed than expected.
+ (expand_call_inline): Cleanup if initialize_inlined_parameters
+ fails.
+
+ * g++.dg/other/inline1.C: New test.
+
+--- gcc/tree-inline.c.jj Tue Oct 9 16:03:13 2001
++++ gcc/tree-inline.c Fri Oct 12 17:08:23 2001
+@@ -474,17 +474,25 @@ initialize_inlined_parameters (id, args,
+
+ /* Loop through the parameter declarations, replacing each with an
+ equivalent VAR_DECL, appropriately initialized. */
+- for (p = parms, a = args; p;
+- a = a ? TREE_CHAIN (a) : a, p = TREE_CHAIN (p))
++ for (p = parms, a = args; p; a = TREE_CHAIN (a), p = TREE_CHAIN (p))
+ {
+ tree init_stmt;
+ tree var;
+ tree value;
+ tree cleanup;
+
++ if (a == NULL_TREE)
++ {
++ pop_srcloc ();
++ /* If less arguments were passed than actually required,
++ issue warning and avoid inlining. */
++ warning ("too few arguments passed to inline function, suppressing inlining");
++ return error_mark_node;
++ }
++
+ /* Find the initializer. */
+ value = (*lang_hooks.tree_inlining.convert_parm_for_inlining)
+- (p, a ? TREE_VALUE (a) : NULL_TREE, fn);
++ (p, TREE_VALUE (a), fn);
+
+ /* If the parameter is never assigned to, we may not need to
+ create a new variable here at all. Instead, we may be able
+@@ -863,6 +871,14 @@ expand_call_inline (tp, walk_subtrees, d
+
+ /* Initialize the parameters. */
+ arg_inits = initialize_inlined_parameters (id, TREE_OPERAND (t, 1), fn);
++ if (arg_inits == error_mark_node)
++ {
++ /* Clean up. */
++ splay_tree_delete (id->decl_map);
++ id->decl_map = st;
++ return NULL_TREE;
++ }
++
+ /* Expand any inlined calls in the initializers. Do this before we
+ push FN on the stack of functions we are inlining; we want to
+ inline calls to FN that appear in the initializers for the
+--- gcc/testsuite/g++.dg/other/inline1.C.jj Fri Oct 12 16:54:05 2001
++++ gcc/testsuite/g++.dg/other/inline1.C Fri Oct 12 17:14:35 2001
+@@ -0,0 +1,38 @@
++// { dg-do compile { target i?86-*-* } }
++// { dg-options -O }
++
++typedef unsigned int u4;
++typedef unsigned long long u8;
++typedef u8 (*u8tou8)(u8);
++
++struct C {
++ static inline u8 a(u4 x, u4 y);
++ static inline u8 b(unsigned char *p) { return c(*(u8 *)p); }
++ static inline u8 c(u8 x) { // { dg-warning "too few arguments" "too few" }
++ return ((u8tou8)a)(x);
++ }
++};
++
++inline u8 C::a(u4 x, u4 y) {
++ return x + y;
++}
++
++u8 n = 0x123456789abcdef;
++
++struct B {
++ unsigned char *e;
++ B() { e = (unsigned char *) &n; }
++ u8 f() {
++ return C::b(e);
++ }
++};
++
++struct A {
++ B *g;
++ void foo ();
++};
++
++void A::foo ()
++{
++ g->f();
++}
--- /dev/null
+2002-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/opt/nrv5.C: New test.
+
+2002-07-05 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/opt/nrv4.C: New test.
+
+2002-04-09 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/opt/nrv3.C: New test.
+
+--- gcc/testsuite/g++.dg/opt/nrv3.C.jj Thu Apr 11 16:25:15 2002
++++ gcc/testsuite/g++.dg/opt/nrv3.C Tue Apr 9 19:02:43 2002
+@@ -0,0 +1,24 @@
++// PR optimization/6189
++// Bug: we forgot about foo's nrv after writing it out.
++// { dg-options -O3 }
++// { dg-do run }
++
++struct A
++{
++ int i;
++};
++
++
++A foo ()
++{
++ A a;
++ a.i = 42;
++ return a;
++}
++
++
++int main()
++{
++ A b = foo();
++ return b.i != 42;
++}
+--- gcc/testsuite/g++.dg/opt/nrv4.C.jj Thu Apr 11 16:25:15 2002
++++ gcc/testsuite/g++.dg/opt/nrv4.C Fri Jul 5 17:16:56 2002
+@@ -0,0 +1,23 @@
++// PR optimization/7145
++// Bug: The NRV optimization caused us to lose the initializer for 'ret'.
++// { dg-options -O }
++// { dg-do run }
++
++struct GdkColor {
++ long pixel;
++ short red;
++ short green;
++ short blue;
++};
++
++inline GdkColor mkcolor() {
++ GdkColor ret={0,1,2,3};
++ return ret;
++}
++
++int
++main()
++{
++ GdkColor col=mkcolor();
++ return (col.pixel != 0 || col.red != 1 || col.green != 2 || col.blue != 3);
++}
+--- gcc/testsuite/g++.dg/opt/nrv5.C.jj Thu Apr 11 16:25:15 2002
++++ gcc/testsuite/g++.dg/opt/nrv5.C Thu Jul 11 11:29:33 2002
+@@ -0,0 +1,52 @@
++// Test for the named return value optimization with inlining.
++// Contributed by Jakub Jelinek <jakub@redhat.com>.
++// { dg-do run }
++// { dg-options -O2 }
++
++enum E { E0, E1, E2, E3 };
++
++struct S
++{
++ E s0 : 2;
++ bool s1 : 1, s2 : 1, s3 : 1, s4 : 1, s5 : 1, s6 : 1;
++ S () : s1 (true), s2 (false), s0 (E1), s3 (true), s4 (false), s5 (true), s6 (false) {}
++ void foo (E x) { this->s0 = x; }
++};
++
++inline S foo ()
++{
++ S s;
++ s.foo (E0);
++ return s;
++}
++
++inline S bar ()
++{
++ S s;
++ s.foo (E2);
++ return s;
++}
++
++void check (S &s, bool isfoo);
++
++void test (bool isfoo)
++{
++ S a = isfoo ? foo () : bar ();
++ check (a, isfoo);
++}
++
++extern "C" void abort ();
++
++void check (S &s, bool isfoo)
++{
++ if (! s.s1 || s.s2 || ! s.s3 || s.s4 || ! s.s5 || s.s6)
++ abort ();
++ if (s.s0 != (isfoo ? E0 : E2))
++ abort ();
++}
++
++int main ()
++{
++ test (true);
++ test (false);
++}
--- /dev/null
+2002-05-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/6794
+ * decl.c (cp_make_fname_decl): If outside of function, emit
+ the variable immediately.
+ * call.c (build_call): Avoid crashing when noreturn function
+ is called outside of function context.
+
+ * g++.dg/ext/pretty1.C: New test.
+ * g++.dg/ext/pretty2.C: New test.
+
+--- gcc/cp/decl.c.jj Tue May 21 20:27:10 2002
++++ gcc/cp/decl.c Fri May 24 17:28:16 2002
+@@ -6772,7 +6772,10 @@ cp_make_fname_decl (id, type_dep)
+ TREE_USED (decl) = 1;
+
+ cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
+-
++
++ if (!current_function_decl)
++ rest_of_decl_compilation (decl, 0, 1, 0);
++
+ return decl;
+ }
+
+--- gcc/cp/call.c.jj Mon Apr 15 14:48:51 2002
++++ gcc/cp/call.c Fri May 24 12:49:22 2002
+@@ -408,7 +408,7 @@ build_call (function, parms)
+ nothrow = ((decl && TREE_NOTHROW (decl))
+ || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (function))));
+
+- if (decl && TREE_THIS_VOLATILE (decl))
++ if (decl && TREE_THIS_VOLATILE (decl) && current_function_decl)
+ current_function_returns_abnormally = 1;
+
+ if (decl && TREE_DEPRECATED (decl))
+--- gcc/testsuite/g++.dg/ext/pretty1.C.jj Fri May 24 18:09:27 2002
++++ gcc/testsuite/g++.dg/ext/pretty1.C Fri May 24 18:13:10 2002
+@@ -0,0 +1,67 @@
++// PR c++/6794
++// Test whether __PRETTY_FUNCTION__ works in templates, functions and
++// in initializers at global scope
++// { dg-do compile }
++// { dg-options "" }
++
++extern "C" void __assert_fail (const char *, const char *,
++ unsigned int, const char *)
++ throw() __attribute__((noreturn));
++extern "C" void abort (void);
++extern "C" void exit (int);
++
++#define str(expr) #expr
++#define assert(expr) \
++ ((expr) ? 0 : (__assert_fail (str(expr), __FILE__, __LINE__, \
++ __PRETTY_FUNCTION__), 0))
++
++int __attribute__((noinline))
++foo (void)
++{
++ return 1;
++}
++
++template<class T> int
++bar (T)
++{
++ return (assert (foo ()), 1);
++}
++
++template<> int
++bar<int> (int)
++{
++ return (assert (foo ()), 2);
++}
++
++int a = (assert (foo ()), 1);
++int b = (assert (foo ()), 2);
++
++int
++main ()
++{
++ double c = 1.0;
++ unsigned char *d = 0;
++ int e = (assert (foo ()), 3);
++
++ bar (c);
++ bar (d);
++ bar (e);
++}
++
++namespace N
++{
++ int f = (assert (foo ()), 4);
++}
++
++void __attribute__((noinline))
++__assert_fail (const char *cond, const char *file, unsigned int line,
++ const char *pretty) throw ()
++{
++ abort ();
++}
++
++// { dg-final { scan-assembler "int bar\\(T\\).*with T = int" } }
++// { dg-final { scan-assembler "top level" } }
++// { dg-final { scan-assembler "int main\\(\\)" } }
++// { dg-final { scan-assembler "int bar\\(T\\).*with T = double" } }
++// { dg-final { scan-assembler "int bar\\(T\\).*with T = unsigned char\*" } }
+--- gcc/testsuite/g++.dg/ext/pretty2.C.jj Fri May 24 18:09:27 2002
++++ gcc/testsuite/g++.dg/ext/pretty2.C Fri May 24 18:13:42 2002
+@@ -0,0 +1,61 @@
++// PR c++/6794
++// Test whether __PRETTY_FUNCTION__ works in templates, functions and
++// in initializers at global scope
++// { dg-do run }
++// { dg-options "" }
++
++extern "C" void __assert_fail (const char *, const char *,
++ unsigned int, const char *)
++ throw() __attribute__((noreturn));
++extern "C" void abort (void);
++extern "C" void exit (int);
++
++#define str(expr) #expr
++#define assert(expr) \
++ ((expr) ? 0 : (__assert_fail (str(expr), __FILE__, __LINE__, \
++ __PRETTY_FUNCTION__), 0))
++
++int __attribute__((noinline))
++foo (void)
++{
++ return 1;
++}
++
++template<class T> int
++bar (T)
++{
++ return (assert (foo ()), 1);
++}
++
++template<> int
++bar<int> (int)
++{
++ return (assert (foo ()), 2);
++}
++
++int a = (assert (foo ()), 1);
++int b = (assert (foo ()), 2);
++
++int
++main ()
++{
++ double c = 1.0;
++ unsigned char *d = 0;
++ int e = (assert (foo ()), 3);
++
++ bar (c);
++ bar (d);
++ bar (e);
++}
++
++namespace N
++{
++ int f = (assert (foo ()), 4);
++}
++
++void __attribute__((noinline))
++__assert_fail (const char *cond, const char *file, unsigned int line,
++ const char *pretty) throw ()
++{
++ abort ();
++}
--- /dev/null
+2002-08-22 Jason Merrill <jason@redhat.com>
+
+ * langhooks-def.h (LANG_HOOKS_EXPR_SIZE): New macro.
+ * langhooks.c (lhd_expr_size): Define default.
+ * langhooks.h (struct lang_hooks): Add expr_size.
+ * explow.c (expr_size): Call it.
+ (int_expr_size): New fn.
+ * expr.h: Declare it.
+ * expr.c (expand_expr) [CONSTRUCTOR]: Use it to calculate how
+ much to store.
+cp/
+ PR c++/5607
+ * search.c (check_final_overrider): No longer static.
+ * class.c (update_vtable_entry_for_fn): Call it.
+ * cp-tree.h: Adjust.
+
+ * cp-lang.c (LANG_HOOKS_EXPR_SIZE): Define.
+ (cp_expr_size): New fn.
+ * call.c (convert_arg_to_ellipsis): Promote non-POD warning to error.
+ * typeck.c (build_modify_expr): Don't use save_expr on an lvalue.
+
+--- gcc/cp/call.c.jj 2002-04-15 14:48:51.000000000 +0200
++++ gcc/cp/call.c 2002-08-23 13:51:08.000000000 +0200
+@@ -4022,9 +4022,12 @@ convert_arg_to_ellipsis (arg)
+
+ if (arg != error_mark_node && ! pod_type_p (TREE_TYPE (arg)))
+ {
+- /* Undefined behaviour [expr.call] 5.2.2/7. */
+- warning ("cannot pass objects of non-POD type `%#T' through `...'",
+- TREE_TYPE (arg));
++ /* Undefined behaviour [expr.call] 5.2.2/7. We used to just warn
++ here and do a bitwise copy, but now cp_expr_size will abort if we
++ try to do that. */
++ error ("cannot pass objects of non-POD type `%#T' through `...'",
++ TREE_TYPE (arg));
++ arg = error_mark_node;
+ }
+
+ return arg;
+--- gcc/cp/class.c.jj 2002-08-05 18:30:31.000000000 +0200
++++ gcc/cp/class.c 2002-08-23 13:51:08.000000000 +0200
+@@ -2454,6 +2454,10 @@ update_vtable_entry_for_fn (t, binfo, fn
+ if (overrider == error_mark_node)
+ return;
+
++ /* Check for unsupported covariant returns again now that we've
++ calculated the base offsets. */
++ check_final_overrider (TREE_PURPOSE (overrider), fn);
++
+ /* Assume that we will produce a thunk that convert all the way to
+ the final overrider, and not to an intermediate virtual base. */
+ virtual_base = NULL_TREE;
+--- gcc/cp/cp-lang.c.jj 2002-05-25 00:02:21.000000000 +0200
++++ gcc/cp/cp-lang.c 2002-08-23 13:51:08.000000000 +0200
+@@ -28,7 +28,8 @@ Boston, MA 02111-1307, USA. */
+ #include "langhooks.h"
+ #include "langhooks-def.h"
+
+-static HOST_WIDE_INT cxx_get_alias_set PARAMS ((tree));
++static HOST_WIDE_INT cxx_get_alias_set PARAMS ((tree));
++static tree cp_expr_size PARAMS ((tree));
+
+ #undef LANG_HOOKS_NAME
+ #define LANG_HOOKS_NAME "GNU C++"
+@@ -91,6 +92,8 @@ static HOST_WIDE_INT cxx_get_alias_set P
+ #define LANG_HOOKS_TREE_DUMP_DUMP_TREE_FN cp_dump_tree
+ #undef LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN
+ #define LANG_HOOKS_TREE_DUMP_TYPE_QUALS_FN cp_type_quals
++#undef LANG_HOOKS_EXPR_SIZE
++#define LANG_HOOKS_EXPR_SIZE cp_expr_size
+
+ /* Each front end provides its own hooks, for toplev.c. */
+ const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+@@ -108,3 +111,28 @@ cxx_get_alias_set (t)
+
+ return c_common_get_alias_set (t);
+ }
++
++/* Langhook for expr_size: Tell the backend that the value of an expression
++ of non-POD class type does not include any tail padding; a derived class
++ might have allocated something there. */
++
++static tree
++cp_expr_size (exp)
++ tree exp;
++{
++ if (CLASS_TYPE_P (TREE_TYPE (exp)))
++ {
++ /* The backend should not be interested in the size of an expression
++ of a type with both of these set; all copies of such types must go
++ through a constructor or assignment op. */
++ if (TYPE_HAS_COMPLEX_INIT_REF (TREE_TYPE (exp))
++ && TYPE_HAS_COMPLEX_ASSIGN_REF (TREE_TYPE (exp)))
++ abort ();
++ /* This would be wrong for a type with virtual bases, but they are
++ caught by the abort above. */
++ return CLASSTYPE_SIZE_UNIT (TREE_TYPE (exp));
++ }
++ else
++ /* Use the default code. */
++ return lhd_expr_size (exp);
++}
+--- gcc/cp/cp-tree.h.jj 2002-07-27 01:31:05.000000000 +0200
++++ gcc/cp/cp-tree.h 2002-08-23 13:51:08.000000000 +0200
+@@ -4084,6 +4084,7 @@ extern tree lookup_conversions PARAMS
+ extern tree binfo_for_vtable PARAMS ((tree));
+ extern tree binfo_from_vbase PARAMS ((tree));
+ extern tree look_for_overrides_here PARAMS ((tree, tree));
++extern int check_final_overrider PARAMS ((tree, tree));
+ extern tree dfs_walk PARAMS ((tree,
+ tree (*) (tree, void *),
+ tree (*) (tree, void *),
+--- gcc/cp/search.c.jj 2002-04-23 20:29:00.000000000 +0200
++++ gcc/cp/search.c 2002-08-23 13:51:08.000000000 +0200
+@@ -100,7 +100,6 @@ static tree dfs_push_decls PARAMS ((tree
+ static tree dfs_unuse_fields PARAMS ((tree, void *));
+ static tree add_conversions PARAMS ((tree, void *));
+ static int covariant_return_p PARAMS ((tree, tree));
+-static int check_final_overrider PARAMS ((tree, tree));
+ static int look_for_overrides_r PARAMS ((tree, tree));
+ static struct search_level *push_search_level
+ PARAMS ((struct stack_level *, struct obstack *));
+@@ -1800,7 +1799,7 @@ covariant_return_p (brettype, drettype)
+ /* Check that virtual overrider OVERRIDER is acceptable for base function
+ BASEFN. Issue diagnostic, and return zero, if unacceptable. */
+
+-static int
++int
+ check_final_overrider (overrider, basefn)
+ tree overrider, basefn;
+ {
+--- gcc/cp/typeck.c.jj 2002-07-10 11:37:43.000000000 +0200
++++ gcc/cp/typeck.c 2002-08-23 13:51:08.000000000 +0200
+@@ -5450,7 +5450,10 @@ build_modify_expr (lhs, modifycode, rhs)
+ so the code to compute it is only emitted once. */
+ tree cond;
+
+- rhs = save_expr (rhs);
++ if (lvalue_p (rhs))
++ rhs = stabilize_reference (rhs);
++ else
++ rhs = save_expr (rhs);
+
+ /* Check this here to avoid odd errors when trying to convert
+ a throw to the type of the COND_EXPR. */
+--- gcc/expr.c.jj 2002-05-07 12:45:49.000000000 +0200
++++ gcc/expr.c 2002-08-23 13:51:09.000000000 +0200
+@@ -6661,8 +6661,7 @@ expand_expr (exp, target, tmode, modifie
+ * TYPE_QUAL_CONST))),
+ 0, TREE_ADDRESSABLE (exp), 1);
+
+- store_constructor (exp, target, 0,
+- int_size_in_bytes (TREE_TYPE (exp)));
++ store_constructor (exp, target, 0, int_expr_size (exp));
+ return target;
+ }
+
+--- gcc/explow.c.jj 2002-02-22 11:32:03.000000000 +0100
++++ gcc/explow.c 2002-08-23 13:51:08.000000000 +0200
+@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - S
+ #include "insn-config.h"
+ #include "ggc.h"
+ #include "recog.h"
++#include "langhooks.h"
+
+ static rtx break_out_memory_refs PARAMS ((rtx));
+ static void emit_stack_probe PARAMS ((rtx));
+@@ -285,20 +286,33 @@ rtx
+ expr_size (exp)
+ tree exp;
+ {
+- tree size;
+-
+- if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
+- && DECL_SIZE_UNIT (exp) != 0)
+- size = DECL_SIZE_UNIT (exp);
+- else
+- size = size_in_bytes (TREE_TYPE (exp));
++ tree size = (*lang_hooks.expr_size) (exp);
+
+ if (TREE_CODE (size) != INTEGER_CST
+ && contains_placeholder_p (size))
+ size = build (WITH_RECORD_EXPR, sizetype, size, exp);
+
+ return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
++}
++
++/* Return a wide integer for the size in bytes of the value of EXP, or -1
++ if the size can vary or is larger than an integer. */
++
++HOST_WIDE_INT
++int_expr_size (exp)
++ tree exp;
++{
++ tree t = (*lang_hooks.expr_size) (exp);
++
++ if (t == 0
++ || TREE_CODE (t) != INTEGER_CST
++ || TREE_OVERFLOW (t)
++ || TREE_INT_CST_HIGH (t) != 0
++ /* If the result would appear negative, it's too big to represent. */
++ || (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0)
++ return -1;
+
++ return TREE_INT_CST_LOW (t);
+ }
+ \f
+ /* Return a copy of X in which all memory references
+--- gcc/expr.h.jj 2002-04-02 23:17:24.000000000 +0200
++++ gcc/expr.h 2002-08-23 13:51:09.000000000 +0200
+@@ -548,6 +548,10 @@ extern unsigned int case_values_threshol
+ /* Return an rtx for the size in bytes of the value of an expr. */
+ extern rtx expr_size PARAMS ((tree));
+
++/* Return a wide integer for the size in bytes of the value of EXP, or -1
++ if the size can vary or is larger than an integer. */
++extern HOST_WIDE_INT int_expr_size PARAMS ((tree));
++
+ extern rtx lookup_static_chain PARAMS ((tree));
+
+ /* Convert a stack slot address ADDR valid in function FNDECL
+--- gcc/langhooks-def.h.jj 2002-05-24 23:55:54.000000000 +0200
++++ gcc/langhooks-def.h 2002-08-23 13:51:09.000000000 +0200
+@@ -48,6 +48,7 @@ extern int lhd_staticp PARAMS ((tree));
+ extern void lhd_clear_binding_stack PARAMS ((void));
+ extern void lhd_print_tree_nothing PARAMS ((FILE *, tree, int));
+ extern void lhd_set_yydebug PARAMS ((int));
++extern tree lhd_expr_size PARAMS ((tree));
+
+ /* Declarations of default tree inlining hooks. */
+ tree lhd_tree_inlining_walk_subtrees PARAMS ((tree *, int *,
+@@ -85,6 +86,7 @@ tree lhd_tree_inlining_convert_parm_for_
+ #define LANG_HOOKS_PRINT_TYPE lhd_print_tree_nothing
+ #define LANG_HOOKS_PRINT_IDENTIFIER lhd_print_tree_nothing
+ #define LANG_HOOKS_SET_YYDEBUG lhd_set_yydebug
++#define LANG_HOOKS_EXPR_SIZE lhd_expr_size
+
+ /* Tree inlining hooks. */
+ #define LANG_HOOKS_TREE_INLINING_WALK_SUBTREES lhd_tree_inlining_walk_subtrees
+@@ -156,6 +158,7 @@ int lhd_tree_dump_type_quals PARAMS ((
+ LANG_HOOKS_PRINT_TYPE, \
+ LANG_HOOKS_PRINT_IDENTIFIER, \
+ LANG_HOOKS_SET_YYDEBUG, \
++ LANG_HOOKS_EXPR_SIZE, \
+ LANG_HOOKS_TREE_INLINING_INITIALIZER, \
+ LANG_HOOKS_TREE_DUMP_INITIALIZER \
+ }
+--- gcc/langhooks.c.jj 2002-03-23 12:02:51.000000000 +0100
++++ gcc/langhooks.c 2002-08-23 13:51:09.000000000 +0200
+@@ -303,3 +303,16 @@ lhd_tree_dump_type_quals (t)
+ return TYPE_QUALS (t);
+ }
+
++/* lang_hooks.expr_size: Determine the size of the value of an expression T
++ in a language-specific way. Returns a tree for the size in bytes. */
++
++tree
++lhd_expr_size (exp)
++ tree exp;
++{
++ if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd'
++ && DECL_SIZE_UNIT (exp) != 0)
++ return DECL_SIZE_UNIT (exp);
++ else
++ return size_in_bytes (TREE_TYPE (exp));
++}
+--- gcc/langhooks.h.jj 2002-05-24 23:55:54.000000000 +0200
++++ gcc/langhooks.h 2002-08-23 13:51:09.000000000 +0200
+@@ -156,6 +156,12 @@ struct lang_hooks
+ warning that the front end does not use such a parser. */
+ void (*set_yydebug) PARAMS ((int));
+
++ /* Called from expr_size to calculate the size of the value of an
++ expression in a language-dependent way. Returns a tree for the size
++ in bytes. A frontend can call lhd_expr_size to get the default
++ semantics in cases that it doesn't want to handle specially. */
++ tree (*expr_size) PARAMS ((tree));
++
+ struct lang_hooks_for_tree_inlining tree_inlining;
+
+ struct lang_hooks_for_tree_dump tree_dump;
--- /dev/null
+2002-08-06 Jason Merrill <jason@redhat.com>
+
+ * c-common.c (c_expand_expr) [STMT_EXPR]: If the last expression is
+ a VAR_DECL with RTL that matches the target, just return that RTL.
+
+2002-06-01 Daniel Berlin <dberlin@dberlin.org>
+
+ * tree-inline.c (expand_call_inline): Make the statement
+ expression we generate have a COMPOUND_STMT.
+
+--- gcc/c-common.c.jj 2002-08-28 11:20:26.000000000 +0200
++++ gcc/c-common.c 2002-08-28 22:49:59.000000000 +0200
+@@ -3564,6 +3564,7 @@ c_expand_expr (exp, target, tmode, modif
+ tree rtl_expr;
+ rtx result;
+ bool preserve_result = false;
++ bool return_target = false;
+
+ /* Since expand_expr_stmt calls free_temp_slots after every
+ expression statement, we must call push_temp_slots here.
+@@ -3591,8 +3592,20 @@ c_expand_expr (exp, target, tmode, modif
+ if (TREE_CODE (last) == SCOPE_STMT
+ && TREE_CODE (expr) == EXPR_STMT)
+ {
+- TREE_ADDRESSABLE (expr) = 1;
+- preserve_result = true;
++ if (target && TREE_CODE (EXPR_STMT_EXPR (expr)) == VAR_DECL
++ && DECL_RTL_IF_SET (EXPR_STMT_EXPR (expr)) == target)
++ /* If the last expression is a variable whose RTL is the
++ same as our target, just return the target; if it
++ isn't valid expanding the decl would produce different
++ RTL, and store_expr would try to do a copy. */
++ return_target = true;
++ else
++ {
++ /* Otherwise, note that we want the value from the last
++ expression. */
++ TREE_ADDRESSABLE (expr) = 1;
++ preserve_result = true;
++ }
+ }
+ }
+
+@@ -3600,7 +3613,9 @@ c_expand_expr (exp, target, tmode, modif
+ expand_end_stmt_expr (rtl_expr);
+
+ result = expand_expr (rtl_expr, target, tmode, modifier);
+- if (preserve_result && GET_CODE (result) == MEM)
++ if (return_target)
++ result = target;
++ else if (preserve_result && GET_CODE (result) == MEM)
+ {
+ if (GET_MODE (result) != BLKmode)
+ result = copy_to_reg (result);
+--- gcc/tree-inline.c.jj 2002-08-28 11:20:27.000000000 +0200
++++ gcc/tree-inline.c 2002-08-28 22:49:59.000000000 +0200
+@@ -773,6 +773,7 @@ expand_call_inline (tp, walk_subtrees, d
+ inline_data *id;
+ tree t;
+ tree expr;
++ tree stmt;
+ tree chain;
+ tree fn;
+ tree scope_stmt;
+@@ -864,10 +865,10 @@ expand_call_inline (tp, walk_subtrees, d
+ for the return statements within the function to jump to. The
+ type of the statement expression is the return type of the
+ function call. */
+- expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), NULL_TREE);
++ expr = build1 (STMT_EXPR, TREE_TYPE (TREE_TYPE (fn)), make_node (COMPOUND_STMT));
+ /* There is no scope associated with the statement-expression. */
+ STMT_EXPR_NO_SCOPE (expr) = 1;
+-
++ stmt = STMT_EXPR_STMT (expr);
+ /* Local declarations will be replaced by their equivalents in this
+ map. */
+ st = id->decl_map;
+@@ -890,7 +891,7 @@ expand_call_inline (tp, walk_subtrees, d
+ parameters. */
+ expand_calls_inline (&arg_inits, id);
+ /* And add them to the tree. */
+- STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), arg_inits);
++ COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), arg_inits);
+
+ /* Record the function we are about to inline so that we can avoid
+ recursing into it. */
+@@ -925,8 +926,8 @@ expand_call_inline (tp, walk_subtrees, d
+ SCOPE_BEGIN_P (scope_stmt) = 1;
+ SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
+ remap_block (scope_stmt, DECL_ARGUMENTS (fn), id);
+- TREE_CHAIN (scope_stmt) = STMT_EXPR_STMT (expr);
+- STMT_EXPR_STMT (expr) = scope_stmt;
++ TREE_CHAIN (scope_stmt) = COMPOUND_BODY (stmt);
++ COMPOUND_BODY (stmt) = scope_stmt;
+
+ /* Tell the debugging backends that this block represents the
+ outermost scope of the inlined function. */
+@@ -934,34 +935,34 @@ expand_call_inline (tp, walk_subtrees, d
+ BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
+
+ /* Declare the return variable for the function. */
+- STMT_EXPR_STMT (expr)
+- = chainon (STMT_EXPR_STMT (expr),
++ COMPOUND_BODY (stmt)
++ = chainon (COMPOUND_BODY (stmt),
+ declare_return_variable (id, &use_stmt));
+
+ /* After we've initialized the parameters, we insert the body of the
+ function itself. */
+- inlined_body = &STMT_EXPR_STMT (expr);
++ inlined_body = &COMPOUND_BODY (stmt);
+ while (*inlined_body)
+ inlined_body = &TREE_CHAIN (*inlined_body);
+ *inlined_body = copy_body (id);
+
+- /* Close the block for the parameters. */
+- scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
+- SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
+- remap_block (scope_stmt, NULL_TREE, id);
+- STMT_EXPR_STMT (expr)
+- = chainon (STMT_EXPR_STMT (expr), scope_stmt);
+-
+ /* After the body of the function comes the RET_LABEL. This must come
+ before we evaluate the returned value below, because that evalulation
+ may cause RTL to be generated. */
+- STMT_EXPR_STMT (expr)
+- = chainon (STMT_EXPR_STMT (expr),
++ COMPOUND_BODY (stmt)
++ = chainon (COMPOUND_BODY (stmt),
+ build_stmt (LABEL_STMT, id->ret_label));
+
+ /* Finally, mention the returned value so that the value of the
+ statement-expression is the returned value of the function. */
+- STMT_EXPR_STMT (expr) = chainon (STMT_EXPR_STMT (expr), use_stmt);
++ COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), use_stmt);
++
++ /* Close the block for the parameters. */
++ scope_stmt = build_stmt (SCOPE_STMT, DECL_INITIAL (fn));
++ SCOPE_NO_CLEANUPS_P (scope_stmt) = 1;
++ remap_block (scope_stmt, NULL_TREE, id);
++ COMPOUND_BODY (stmt)
++ = chainon (COMPOUND_BODY (stmt), scope_stmt);
+
+ /* Clean up. */
+ splay_tree_delete (id->decl_map);
--- /dev/null
+2002-05-09 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/ext/asm2.C: New test.
+
+--- gcc/testsuite/g++.dg/ext/asm2.C.jj Wed May 15 13:51:22 2002
++++ gcc/testsuite/g++.dg/ext/asm2.C Sun May 12 11:25:45 2002
+@@ -0,0 +1,12 @@
++// Bug: in a template, we forgot that this was a simple asm, and decided
++// that %edi was a malformed operand specifier.
++
++template <class T> class I {
++public:
++ void f() { asm ("# mov %edi, %esi" ); }
++};
++
++int main () {
++ I<int> x;
++ x.f();
++}
--- /dev/null
+2002-05-28 Richard Henderson <rth@redhat.com>
+
+ * flow.c (calculate_global_regs_live): Rename call_used to
+ invalidated_by_call. Initialize from regs_invalidated_by_call
+ instead of call_used_regs.
+
+2002-07-20 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/opt/life1.C: New test.
+
+--- gcc/flow.c 28 May 2002 12:53:39 -0000 1.527
++++ gcc/flow.c 28 May 2002 20:01:29 -0000 1.528
+@@ -1048,19 +1048,19 @@ calculate_global_regs_live (blocks_in, b
+ int flags;
+ {
+ basic_block *queue, *qhead, *qtail, *qend;
+- regset tmp, new_live_at_end, call_used;
+- regset_head tmp_head, call_used_head;
++ regset tmp, new_live_at_end, invalidated_by_call;
++ regset_head tmp_head, invalidated_by_call_head;
+ regset_head new_live_at_end_head;
+ int i;
+
+ tmp = INITIALIZE_REG_SET (tmp_head);
+ new_live_at_end = INITIALIZE_REG_SET (new_live_at_end_head);
+- call_used = INITIALIZE_REG_SET (call_used_head);
++ invalidated_by_call = INITIALIZE_REG_SET (invalidated_by_call_head);
+
+ /* Inconveniently, this is only readily available in hard reg set form. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+- if (call_used_regs[i])
+- SET_REGNO_REG_SET (call_used, i);
++ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
++ SET_REGNO_REG_SET (invalidated_by_call, i);
+
+ /* Create a worklist. Allocate an extra slot for ENTRY_BLOCK, and one
+ because the `head == tail' style test for an empty queue doesn't
+@@ -1147,7 +1147,7 @@ calculate_global_regs_live (blocks_in, b
+ if (e->flags & EDGE_EH)
+ {
+ bitmap_operation (tmp, sb->global_live_at_start,
+- call_used, BITMAP_AND_COMPL);
++ invalidated_by_call, BITMAP_AND_COMPL);
+ IOR_REG_SET (new_live_at_end, tmp);
+ }
+ else
+@@ -1315,7 +1315,7 @@ calculate_global_regs_live (blocks_in, b
+
+ FREE_REG_SET (tmp);
+ FREE_REG_SET (new_live_at_end);
+- FREE_REG_SET (call_used);
++ FREE_REG_SET (invalidated_by_call);
+
+ if (blocks_out)
+ {
+--- gcc/testsuite/g++.dg/opt/life1.C.jj Sat Jul 20 18:57:05 2002
++++ gcc/testsuite/g++.dg/opt/life1.C Sat Jul 20 19:00:01 2002
+@@ -0,0 +1,16 @@
++// This testcase did not set up the pic register on IA-32 due
++// to bug in calculate_global_regs_live EH edge handling.
++// { dg-do compile { target i?86-*-linux* } }
++// { dg-options "-O2 -fPIC" }
++
++struct A { };
++
++void foo (A (*fn)())
++{
++ try {
++ A a = fn ();
++ } catch (...) {
++ }
++}
++
++// { dg-final { scan-assembler "GLOBAL_OFFSET_TABLE" } }
--- /dev/null
+2002-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/7241
+ * dwarf2out.c (base_type_die): Use DW_ATE_*_char even if main
+ variant is char_type_node and type name is char.
+
+--- gcc/dwarf2out.c.jj Wed Jun 19 15:09:56 2002
++++ gcc/dwarf2out.c Thu Jul 11 20:47:52 2002
+@@ -7335,9 +7335,11 @@ base_type_die (type)
+ /* Carefully distinguish the C character types, without messing
+ up if the language is not C. Note that we check only for the names
+ that contain spaces; other names might occur by coincidence in other
+- languages. */
++ languages, so we only check if main variant is char_type_node. */
+ if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
+ && (type == char_type_node
++ || (TYPE_MAIN_VARIANT (type) == char_type_node
++ && ! strcmp (type_name, "char"))
+ || ! strcmp (type_name, "signed char")
+ || ! strcmp (type_name, "unsigned char"))))
+ {
--- /dev/null
+2002-08-14 Nathan Sidwell <nathan@codesourcery.com>
+
+ * doc/invoke.texi (-a): Remove documentation.
+ (-fprofile-arcs): Remove reference to -a, -ax options.
+ * doc/gcov.texi (Gcov Data Files): Data might be merged.
+
+--- gcc/doc/gcov.texi.jj 2001-11-15 11:38:19.000000000 +0100
++++ gcc/doc/gcov.texi 2002-08-22 11:48:48.000000000 +0200
+@@ -388,7 +388,7 @@ built with the GCC @option{-fprofile-arc
+ separate @file{.da} file is created for each source file compiled with
+ this option, and the name of the @file{.da} file is stored as an
+ absolute pathname in the resulting object file. This path name is
+-derived from the source file name by substituting a @file{.da} suffix.
++derived from the object file name by substituting a @file{.da} suffix.
+
+ The format of the @file{.da} file is fairly simple. The first 8-byte
+ number is the number of counts in the file, followed by the counts
+--- gcc/doc/invoke.texi.jj 2002-08-08 17:55:08.000000000 +0200
++++ gcc/doc/invoke.texi 2002-08-22 11:46:49.000000000 +0200
+@@ -2831,20 +2831,6 @@ analysis program @code{gprof}. You must
+ the source files you want data about, and you must also use it when
+ linking.
+
+-@cindex @code{tcov}
+-@item -a
+-@opindex a
+-Generate extra code to write profile information for basic blocks, which will
+-record the number of times each basic block is executed, the basic block start
+-address, and the function name containing the basic block. If @option{-g} is
+-used, the line number and filename of the start of the basic block will also be
+-recorded. If not overridden by the machine description, the default action is
+-to append to the text file @file{bb.out}.
+-
+-This data could be analyzed by a program like @code{tcov}. Note,
+-however, that the format of the data is not what @code{tcov} expects.
+-Eventually GNU @code{gprof} should be extended to process this data.
+-
+ @item -Q
+ @opindex Q
+ Makes the compiler print out each function name as it is compiled, and
+@@ -2877,18 +2863,7 @@ optimization and code generation options
+ Control Optimization}).
+
+ The other use of @option{-fprofile-arcs} is for use with @code{gcov},
+-when it is used with the @option{-ftest-coverage} option. GCC
+-supports two methods of determining code coverage: the options that
+-support @code{gcov}, and options @option{-a} and @option{-ax}, which
+-write information to text files. The options that support @code{gcov}
+-do not need to instrument every arc in the program, so a program compiled
+-with them runs faster than a program compiled with @option{-a}, which
+-adds instrumentation code to every basic block in the program. The
+-tradeoff: since @code{gcov} does not have execution counts for all
+-branches, it must start with the execution counts for the instrumented
+-branches, and then iterate over the program flow graph until the entire
+-graph has been solved. Hence, @code{gcov} runs a little more slowly than
+-a program which uses information from @option{-a} and @option{-ax}.
++when it is used with the @option{-ftest-coverage} option.
+
+ With @option{-fprofile-arcs}, for each function of your program GCC
+ creates a program flow graph, then finds a spanning tree for the graph.
+@@ -2898,11 +2873,6 @@ executed. When an arc is the only exit
+ instrumentation code can be added to the block; otherwise, a new basic
+ block must be created to hold the instrumentation code.
+
+-This option makes it possible to estimate branch probabilities and to
+-calculate basic block execution counts. In general, basic block
+-execution counts as provided by @option{-a} do not give enough
+-information to estimate all branch probabilities.
+-
+ @need 2000
+ @item -ftest-coverage
+ @opindex ftest-coverage
--- /dev/null
+2002-01-25 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/other/redecl1.C: New test.
+
+--- gcc/testsuite/g++.dg/other/redecl1.C.jj Fri Jan 25 00:19:22 2002
++++ gcc/testsuite/g++.dg/other/redecl1.C Fri Jan 25 00:23:33 2002
+@@ -0,0 +1,10 @@
++// PR c++/5857
++// This testcase failed because during duplicate_decls the type was promoted
++// to int.
++
++// { dg-do compile }
++
++typedef char baz;
++extern const char foo[];
++const baz foo[] = "xyz";
++const char bar[] = "abc";
--- /dev/null
+2002-05-08 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/debug/const1.C: New test.
+
+--- gcc/testsuite/g++.dg/debug/const1.C.jj Thu Aug 30 22:30:55 2001
++++ gcc/testsuite/g++.dg/debug/const1.C Wed May 8 17:33:04 2002
+@@ -0,0 +1,11 @@
++// PR c++/6381
++// Bug: we were emitting the initializer for bar, which referenced foo,
++// which was not emitted.
++
++// { dg-options "-O" }
++// { dg-do link }
++
++static const int foo[] = { 0 };
++static const int * const bar[] = { foo };
++
++int main() {}
--- /dev/null
+2002-04-30 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/debug/typedef1.C: New test.
+
+--- gcc/testsuite/g++.dg/debug/typedef1.C.jj Thu Aug 30 22:30:55 2001
++++ gcc/testsuite/g++.dg/debug/typedef1.C Tue Apr 30 19:50:12 2002
+@@ -0,0 +1,17 @@
++// PR debug/6436
++// { dg-do compile }
++
++typedef struct
++{
++ unsigned int a0, a1;
++} A __attribute__ ((aligned(8)));
++
++typedef struct
++{
++ A a;
++} B;
++
++struct C
++{
++ B *bp;
++};
--- /dev/null
+2001-10-31 Jakub Jelinek <jakub@redhat.com>
+
+ * frame.c (fde_merge): Choose just one from FDEs for the
+ same function in erratic array.
+
+--- gcc/unwind-dw2-fde.c.jj Fri Jan 11 14:01:21 2002
++++ gcc/unwind-dw2-fde.c Tue Jan 15 15:58:27 2002
+@@ -535,7 +535,7 @@ fde_merge (struct object *ob, fde_compar
+ struct fde_vector *v1, struct fde_vector *v2)
+ {
+ size_t i1, i2;
+- fde * fde2;
++ fde * fde2 = NULL;
+
+ i2 = v2->count;
+ if (i2 > 0)
+@@ -544,6 +544,17 @@ fde_merge (struct object *ob, fde_compar
+ do
+ {
+ i2--;
++ if (fde2 != NULL && fde_compare (ob, v2->array[i2], fde2) == 0)
++ {
++ /* Some linkers (e.g. 2.10.91.0.2 or 2.11.92.0.8) resolve
++ section relative relocations against removed linkonce
++ section to corresponding location in the output linkonce
++ section. Always use the earliest fde in that case. */
++ fde2 = v2->array[i2];
++ v1->array[i1+i2+1] = fde2;
++ v1->array[i1+i2] = fde2;
++ continue;
++ }
+ fde2 = v2->array[i2];
+ while (i1 > 0 && fde_compare (ob, v1->array[i1-1], fde2) > 0)
+ {
--- /dev/null
+2002-08-05 Jakub Jelinek <jakub@redhat.com>
+
+ * fold-const.c (associate_trees): Only optimize NEGATE_EXPR in one
+ of the operands into MINUS_EXPR if code is PLUS_EXPR.
+
+ * gcc.c-torture/execute/20020805-1.c: New test.
+
+--- gcc/testsuite/gcc.c-torture/execute/20020805-1.c.jj 2002-08-05 18:27:42.000000000 +0200
++++ gcc/testsuite/gcc.c-torture/execute/20020805-1.c 2002-08-05 18:26:42.000000000 +0200
+@@ -0,0 +1,21 @@
++/* This testcase was miscompiled on IA-32, because fold-const
++ assumed associate_trees is always done on PLUS_EXPR. */
++
++extern void abort (void);
++extern void exit (int);
++
++void check (unsigned int m)
++{
++ if (m != (unsigned int) -1)
++ abort ();
++}
++
++unsigned int n = 1;
++
++int main (void)
++{
++ unsigned int m;
++ m = (1 | (2 - n)) | (-n);
++ check (m);
++ exit (0);
++}
+--- gcc/fold-const.c.jj 2002-08-05 18:16:25.000000000 +0200
++++ gcc/fold-const.c 2002-08-05 18:16:25.000000000 +0200
+@@ -1500,14 +1500,16 @@ associate_trees (t1, t2, code, type)
+ if (TREE_CODE (t1) == code || TREE_CODE (t2) == code
+ || TREE_CODE (t1) == MINUS_EXPR || TREE_CODE (t2) == MINUS_EXPR)
+ {
+- if (TREE_CODE (t1) == NEGATE_EXPR)
+- return build (MINUS_EXPR, type, convert (type, t2),
+- convert (type, TREE_OPERAND (t1, 0)));
+- else if (TREE_CODE (t2) == NEGATE_EXPR)
+- return build (MINUS_EXPR, type, convert (type, t1),
+- convert (type, TREE_OPERAND (t2, 0)));
+- else
+- return build (code, type, convert (type, t1), convert (type, t2));
++ if (code == PLUS_EXPR)
++ {
++ if (TREE_CODE (t1) == NEGATE_EXPR)
++ return build (MINUS_EXPR, type, convert (type, t2),
++ convert (type, TREE_OPERAND (t1, 0)));
++ else if (TREE_CODE (t2) == NEGATE_EXPR)
++ return build (MINUS_EXPR, type, convert (type, t1),
++ convert (type, TREE_OPERAND (t2, 0)));
++ }
++ return build (code, type, convert (type, t1), convert (type, t2));
+ }
+
+ return fold (build (code, type, convert (type, t1), convert (type, t2)));
--- /dev/null
+2002-05-15 Jakub Jelinek <jakub@redhat.com>
+
+ * fold-const.c (fold): Fix a typo.
+
+--- gcc/fold-const.c.jj Wed May 15 14:02:54 2002
++++ gcc/fold-const.c Wed May 15 14:06:09 2002
+@@ -6530,7 +6530,7 @@ fold (expr)
+
+ else if (TREE_INT_CST_HIGH (arg1) == -1
+ && (TREE_INT_CST_LOW (arg1)
+- == ((unsigned HOST_WIDE_INT) 1 << (width - 1)))
++ == ((unsigned HOST_WIDE_INT) -1 << (width - 1)))
+ && ! TREE_UNSIGNED (TREE_TYPE (arg1)))
+ switch (TREE_CODE (t))
+ {
--- /dev/null
+2002-06-20 Jakub Jelinek <jakub@redhat.com>
+
+ * emit-rtl.c (init_emit_once): Register static_regno_reg_rtx
+ with GC.
+ * alias.c (init_alias_once): Register static_reg_base_value
+ with GC.
+
+2002-06-13 Jeffrey Law <law@redhat.com>
+
+ * rs6000.c (rs6000_frame_related): Avoid unwanted sharing
+ of hard registers.
+
+ * emit-rtl.c (static_regno_reg_rtx): Define.
+ (init_emit_once): Initialize static_regno_reg_rtx.
+ (init_emit): Copy static_regno_reg_rtx into regno_reg_rtx instead
+ of building new hard reg objects once per function.
+ (gen_rtx_REG): Try to share hard regs.
+ * regclass.c (init_fake_stack_mems): New function broken out from
+ init_regs.
+ * rtl.h (init_fake_stack_mems): Declare.
+ * toplev.c (lang_independent_init): Call init_regs before
+ init_emit_once. Call init_fake_stack_mems after init_emit_once.
+
+ * alias.c (argument_registers): Remove.
+ (init_alias_once): Initialize static_reg_base_value here. Remove
+ initialization of argument_registers.
+ (init_alias_once_per_function): Remove.
+ (init_alias_analysis): Copy all the entries from static_reg_base_value
+ into new_reg_base_value all at once.
+ * rtl.h (init_alias_once_per_function): Remove declaration.
+ * function.c (prepare_function_start): Do not call
+ init_alias_once_per_function.
+
+ * caller-save.c (init_caller_save): Use gen_rtx_INSN instead of
+ starting a sequence and emitting an INSN.
+
+2002-06-11 Jeffrey Law <law@redhat.com>
+
+ * caller-save.c (init_caller_save): Move creation of SAVEINSN
+ and RESTINSN into into the scope of the sequence.
+
+ * loop.c (loop_regs_scan): Avoid useless generation of REG objects.
+
+2002-06-10 Jeffrey Law <law@redhat.com>
+
+ * alias.c (static_reg_base_value): New to hold RTL for
+ items allocated once per function for the aliasing code.
+ (init_alias_once_per_function): Initialize static_reg_base_value.
+ (init_alias_analysis): Avoid throw-away allocations of RTL by
+ using pre-computed values in static_reg_base_value.
+ * function.c (prepare_function_start): Call
+ init_alias_once_per_function appropriately.
+ * rtl.h (init_alias_once_per_function): Declare.
+ * caller-save (init_caller_save): Restructure slightly to
+ avoid lots of silly RTL generation.
+ * expr.c (init_expr_once): Likewise.
+ * reload1.c (reload_cse_regs_1): Allocate throw-away register
+ RTL object here. Pass it into children.
+ (reload_cse_simplify_operands): Use passed-in register RTL
+ object.
+ (reload_cse_simplify): Pass through throw-away register
+ RTL object.
+
+2002-06-07 Jeff Law <law@redhat.com>
+
+ * emit-rtl.c (init_emit): Add hard registers to regno_reg_rtx.
+ * combine.c (move_deaths): Use regno_reg_rtx for hard regs rather
+ than creating a new register.
+ (distribute_notes): Likewise.
+ * df.c (df_reg_use_gen): Likewise.
+ (df_reg_clobber_gen): Likewise.
+ (df_ref_record): Likewise.
+ * expr.c (use_regs): Likewise.
+ * flow.c (propagate_one_insn): Likewise.
+ (mark_set_1): Likewise.
+ (mark_used_reg): Likewise.
+ * reload.c (emit_reload_insns): Likewise.
+
+--- gcc/df.c.jj Tue Apr 2 21:23:50 2002
++++ gcc/df.c Thu Jun 20 14:12:05 2002
+@@ -633,8 +633,7 @@ static rtx df_reg_use_gen (regno)
+ rtx reg;
+ rtx use;
+
+- reg = regno >= FIRST_PSEUDO_REGISTER
+- ? regno_reg_rtx[regno] : gen_rtx_REG (reg_raw_mode[regno], regno);
++ reg = regno_reg_rtx[regno];
+
+ use = gen_rtx_USE (GET_MODE (reg), reg);
+ return use;
+@@ -648,8 +647,7 @@ static rtx df_reg_clobber_gen (regno)
+ rtx reg;
+ rtx use;
+
+- reg = regno >= FIRST_PSEUDO_REGISTER
+- ? regno_reg_rtx[regno] : gen_rtx_REG (reg_raw_mode[regno], regno);
++ reg = regno_reg_rtx[regno];
+
+ use = gen_rtx_CLOBBER (GET_MODE (reg), reg);
+ return use;
+@@ -905,7 +903,7 @@ df_ref_record (df, reg, loc, insn, ref_t
+ endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg));
+
+ for (i = regno; i < endregno; i++)
+- df_ref_record_1 (df, gen_rtx_REG (reg_raw_mode[i], i),
++ df_ref_record_1 (df, regno_reg_rtx[i],
+ loc, insn, ref_type, ref_flags);
+ }
+ else
+--- gcc/config/rs6000/rs6000.c.jj Sat May 25 00:01:52 2002
++++ gcc/config/rs6000/rs6000.c Thu Jun 20 18:23:59 2002
+@@ -8531,6 +8531,14 @@ rs6000_frame_related (insn, reg, val, re
+ {
+ rtx real, temp;
+
++ /* copy_rtx will not make unique copies of registers, so we need to
++ ensure we don't have unwanted sharing here. */
++ if (reg == reg2)
++ reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
++
++ if (reg == rreg)
++ reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
++
+ real = copy_rtx (PATTERN (insn));
+
+ real = replace_rtx (real, reg,
+--- gcc/combine.c.jj Tue Jun 4 15:02:15 2002
++++ gcc/combine.c Thu Jun 20 14:12:38 2002
+@@ -11908,7 +11908,7 @@ move_deaths (x, maybe_kill_insn, from_cu
+ if (i < regno || i >= ourend)
+ REG_NOTES (where_dead)
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+- gen_rtx_REG (reg_raw_mode[i], i),
++ regno_reg_rtx[i],
+ REG_NOTES (where_dead));
+ }
+
+@@ -11935,7 +11935,7 @@ move_deaths (x, maybe_kill_insn, from_cu
+ offset = 1;
+
+ for (i = regno + offset; i < ourend; i++)
+- move_deaths (gen_rtx_REG (reg_raw_mode[i], i),
++ move_deaths (regno_reg_rtx[i],
+ maybe_kill_insn, from_cuid, to_insn, &oldnotes);
+ }
+
+@@ -12557,7 +12557,7 @@ distribute_notes (notes, from_insn, i3,
+ for (i = regno; i < endregno;
+ i += HARD_REGNO_NREGS (i, reg_raw_mode[i]))
+ {
+- rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
++ rtx piece = regno_reg_rtx[i];
+ basic_block bb = BASIC_BLOCK (this_basic_block);
+
+ if (! dead_or_set_p (place, piece)
+--- gcc/emit-rtl.c.jj Thu May 23 10:28:12 2002
++++ gcc/emit-rtl.c Thu Jun 20 18:38:08 2002
+@@ -92,6 +92,12 @@ static int no_line_numbers;
+
+ rtx global_rtl[GR_MAX];
+
++/* Commonly used RTL for hard registers. These objects are not necessarily
++ unique, so we allocate them separately from global_rtl. They are
++ initialized once per compilation unit, then copied into regno_reg_rtx
++ at the beginning of each function. */
++static rtx static_regno_reg_rtx[FIRST_PSEUDO_REGISTER];
++
+ /* We record floating-point CONST_DOUBLEs in each floating-point mode for
+ the values of 0, 1, and 2. For the integer entries and VOIDmode, we
+ record a copy of const[012]_rtx. */
+@@ -427,6 +433,15 @@ gen_rtx_REG (mode, regno)
+ return stack_pointer_rtx;
+ }
+
++ /* If the per-function register table has been set up, try to re-use
++ an existing entry in that table to avoid useless generation of RTL. */
++ if (0 && cfun
++ && cfun->emit
++ && regno_reg_rtx
++ && regno >= 0 && regno < FIRST_PSEUDO_REGISTER
++ && reg_raw_mode[regno] == mode)
++ return regno_reg_rtx[regno];
++
+ return gen_raw_REG (mode, regno);
+ }
+
+@@ -4841,6 +4856,11 @@ init_emit ()
+ f->emit->regno_decl
+ = (tree *) xcalloc (f->emit->regno_pointer_align_length, sizeof (tree));
+
++ /* Put copies of all the hard registers into regno_reg_rtx. */
++ memcpy (regno_reg_rtx,
++ static_regno_reg_rtx,
++ FIRST_PSEUDO_REGISTER * sizeof (rtx));
++
+ /* Put copies of all the virtual register rtx into regno_reg_rtx. */
+ init_virtual_regs (f->emit);
+
+@@ -5015,8 +5035,14 @@ init_emit_once (line_numbers)
+ gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
+ virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+
++ /* Initialize RTL for commonly used hard registers. These are
++ copied into regno_reg_rtx as we begin to compile each function. */
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);
++
+ /* These rtx must be roots if GC is enabled. */
+ ggc_add_rtx_root (global_rtl, GR_MAX);
++ ggc_add_rtx_root (static_regno_reg_rtx, (int) FIRST_PSEUDO_REGISTER);
+
+ #ifdef INIT_EXPANDERS
+ /* This is to initialize {init|mark|free}_machine_status before the first
+--- gcc/expr.c.jj Tue May 7 12:45:49 2002
++++ gcc/expr.c Thu Jun 20 17:04:00 2002
+@@ -208,6 +208,7 @@ init_expr_once ()
+ enum machine_mode mode;
+ int num_clobbers;
+ rtx mem, mem1;
++ rtx reg;
+
+ start_sequence ();
+
+@@ -217,6 +218,10 @@ init_expr_once ()
+ mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
+ mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
+
++ /* A scratch register we can modify in-place below to avoid
++ useless RTL allocations. */
++ reg = gen_raw_REG (VOIDmode, -1);
++
+ insn = emit_insn (gen_rtx_SET (0, NULL_RTX, NULL_RTX));
+ pat = PATTERN (insn);
+
+@@ -224,11 +229,11 @@ init_expr_once ()
+ mode = (enum machine_mode) ((int) mode + 1))
+ {
+ int regno;
+- rtx reg;
+
+ direct_load[(int) mode] = direct_store[(int) mode] = 0;
+ PUT_MODE (mem, mode);
+ PUT_MODE (mem1, mode);
++ PUT_MODE (reg, mode);
+
+ /* See if there is some register that can be used in this mode and
+ directly loaded or stored from memory. */
+@@ -241,7 +246,7 @@ init_expr_once ()
+ if (! HARD_REGNO_MODE_OK (regno, mode))
+ continue;
+
+- reg = gen_rtx_REG (mode, regno);
++ REGNO (reg) = regno;
+
+ SET_SRC (pat) = mem;
+ SET_DEST (pat) = reg;
+@@ -2280,7 +2285,7 @@ use_regs (call_fusage, regno, nregs)
+ abort ();
+
+ for (i = 0; i < nregs; i++)
+- use_reg (call_fusage, gen_rtx_REG (reg_raw_mode[regno + i], regno + i));
++ use_reg (call_fusage, regno_reg_rtx[regno + i]);
+ }
+
+ /* Add USE expressions to *CALL_FUSAGE for each REG contained in the
+--- gcc/flow.c.jj Tue Apr 23 20:26:35 2002
++++ gcc/flow.c Thu Jun 20 14:12:05 2002
+@@ -1721,8 +1721,7 @@ propagate_one_insn (pbi, insn)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
+ {
+ /* We do not want REG_UNUSED notes for these registers. */
+- mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
+- cond, insn,
++ mark_set_1 (pbi, CLOBBER, regno_reg_rtx[i], cond, insn,
+ pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
+ }
+ }
+@@ -1770,8 +1769,7 @@ propagate_one_insn (pbi, insn)
+ so they are made live. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (global_regs[i])
+- mark_used_reg (pbi, gen_rtx_REG (reg_raw_mode[i], i),
+- cond, insn);
++ mark_used_reg (pbi, regno_reg_rtx[i], cond, insn);
+ }
+ }
+
+@@ -2769,7 +2767,7 @@ mark_set_1 (pbi, code, reg, cond, insn,
+ if (! REGNO_REG_SET_P (pbi->reg_live, i))
+ REG_NOTES (insn)
+ = alloc_EXPR_LIST (REG_UNUSED,
+- gen_rtx_REG (reg_raw_mode[i], i),
++ regno_reg_rtx[i],
+ REG_NOTES (insn));
+ }
+ }
+@@ -3577,7 +3575,7 @@ mark_used_reg (pbi, reg, cond, insn)
+ && ! dead_or_set_regno_p (insn, i))
+ REG_NOTES (insn)
+ = alloc_EXPR_LIST (REG_DEAD,
+- gen_rtx_REG (reg_raw_mode[i], i),
++ regno_reg_rtx[i],
+ REG_NOTES (insn));
+ }
+ }
+--- gcc/reload1.c.jj Wed May 22 14:17:55 2002
++++ gcc/reload1.c Thu Jun 20 17:05:46 2002
+@@ -444,7 +444,7 @@ static int constraint_accepts_reg_p PARA
+ static void reload_cse_regs_1 PARAMS ((rtx));
+ static int reload_cse_noop_set_p PARAMS ((rtx));
+ static int reload_cse_simplify_set PARAMS ((rtx, rtx));
+-static int reload_cse_simplify_operands PARAMS ((rtx));
++static int reload_cse_simplify_operands PARAMS ((rtx, rtx));
+ static void reload_combine PARAMS ((void));
+ static void reload_combine_note_use PARAMS ((rtx *, rtx));
+ static void reload_combine_note_store PARAMS ((rtx, rtx, void *));
+@@ -459,7 +459,7 @@ static HOST_WIDE_INT sext_for_mode PARAM
+ static void failed_reload PARAMS ((rtx, int));
+ static int set_reload_reg PARAMS ((int, int));
+ static void reload_cse_delete_noop_set PARAMS ((rtx, rtx));
+-static void reload_cse_simplify PARAMS ((rtx));
++static void reload_cse_simplify PARAMS ((rtx, rtx));
+ void fixup_abnormal_edges PARAMS ((void));
+ extern void dump_needs PARAMS ((struct insn_chain *));
+ \f
+@@ -7161,8 +7161,7 @@ emit_reload_insns (chain)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+- ? gen_rtx_REG (reg_raw_mode[REGNO (rld[r].reg_rtx) + k],
+- REGNO (rld[r].reg_rtx) + k)
++ ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
+ : 0);
+
+ /* Now do the inverse operation. */
+@@ -7211,8 +7210,7 @@ emit_reload_insns (chain)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+- ? gen_rtx_REG (reg_raw_mode[REGNO (rld[r].reg_rtx) + k],
+- REGNO (rld[r].reg_rtx) + k)
++ ? regno_reg_rtx[REGNO (rld[r].reg_rtx) + k]
+ : 0);
+
+ /* Unless we inherited this reload, show we haven't
+@@ -8061,8 +8059,9 @@ reload_cse_noop_set_p (set)
+
+ /* Try to simplify INSN. */
+ static void
+-reload_cse_simplify (insn)
++reload_cse_simplify (insn, testreg)
+ rtx insn;
++ rtx testreg;
+ {
+ rtx body = PATTERN (insn);
+
+@@ -8089,7 +8088,7 @@ reload_cse_simplify (insn)
+ if (count > 0)
+ apply_change_group ();
+ else
+- reload_cse_simplify_operands (insn);
++ reload_cse_simplify_operands (insn, testreg);
+ }
+ else if (GET_CODE (body) == PARALLEL)
+ {
+@@ -8132,7 +8131,7 @@ reload_cse_simplify (insn)
+ if (count > 0)
+ apply_change_group ();
+ else
+- reload_cse_simplify_operands (insn);
++ reload_cse_simplify_operands (insn, testreg);
+ }
+ }
+
+@@ -8158,6 +8157,7 @@ reload_cse_regs_1 (first)
+ rtx first;
+ {
+ rtx insn;
++ rtx testreg = gen_raw_REG (VOIDmode, -1);
+
+ cselib_init ();
+ init_alias_analysis ();
+@@ -8165,7 +8165,7 @@ reload_cse_regs_1 (first)
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ if (INSN_P (insn))
+- reload_cse_simplify (insn);
++ reload_cse_simplify (insn, testreg);
+
+ cselib_process_insn (insn);
+ }
+@@ -8336,8 +8336,9 @@ reload_cse_simplify_set (set, insn)
+ hard registers. */
+
+ static int
+-reload_cse_simplify_operands (insn)
++reload_cse_simplify_operands (insn, testreg)
+ rtx insn;
++ rtx testreg;
+ {
+ int i, j;
+
+@@ -8357,7 +8358,6 @@ reload_cse_simplify_operands (insn)
+ int *op_alt_regno[MAX_RECOG_OPERANDS];
+ /* Array of alternatives, sorted in order of decreasing desirability. */
+ int *alternative_order;
+- rtx reg = gen_rtx_REG (VOIDmode, -1);
+
+ extract_insn (insn);
+
+@@ -8441,8 +8441,8 @@ reload_cse_simplify_operands (insn)
+ if (! TEST_HARD_REG_BIT (equiv_regs[i], regno))
+ continue;
+
+- REGNO (reg) = regno;
+- PUT_MODE (reg, mode);
++ REGNO (testreg) = regno;
++ PUT_MODE (testreg, mode);
+
+ /* We found a register equal to this operand. Now look for all
+ alternatives that can accept this register and have not been
+@@ -8484,10 +8484,10 @@ reload_cse_simplify_operands (insn)
+ alternative yet and the operand being replaced is not
+ a cheap CONST_INT. */
+ if (op_alt_regno[i][j] == -1
+- && reg_fits_class_p (reg, class, 0, mode)
++ && reg_fits_class_p (testreg, class, 0, mode)
+ && (GET_CODE (recog_data.operand[i]) != CONST_INT
+ || (rtx_cost (recog_data.operand[i], SET)
+- > rtx_cost (reg, SET))))
++ > rtx_cost (testreg, SET))))
+ {
+ alternative_nregs[j]++;
+ op_alt_regno[i][j] = regno;
+--- gcc/alias.c.jj Thu Jun 20 12:43:03 2002
++++ gcc/alias.c Thu Jun 20 18:36:24 2002
+@@ -149,6 +149,10 @@ static rtx *reg_base_value;
+ static rtx *new_reg_base_value;
+ static unsigned int reg_base_value_size; /* size of reg_base_value array */
+
++/* Static hunks of RTL used by the aliasing code; these are initialized
++ once per function to avoid unnecessary RTL allocations. */
++static rtx static_reg_base_value[FIRST_PSEUDO_REGISTER];
++
+ #define REG_BASE_VALUE(X) \
+ (REGNO (X) < reg_base_value_size \
+ ? reg_base_value[REGNO (X)] : 0)
+@@ -2429,8 +2433,6 @@ mark_constant_function ()
+ }
+
+
+-static HARD_REG_SET argument_registers;
+-
+ void
+ init_alias_once ()
+ {
+@@ -2439,13 +2441,26 @@ init_alias_once ()
+ #ifndef OUTGOING_REGNO
+ #define OUTGOING_REGNO(N) N
+ #endif
++ ggc_add_rtx_root (static_reg_base_value, (int) FIRST_PSEUDO_REGISTER);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ /* Check whether this register can hold an incoming pointer
+ argument. FUNCTION_ARG_REGNO_P tests outgoing register
+ numbers, so translate if necessary due to register windows. */
+ if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
+ && HARD_REGNO_MODE_OK (i, Pmode))
+- SET_HARD_REG_BIT (argument_registers, i);
++ static_reg_base_value[i]
++ = gen_rtx_ADDRESS (VOIDmode, gen_rtx_REG (Pmode, i));
++
++ static_reg_base_value[STACK_POINTER_REGNUM]
++ = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
++ static_reg_base_value[ARG_POINTER_REGNUM]
++ = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
++ static_reg_base_value[FRAME_POINTER_REGNUM]
++ = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
++#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
++ static_reg_base_value[HARD_FRAME_POINTER_REGNUM]
++ = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
++#endif
+
+ alias_sets = splay_tree_new (splay_tree_compare_ints, 0, 0);
+ }
+@@ -2535,21 +2550,8 @@ init_alias_analysis ()
+ The address expression is VOIDmode for an argument and
+ Pmode for other registers. */
+
+- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+- if (TEST_HARD_REG_BIT (argument_registers, i))
+- new_reg_base_value[i] = gen_rtx_ADDRESS (VOIDmode,
+- gen_rtx_REG (Pmode, i));
+-
+- new_reg_base_value[STACK_POINTER_REGNUM]
+- = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
+- new_reg_base_value[ARG_POINTER_REGNUM]
+- = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
+- new_reg_base_value[FRAME_POINTER_REGNUM]
+- = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
+-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+- new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
+- = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
+-#endif
++ memcpy (new_reg_base_value, static_reg_base_value,
++ FIRST_PSEUDO_REGISTER * sizeof (rtx));
+
+ /* Walk the insns adding values to the new_reg_base_value array. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+--- gcc/caller-save.c.jj Wed Jan 2 12:47:35 2002
++++ gcc/caller-save.c Thu Jun 20 17:49:47 2002
+@@ -115,6 +115,9 @@ init_caller_save ()
+ rtx address;
+ int i, j;
+ enum machine_mode mode;
++ rtx savepat, restpat;
++ rtx test_reg, test_mem;
++ rtx saveinsn, restinsn;
+
+ /* First find all the registers that we need to deal with and all
+ the modes that they can have. If we can't find a mode to use,
+@@ -179,22 +182,30 @@ init_caller_save ()
+ address = addr_reg;
+
+ /* Next we try to form an insn to save and restore the register. We
+- see if such an insn is recognized and meets its constraints. */
++ see if such an insn is recognized and meets its constraints.
+
+- start_sequence ();
++ To avoid lots of unnecessary RTL allocation, we construct all the RTL
++ once, then modify the memory and register operands in-place. */
++
++ test_reg = gen_rtx_REG (VOIDmode, 0);
++ test_mem = gen_rtx_MEM (VOIDmode, address);
++ savepat = gen_rtx_SET (VOIDmode, test_mem, test_reg);
++ restpat = gen_rtx_SET (VOIDmode, test_reg, test_mem);
++ saveinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, savepat, -1, 0, 0);
++ restinsn = gen_rtx_INSN (VOIDmode, 0, 0, 0, restpat, -1, 0, 0);
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ for (mode = 0 ; mode < MAX_MACHINE_MODE; mode++)
+ if (HARD_REGNO_MODE_OK (i, mode))
+ {
+- rtx mem = gen_rtx_MEM (mode, address);
+- rtx reg = gen_rtx_REG (mode, i);
+- rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
+- rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
+- rtx saveinsn = emit_insn (savepat);
+- rtx restinsn = emit_insn (restpat);
+ int ok;
+
++ /* Update the register number and modes of the register
++ and memory operand. */
++ REGNO (test_reg) = i;
++ PUT_MODE (test_reg, mode);
++ PUT_MODE (test_mem, mode);
++
+ reg_save_code[i][mode] = recog_memoized (saveinsn);
+ reg_restore_code[i][mode] = recog_memoized (restinsn);
+
+@@ -232,8 +243,6 @@ init_caller_save ()
+ SET_HARD_REG_BIT (call_fixed_reg_set, i);
+ }
+ }
+-
+- end_sequence ();
+ }
+ \f
+ /* Initialize save areas by showing that we haven't allocated any yet. */
+--- gcc/rtl.h.jj Tue May 21 20:19:51 2002
++++ gcc/rtl.h Thu Jun 20 18:01:01 2002
+@@ -1964,6 +1964,7 @@ extern int reg_classes_intersect_p PARAM
+ extern int reg_class_subset_p PARAMS ((enum reg_class, enum reg_class));
+ extern void globalize_reg PARAMS ((int));
+ extern void init_regs PARAMS ((void));
++extern void init_fake_stack_mems PARAMS ((void));
+ extern void init_reg_sets PARAMS ((void));
+ extern void regset_release_memory PARAMS ((void));
+ extern void regclass_init PARAMS ((void));
+--- gcc/regclass.c.jj Wed Jun 19 15:11:11 2002
++++ gcc/regclass.c Thu Jun 20 18:01:01 2002
+@@ -605,11 +605,16 @@ init_regs ()
+ init_reg_sets_1 ();
+
+ init_reg_modes ();
++}
+
++/* Initialize some fake stack-frame MEM references for use in
++ memory_move_secondary_cost. */
++
++void
++init_fake_stack_mems ()
++{
+ #ifdef HAVE_SECONDARY_RELOADS
+ {
+- /* Make some fake stack-frame MEM references for use in
+- memory_move_secondary_cost. */
+ int i;
+
+ for (i = 0; i < MAX_MACHINE_MODE; i++)
+--- gcc/toplev.c.jj Thu May 30 11:08:44 2002
++++ gcc/toplev.c Thu Jun 20 18:01:01 2002
+@@ -5058,6 +5058,9 @@ lang_independent_init ()
+ init_stringpool ();
+ init_obstacks ();
+
++ /* init_emit_once uses reg_raw_mode and therefore must be called
++ after init_regs which initialized reg_raw_mode. */
++ init_regs ();
+ init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
+ || debug_info_level == DINFO_LEVEL_VERBOSE
+ #ifdef VMS_DEBUGGING_INFO
+@@ -5066,7 +5069,7 @@ lang_independent_init ()
+ #endif
+ || flag_test_coverage
+ || warn_notreached);
+- init_regs ();
++ init_fake_stack_mems ();
+ init_alias_once ();
+ init_stmt ();
+ init_loop ();
+--- gcc/loop.c.jj Wed Jun 19 15:10:51 2002
++++ gcc/loop.c Thu Jun 20 18:22:01 2002
+@@ -9541,7 +9541,7 @@ loop_regs_scan (loop, extra_size)
+ if (LOOP_INFO (loop)->has_call)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i)
+- && rtx_varies_p (gen_rtx_REG (Pmode, i), /*for_alias=*/1))
++ && rtx_varies_p (regno_reg_rtx[i], 1))
+ {
+ regs->array[i].may_not_optimize = 1;
+ regs->array[i].set_in_loop = 1;
--- /dev/null
+2002-06-11 Richard Henderson <rth@redhat.com>
+
+ * caller-save.c (init_caller_save): Clear INSN_CODE each iteration.
+
+--- gcc/caller-save.c.jj Fri Jun 21 01:16:13 2002
++++ gcc/caller-save.c Thu Jul 11 10:27:57 2002
+@@ -206,6 +206,10 @@ init_caller_save ()
+ PUT_MODE (test_reg, mode);
+ PUT_MODE (test_mem, mode);
+
++ /* Force re-recognition of the modified insns. */
++ INSN_CODE (saveinsn) = -1;
++ INSN_CODE (restinsn) = -1;
++
+ reg_save_code[i][mode] = recog_memoized (saveinsn);
+ reg_restore_code[i][mode] = recog_memoized (restinsn);
+
--- /dev/null
+2002-05-29 Richard Henderson <rth@redhat.com>
+
+ * config/i386/biarch64.h (TARGET_64BIT_DEFAULT): Define with value.
+ (TARGET_BI_ARCH): Likewise.
+ * config/i386/i386.h: Test TARGET_64BIT_DEFAULT by value.
+ (TARGET_SWITCHES): Combine target defaults here not in TARGET_DEFAULT.
+ (TARGET_64BIT_DEFAULT): Default to 0.
+ (TARGET_DEFAULT): Default to MASK_OMIT_LEAF_FRAME_POINTER.
+
+--- gcc/config/i386/biarch64.h.jj Tue Oct 2 12:59:38 2001
++++ gcc/config/i386/biarch64.h Tue Jun 4 15:11:52 2002
+@@ -21,5 +21,5 @@ along with GNU CC; see the file COPYING.
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+-#define TARGET_64BIT_DEFAULT
+-#define TARGET_BI_ARCH
++#define TARGET_64BIT_DEFAULT MASK_64BIT
++#define TARGET_BI_ARCH 1
+--- gcc/config/i386/i386.h.jj Thu Apr 18 19:02:03 2002
++++ gcc/config/i386/i386.h Tue Jun 4 15:13:40 2002
+@@ -192,7 +192,7 @@ extern int target_flags;
+ #ifdef TARGET_BI_ARCH
+ #define TARGET_64BIT (target_flags & MASK_64BIT)
+ #else
+-#ifdef TARGET_64BIT_DEFAULT
++#if TARGET_64BIT_DEFAULT
+ #define TARGET_64BIT 1
+ #else
+ #define TARGET_64BIT 0
+@@ -381,14 +381,14 @@ extern int x86_prefetch_sse;
+ { "no-red-zone", MASK_NO_RED_ZONE, \
+ N_("Do not use red-zone in the x86-64 code") }, \
+ SUBTARGET_SWITCHES \
+- { "", TARGET_DEFAULT, 0 }}
++ { "", TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT, 0 }}
+
+-#ifdef TARGET_64BIT_DEFAULT
+-#define TARGET_DEFAULT (MASK_64BIT | TARGET_SUBTARGET_DEFAULT)
+-#else
+-#define TARGET_DEFAULT TARGET_SUBTARGET_DEFAULT
++#ifndef TARGET_64BIT_DEFAULT
++#define TARGET_64BIT_DEFAULT 0
+ #endif
+
++#define TARGET_DEFAULT MASK_OMIT_LEAF_FRAME_POINTER
++
+ /* Which processor to schedule for. The cpu attribute defines a list that
+ mirrors this list, so changes to i386.md must be made at the same time. */
+
+@@ -624,13 +624,13 @@ extern int ix86_arch;
+
+ #ifndef CPP_CPU_SPEC
+ #ifdef TARGET_BI_ARCH
+-#ifdef TARGET_64BIT_DEFAULT
++#if TARGET_64BIT_DEFAULT
+ #define CPP_CPU_SPEC "%{m32:%(cpp_cpu32)}%{!m32:%(cpp_cpu64)} %(cpp_cpucommon)"
+ #else
+ #define CPP_CPU_SPEC "%{m64:%(cpp_cpu64)}%{!m64:%(cpp_cpu32)} %(cpp_cpucommon)"
+ #endif
+ #else
+-#ifdef TARGET_64BIT_DEFAULT
++#if TARGET_64BIT_DEFAULT
+ #define CPP_CPU_SPEC "%(cpp_cpu64) %(cpp_cpucommon)"
+ #else
+ #define CPP_CPU_SPEC "%(cpp_cpu32) %(cpp_cpucommon)"
+@@ -695,7 +695,7 @@ extern int ix86_arch;
+ #define DOUBLE_TYPE_SIZE 64
+ #define LONG_LONG_TYPE_SIZE 64
+
+-#if defined (TARGET_BI_ARCH) || defined (TARGET_64BIT_DEFAULT)
++#if defined (TARGET_BI_ARCH) || TARGET_64BIT_DEFAULT
+ #define MAX_BITS_PER_WORD 64
+ #define MAX_LONG_TYPE_SIZE 64
+ #else
--- /dev/null
+2002-05-20 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/20020525-1.c: New test.
+
+--- gcc/testsuite/gcc.dg/20020525-1.c.jj Thu Aug 30 22:30:55 2001
++++ gcc/testsuite/gcc.dg/20020525-1.c Sat May 25 10:45:13 2002
+@@ -0,0 +1,24 @@
++/* PR optimization/6703
++ Origin: Glen Nakamura <glen@imodulo.com> */
++/* { dg-do run } */
++/* { dg-options "-O2" } */
++
++extern void abort (void);
++extern void exit (int);
++
++void foo (int *x, int y)
++{
++ __builtin_memset (x, 0, y);
++}
++
++int main ()
++{
++ int x[2] = { 0x5a5a5a5a, 0x5a5a5a5a };
++
++ if (x[1] != 0x5a5a5a5a)
++ abort ();
++ foo (x, sizeof (int) + 1);
++ if (x[1] == 0x5a5a5a5a)
++ abort ();
++ exit (0);
++}
--- /dev/null
+Argh, GDB is not ready.
+
+--- gcc/config/i386/i386.h.jj 2002-08-28 11:20:27.000000000 +0200
++++ gcc/config/i386/i386.h 2002-08-28 22:01:26.000000000 +0200
+@@ -390,7 +390,7 @@ extern int x86_prefetch_sse;
+ #define TARGET_64BIT_DEFAULT 0
+ #endif
+
+-#define TARGET_DEFAULT MASK_OMIT_LEAF_FRAME_POINTER
++#define TARGET_DEFAULT 0
+
+ /* Which processor to schedule for. The cpu attribute defines a list that
+ mirrors this list, so changes to i386.md must be made at the same time. */
--- /dev/null
+2002-06-04 Richard Henderson <rth@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * config/i386/i386.c (USE_HIDDEN_LINKONCE): New.
+ (ix86_asm_file_end): If USE_HIDDEN_LINKONCE, emit get_pc thunks
+ into linkonce sections.
+ (load_pic_register): Set up pic_label_name for it.
+
+--- gcc/config/i386/i386.c.jj Mon Jun 3 17:24:13 2002
++++ gcc/config/i386/i386.c Tue Jun 4 15:49:17 2002
+@@ -3786,6 +3786,12 @@ ix86_setup_frame_addresses ()
+ cfun->machine->accesses_prev_frame = 1;
+ }
+ \f
++#if defined(HAVE_GAS_HIDDEN) && defined(SUPPORTS_ONE_ONLY)
++# define USE_HIDDEN_LINKONCE 1
++#else
++# define USE_HIDDEN_LINKONCE 0
++#endif
++
+ static char pic_label_name[32];
+
+ /* This function generates code for -fpic that loads %ebx with
+@@ -3800,10 +3806,6 @@ ix86_asm_file_end (file)
+ if (! TARGET_DEEP_BRANCH_PREDICTION || pic_label_name[0] == 0)
+ return;
+
+- /* ??? Binutils 2.10 and earlier has a linkonce elimination bug related
+- to updating relocations to a section being discarded such that this
+- doesn't work. Ought to detect this at configure time. */
+-#if 0
+ /* The trick here is to create a linkonce section containing the
+ pic label thunk, but to refer to it with an internal label.
+ Because the label is internal, we don't have inter-dso name
+@@ -3811,28 +3813,27 @@ ix86_asm_file_end (file)
+
+ In order to use these macros, however, we must create a fake
+ function decl. */
+- if (targetm.have_named_sections)
++ if (USE_HIDDEN_LINKONCE && targetm.have_named_sections)
+ {
+ tree decl = build_decl (FUNCTION_DECL,
+- get_identifier ("i686.get_pc_thunk"),
++ get_identifier (pic_label_name),
+ error_mark_node);
++ TREE_PUBLIC (decl) = 1;
++ TREE_STATIC (decl) = 1;
+ DECL_ONE_ONLY (decl) = 1;
+ UNIQUE_SECTION (decl, 0);
+- named_section (decl, NULL);
++ named_section (decl, NULL, 0);
++ ASM_GLOBALIZE_LABEL (file, pic_label_name);
++ fputs ("\t.hidden\t", file);
++ assemble_name (file, pic_label_name);
++ fputc ('\n', file);
++ ASM_DECLARE_FUNCTION_NAME (file, pic_label_name, decl);
+ }
+ else
+-#else
+- text_section ();
+-#endif
+-
+- /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
+- internal (non-global) label that's being emitted, it didn't make
+- sense to have .type information for local labels. This caused
+- the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
+- me debug info for a label that you're declaring non-global?) this
+- was changed to call ASM_OUTPUT_LABEL() instead. */
+-
+- ASM_OUTPUT_LABEL (file, pic_label_name);
++ {
++ text_section ();
++ ASM_OUTPUT_LABEL (file, pic_label_name);
++ }
+
+ xops[0] = pic_offset_table_rtx;
+ xops[1] = gen_rtx_MEM (SImode, stack_pointer_rtx);
+@@ -3853,7 +3854,12 @@ load_pic_register ()
+ if (TARGET_DEEP_BRANCH_PREDICTION)
+ {
+ if (! pic_label_name[0])
+- ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
++ {
++ if (USE_HIDDEN_LINKONCE && targetm.have_named_sections)
++ strcpy (pic_label_name, "__i686.get_pc_thunk.bx");
++ else
++ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
++ }
+ pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name));
+ }
+ else
--- /dev/null
+2002-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/7242
+ * config/i386/i386.h (CPP_CPUCOMMON_SPEC): Fix typo.
+
+--- gcc/config/i386/i386.h.jj Wed Jul 10 16:56:41 2002
++++ gcc/config/i386/i386.h Thu Jul 11 09:59:06 2002
+@@ -601,7 +601,7 @@ extern int ix86_arch;
+ %{m386|mcpu=i386:-D__tune_i386__ }\
+ %{m486|mcpu=i486:-D__tune_i486__ }\
+ %{mpentium|mcpu=pentium|mcpu=i586|mcpu=pentium-mmx:-D__tune_i586__ -D__tune_pentium__ }\
+-%{mpentiumpro|mcpu=pentiumpro|mcpu=i686|cpu=pentium2|cpu=pentium3:-D__tune_i686__ \
++%{mpentiumpro|mcpu=pentiumpro|mcpu=i686|mcpu=pentium2|mcpu=pentium3:-D__tune_i686__ \
+ -D__tune_pentiumpro__ }\
+ %{mcpu=k6|mcpu=k6-2|mcpu=k6-3:-D__tune_k6__ }\
+ %{mcpu=athlon|mcpu=athlon-tbird|mcpu=athlon-4|mcpu=athlon-xp|mcpu=athlon-mp:\
--- /dev/null
+2002-05-30 Richard Henderson <rth@redhat.com>
+
+ * defaults.h (TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER): Kill.
+ * toplev.c (process_options): Don't check it.
+ * doc/tm.texi: Don't document it.
+ * config/i386/linux.h (SUBTARGET_FRAME_POINTER_REQUIRED): New.
+ (TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER): Kill.
+ * config/i386/i386.c (ix86_frame_pointer_required): Suppress leaf
+ frame pointer optimization if current_function_profile.
+
+--- gcc/doc/tm.texi.jj Fri May 3 19:25:59 2002
++++ gcc/doc/tm.texi Tue Jun 4 23:18:43 2002
+@@ -4077,22 +4077,6 @@ must not use the @var{labelno} argument
+ @item PROFILE_BEFORE_PROLOGUE
+ Define this macro if the code for function profiling should come before
+ the function prologue. Normally, the profiling code comes after.
+-
+-
+-@findex TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER
+-@item TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER
+-On some targets, it is impossible to use profiling when the frame
+-pointer has been omitted. For example, on x86 GNU/Linux systems,
+-the @code{mcount} routine provided by the GNU C Library finds the
+-address of the routine that called the routine that called @code{mcount}
+-by looking in the immediate caller's stack frame. If the immediate
+-caller has no frame pointer, this lookup will fail.
+-
+-By default, GCC assumes that the target does allow profiling when the
+-frame pointer is omitted. This macro should be defined to a C
+-expression that evaluates to @code{false} if the target does not allow
+-profiling when the frame pointer is omitted.
+-
+ @end table
+
+ @node Tail Calls
+--- gcc/config/i386/i386.c.jj Tue Jun 4 21:13:34 2002
++++ gcc/config/i386/i386.c Tue Jun 4 23:18:43 2002
+@@ -3827,7 +3827,8 @@ ix86_frame_pointer_required ()
+ /* In override_options, TARGET_OMIT_LEAF_FRAME_POINTER turns off
+ the frame pointer by default. Turn it back on now if we've not
+ got a leaf function. */
+- if (TARGET_OMIT_LEAF_FRAME_POINTER && ! leaf_function_p ())
++ if (TARGET_OMIT_LEAF_FRAME_POINTER
++ && (!current_function_is_leaf || current_function_profile))
+ return 1;
+
+ return 0;
+--- gcc/config/i386/linux.h.jj Tue Apr 16 08:15:02 2002
++++ gcc/config/i386/linux.h Tue Jun 4 23:18:43 2002
+@@ -63,14 +63,11 @@ Boston, MA 02111-1307, USA. */
+ fprintf (FILE, "\tcall\tmcount\n"); \
+ }
+
+-/* True if it is possible to profile code that does not have a frame
+- pointer.
+-
+- The GLIBC version of mcount for the x86 assumes that there is a
++/* The GLIBC version of mcount for the x86 assumes that there is a
+ frame, so we cannot allow profiling without a frame pointer. */
+
+-#undef TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER
+-#define TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER false
++#undef SUBTARGET_FRAME_POINTER_REQUIRED
++#define SUBTARGET_FRAME_POINTER_REQUIRED current_function_profile
+
+ #undef SIZE_TYPE
+ #define SIZE_TYPE "unsigned int"
+--- gcc/defaults.h.jj Fri May 3 19:24:51 2002
++++ gcc/defaults.h Tue Jun 4 23:18:43 2002
+@@ -398,13 +398,6 @@ do { \
+ ? ptrmemfunc_vbit_in_pfn : ptrmemfunc_vbit_in_delta)
+ #endif
+
+-/* True if it is possible to profile code that does not have a frame
+- pointer. */
+-
+-#ifndef TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER
+-#define TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER true
+-#endif
+-
+ #ifndef DEFAULT_GDB_EXTENSIONS
+ #define DEFAULT_GDB_EXTENSIONS 1
+ #endif
+--- gcc/toplev.c.jj Thu May 30 11:08:44 2002
++++ gcc/toplev.c Tue Jun 4 23:19:11 2002
+@@ -4908,16 +4908,6 @@ process_options ()
+ warning ("this target machine does not have delayed branches");
+ #endif
+
+- /* Some operating systems do not allow profiling without a frame
+- pointer. */
+- if (!TARGET_ALLOWS_PROFILING_WITHOUT_FRAME_POINTER
+- && profile_flag
+- && flag_omit_frame_pointer)
+- {
+- error ("profiling does not work without a frame pointer");
+- flag_omit_frame_pointer = 0;
+- }
+-
+ user_label_prefix = USER_LABEL_PREFIX;
+ if (flag_leading_underscore != -1)
+ {
--- /dev/null
+2002-08-07 Jakub Jelinek <jakub@redhat.com>
+
+ * tree-inline.c (remap_decl): Make sure DECL_TOO_LATE is clear for
+ remapped labels.
+
+ * gcc.c-torture/compile/20020807-1.c: New test.
+
+--- gcc/tree-inline.c.jj 2002-04-17 15:35:57.000000000 +0200
++++ gcc/tree-inline.c 2002-08-07 14:53:14.000000000 +0200
+@@ -145,6 +145,9 @@ remap_decl (decl, id)
+ t = copy_decl_for_inlining (decl, fn,
+ VARRAY_TREE (id->fns, 0));
+
++ if (TREE_CODE (t) == LABEL_DECL)
++ DECL_TOO_LATE (t) = 0;
++
+ /* The decl T could be a dynamic array or other variable size type,
+ in which case some fields need to be remapped because they may
+ contain SAVE_EXPRs. */
+--- gcc/testsuite/gcc.c-torture/compile/20020807-1.c.jj 2002-08-07 14:55:26.000000000 +0200
++++ gcc/testsuite/gcc.c-torture/compile/20020807-1.c 2002-08-07 14:22:07.000000000 +0200
+@@ -0,0 +1,33 @@
++int x;
++
++static int
++__attribute__ ((noinline))
++foo (void)
++{
++ return 0;
++}
++
++static void
++__attribute__ ((noinline))
++bar (void)
++{
++}
++
++static inline void
++baz (void)
++{
++ char arr[x];
++
++lab:
++ if (foo () == -1)
++ {
++ bar ();
++ goto lab;
++ }
++}
++
++void
++test (void)
++{
++ baz ();
++}
--- /dev/null
+--- libjava/Makefile.am.jj Tue Jun 4 20:41:44 2002
++++ libjava/Makefile.am Wed Jun 5 15:20:30 2002
+@@ -111,6 +111,8 @@ INCLUDES = -I$(top_srcdir) -Iinclude -I$
+
+ ## ################################################################
+
++rpath_def = $(shell if test "$(toolexeclibdir)" != /usr/lib; then echo -rpath $(toolexeclibdir); fi)
++
+ ##
+ ## How to build libgcj.a and libgcj.jar
+ ##
+@@ -410,7 +412,7 @@ EXTRA_jv_convert_SOURCES = $(convert_sou
+ ## need this because we are explicitly using libtool to link using the
+ ## `.la' file.
+ jv_convert_LDFLAGS = --main=gnu.gcj.convert.Convert \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+ jv_convert_LINK = $(GCJLINK)
+ ## We don't explicitly link in the libraries we need; libgcj.la brings
+ ## in all dependencies. We need the -L so that gcj can find libgcj
+@@ -429,7 +431,7 @@ gij_SOURCES = gij.cc
+ ## We need -nodefaultlibs because we want to avoid gcj's `-lgcj'. We
+ ## need this because we are explicitly using libtool to link using the
+ ## `.la' file.
+-gij_LDFLAGS = -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++gij_LDFLAGS = $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+ gij_LINK = $(GCJLINK)
+ ## See jv_convert_LDADD.
+ gij_LDADD = -L$(here)/.libs libgcj.la
+@@ -441,7 +443,7 @@ rmic_SOURCES =
+ ## This is a dummy definition.
+ EXTRA_rmic_SOURCES = $(rmi_java_source_files)
+ rmic_LDFLAGS = --main=gnu.java.rmi.rmic.RMIC \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+ rmic_LINK = $(GCJLINK)
+ ## See jv_convert_LDADD.
+ rmic_LDADD = -L$(here)/.libs libgcj.la
+@@ -453,7 +455,7 @@ rmiregistry_SOURCES =
+ ## This is a dummy definition.
+ EXTRA_rmiregistry_SOURCES = $(rmi_java_source_files)
+ rmiregistry_LDFLAGS = --main=gnu.java.rmi.registry.RegistryImpl \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+ rmiregistry_LINK = $(GCJLINK)
+ ## See jv_convert_LDADD.
+ rmiregistry_LDADD = -L$(here)/.libs libgcj.la
+--- libjava/Makefile.in.jj Tue Jun 4 23:25:56 2002
++++ libjava/Makefile.in Wed Jun 5 15:21:59 2002
+@@ -184,6 +184,7 @@ INCLUDES = -I$(top_srcdir) -Iinclude -I$
+ $(GCINCS) $(THREADINCS) $(INCLTDL) \
+ $(GCC_UNWIND_INCLUDE) $(ZINCS) $(LIBFFIINCS)
+
++rpath_def = $(shell if test "$(toolexeclibdir)" != /usr/lib; then echo -rpath $(toolexeclibdir); fi)
+
+ nat_files = $(nat_source_files:.cc=.lo)
+ x_nat_files = $(x_nat_source_files:.cc=.lo)
+@@ -263,7 +264,7 @@ CONVERT_DIR = gnu/gcj/convert
+ jv_convert_SOURCES =
+ EXTRA_jv_convert_SOURCES = $(convert_source_files)
+ jv_convert_LDFLAGS = --main=gnu.gcj.convert.Convert \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+
+ jv_convert_LINK = $(GCJLINK)
+ jv_convert_LDADD = -L$(here)/.libs libgcj.la
+@@ -272,7 +273,7 @@ jv_convert_DEPENDENCIES = $(convert_sour
+
+
+ gij_SOURCES = gij.cc
+-gij_LDFLAGS = -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++gij_LDFLAGS = $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+ gij_LINK = $(GCJLINK)
+ gij_LDADD = -L$(here)/.libs libgcj.la
+ gij_DEPENDENCIES = libgcj.la libgcj.spec
+@@ -280,7 +281,7 @@ gij_DEPENDENCIES = libgcj.la libgcj.spec
+ rmic_SOURCES =
+ EXTRA_rmic_SOURCES = $(rmi_java_source_files)
+ rmic_LDFLAGS = --main=gnu.java.rmi.rmic.RMIC \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+
+ rmic_LINK = $(GCJLINK)
+ rmic_LDADD = -L$(here)/.libs libgcj.la
+@@ -289,7 +290,7 @@ rmic_DEPENDENCIES = libgcj.la libgcj.spe
+ rmiregistry_SOURCES =
+ EXTRA_rmiregistry_SOURCES = $(rmi_java_source_files)
+ rmiregistry_LDFLAGS = --main=gnu.java.rmi.registry.RegistryImpl \
+- -rpath $(toolexeclibdir) -shared-libgcc $(THREADLDFLAGS)
++ $(rpath_def) -shared-libgcc $(THREADLDFLAGS)
+
+ rmiregistry_LINK = $(GCJLINK)
+ rmiregistry_LDADD = -L$(here)/.libs libgcj.la
--- /dev/null
+--- libstdc++-v3/config/locale/gnu/ctype_members.cc.jj 2002-08-30 12:09:12.000000000 +0200
++++ libstdc++-v3/config/locale/gnu/ctype_members.cc 2002-09-02 15:25:15.000000000 +0200
+@@ -166,15 +166,30 @@ namespace std
+ wchar_t
+ ctype<wchar_t>::
+ do_widen(char __c) const
+- { return btowc(__c); }
+-
++ {
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(_M_c_locale_ctype);
++#endif
++ wchar_t __ret = btowc(__c);
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#endif
++ return __ret;
++ }
++
+ const char*
+ ctype<wchar_t>::
+ do_widen(const char* __lo, const char* __hi, wchar_t* __dest) const
+ {
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(_M_c_locale_ctype);
++#endif
+ mbstate_t __state;
+ memset(static_cast<void*>(&__state), 0, sizeof(mbstate_t));
+ mbsrtowcs(__dest, &__lo, __hi - __lo, &__state);
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#endif
+ return __hi;
+ }
+
+@@ -182,7 +197,13 @@ namespace std
+ ctype<wchar_t>::
+ do_narrow(wchar_t __wc, char __dfault) const
+ {
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(_M_c_locale_ctype);
++#endif
+ int __c = wctob(__wc);
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#endif
+ return (__c == EOF ? __dfault : static_cast<char>(__c));
+ }
+
+@@ -191,6 +212,9 @@ namespace std
+ do_narrow(const wchar_t* __lo, const wchar_t* __hi, char __dfault,
+ char* __dest) const
+ {
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(_M_c_locale_ctype);
++#endif
+ size_t __offset = 0;
+ while (true)
+ {
+@@ -208,6 +232,9 @@ namespace std
+ else
+ break;
+ }
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#endif
+ return __hi;
+ }
+ #endif // _GLIBCPP_USE_WCHAR_T
--- /dev/null
+--- libstdc++-v3/config/locale/gnu/monetary_members.cc.jj 2002-08-30 12:09:12.000000000 +0200
++++ libstdc++-v3/config/locale/gnu/monetary_members.cc 2002-08-31 23:41:51.000000000 +0200
+@@ -335,9 +335,13 @@ namespace std
+ else
+ {
+ // Named locale.
+- // XXX Fix me. Switch to named locale so that mbsrtowcs will work.
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(__cloc);
++#else
++ // Switch to named locale so that mbsrtowcs will work.
+ char* __old = strdup(setlocale(LC_ALL, NULL));
+ setlocale(LC_ALL, __name);
++#endif
+
+ _M_decimal_point = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc)}).__w);
+
+@@ -400,9 +404,12 @@ namespace std
+ char __nspace = *(__nl_langinfo_l(__INT_N_SEP_BY_SPACE, __cloc));
+ _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
+
+- // XXX
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#else
+ setlocale(LC_ALL, __old);
+ free(__old);
++#endif
+ }
+ }
+
+@@ -427,9 +434,13 @@ namespace std
+ else
+ {
+ // Named locale.
+- // XXX Fix me. Switch to named locale so that mbsrtowcs will work.
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __c_locale __old = __uselocale(__cloc);
++#else
++ // Switch to named locale so that mbsrtowcs will work.
+ char* __old = strdup(setlocale(LC_ALL, NULL));
+ setlocale(LC_ALL, __name);
++#endif
+
+ _M_decimal_point = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc)}).__w);
+ _M_thousands_sep = static_cast<wchar_t>(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_THOUSANDS_SEP_WC, __cloc)}).__w);
+@@ -491,9 +502,12 @@ namespace std
+ char __nspace = *(__nl_langinfo_l(__N_SEP_BY_SPACE, __cloc));
+ _M_neg_format = _S_construct_pattern(__nprecedes, __nspace, __nposn);
+
+- // XXX
++#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2)
++ __uselocale(__old);
++#else
+ setlocale(LC_ALL, __old);
+ free(__old);
++#endif
+ }
+ }
--- /dev/null
+Wed Jul 10 19:12:41 CEST 2002 Janis Johnson <janis187@us.ibm.com>
+
+ * loop.c (emit_prefetch_instructions): Small fix.
+
+--- gcc/loop.c.jj Fri Jun 14 21:12:04 2002
++++ gcc/loop.c Wed Aug 14 12:13:43 2002
+@@ -4090,11 +4090,17 @@ emit_prefetch_instructions (loop)
+ {
+ rtx reg = gen_reg_rtx (Pmode);
+ rtx loop_start = loop->start;
++ rtx init_val = info[i].class->initial_value;
+ rtx add_val = simplify_gen_binary (PLUS, Pmode,
+ info[i].giv->add_val,
+ GEN_INT (y * PREFETCH_BLOCK));
+
+- loop_iv_add_mult_emit_before (loop, info[i].class->initial_value,
++ /* Functions called by LOOP_IV_ADD_EMIT_BEFORE expect a
++ non-constant INIT_VAL to have the same mode as REG, which
++ in this case we know to be Pmode. */
++ if (GET_MODE (init_val) != Pmode && !CONSTANT_P (init_val))
++ init_val = convert_to_mode (Pmode, init_val, 0);
++ loop_iv_add_mult_emit_before (loop, init_val,
+ info[i].giv->mult_val,
+ add_val, reg, 0, loop_start);
+ emit_insn_before (gen_prefetch (reg, GEN_INT (info[i].write),
--- /dev/null
+2002-05-31 Jakub Jelinek <jakub@redhat.com>
+
+ PR optimization/6842
+ * combine.c (combine_simplify_rtx) [SUBREG]: Don't ICE if VOIDmode
+ operand subreg cannot be simplified.
+
+ * gcc.dg/20020531-1.c: New test.
+
+--- gcc/testsuite/gcc.dg/20020531-1.c.jj Fri May 31 17:15:15 2002
++++ gcc/testsuite/gcc.dg/20020531-1.c Fri May 31 17:13:50 2002
+@@ -0,0 +1,21 @@
++/* PR optimization/6842
++ This testcase caused ICE when trying to optimize V8QI subreg of VOIDmode
++ CONST_DOUBLE. */
++/* { dg-do compile { target i?86-*-* } } */
++/* { dg-options "-O2 -mmmx" } */
++
++typedef int __v8qi __attribute__ ((__mode__ (__V8QI__)));
++extern void abort (void);
++extern void exit (int);
++
++void foo (void)
++{
++ unsigned long long a = 0x0102030405060708LL;
++ unsigned long long b = 0x1020304050607080LL;
++ unsigned long long c;
++
++ c = (unsigned long long) __builtin_ia32_paddusb ((__v8qi) a, (__v8qi) b);
++ __builtin_ia32_emms ();
++ if (c != 0x1122334455667788)
++ abort ();
++}
+--- gcc/combine.c.jj Thu May 23 10:22:59 2002
++++ gcc/combine.c Fri May 31 17:05:09 2002
+@@ -3863,7 +3863,12 @@ combine_simplify_rtx (x, op0_mode, last,
+
+ /* simplify_subreg can't use gen_lowpart_for_combine. */
+ if (CONSTANT_P (SUBREG_REG (x))
+- && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x))
++ && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x)
++ /* Don't call gen_lowpart_for_combine if the inner mode
++ is VOIDmode and we cannot simplify it, as SUBREG without
++ inner mode is invalid. */
++ && (GET_MODE (SUBREG_REG (x)) != VOIDmode
++ || gen_lowpart_common (mode, SUBREG_REG (x))))
+ return gen_lowpart_for_combine (mode, SUBREG_REG (x));
+
+ if (GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_CC)
--- /dev/null
+2002-07-29 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/20020729-1.c: New test.
+
+2002-05-17 Richard Sandiford <rsandifo@redhat.com>
+
+ * expr.c (force_operand): Fix reversed move.
+
+Sat May 4 13:20:54 CEST 2002 Jan Hubicka <jh@suse.cz>
+
+ * expr.c (force_operand): Use expand_simple_* to handle more
+ cases.
+
+--- gcc/expr.c.jj 2002-05-07 12:45:49.000000000 +0200
++++ gcc/expr.c 2002-08-03 01:08:28.000000000 +0200
+@@ -5434,16 +5434,13 @@ rtx
+ force_operand (value, target)
+ rtx value, target;
+ {
+- optab binoptab = 0;
+- /* Use a temporary to force order of execution of calls to
+- `force_operand'. */
+- rtx tmp;
+- rtx op2;
++ rtx op1, op2;
+ /* Use subtarget as the target for operand 0 of a binary operation. */
+ rtx subtarget = get_subtarget (target);
++ enum rtx_code code = GET_CODE (value);
+
+ /* Check for a PIC address load. */
+- if ((GET_CODE (value) == PLUS || GET_CODE (value) == MINUS)
++ if ((code == PLUS || code == MINUS)
+ && XEXP (value, 0) == pic_offset_table_rtx
+ && (GET_CODE (XEXP (value, 1)) == SYMBOL_REF
+ || GET_CODE (XEXP (value, 1)) == LABEL_REF
+@@ -5455,60 +5452,88 @@ force_operand (value, target)
+ return subtarget;
+ }
+
+- if (GET_CODE (value) == PLUS)
+- binoptab = add_optab;
+- else if (GET_CODE (value) == MINUS)
+- binoptab = sub_optab;
+- else if (GET_CODE (value) == MULT)
++ if (code == ZERO_EXTEND || code == SIGN_EXTEND)
+ {
+- op2 = XEXP (value, 1);
+- if (!CONSTANT_P (op2)
+- && !(GET_CODE (op2) == REG && op2 != subtarget))
+- subtarget = 0;
+- tmp = force_operand (XEXP (value, 0), subtarget);
+- return expand_mult (GET_MODE (value), tmp,
+- force_operand (op2, NULL_RTX),
+- target, 1);
++ if (!target)
++ target = gen_reg_rtx (GET_MODE (value));
++ convert_move (target, force_operand (XEXP (value, 0), NULL),
++ code == ZERO_EXTEND);
++ return target;
+ }
+
+- if (binoptab)
++ if (GET_RTX_CLASS (code) == '2' || GET_RTX_CLASS (code) == 'c')
+ {
+ op2 = XEXP (value, 1);
+- if (!CONSTANT_P (op2)
+- && !(GET_CODE (op2) == REG && op2 != subtarget))
++ if (!CONSTANT_P (op2) && !(GET_CODE (op2) == REG && op2 != subtarget))
+ subtarget = 0;
+- if (binoptab == sub_optab && GET_CODE (op2) == CONST_INT)
++ if (code == MINUS && GET_CODE (op2) == CONST_INT)
+ {
+- binoptab = add_optab;
++ code = PLUS;
+ op2 = negate_rtx (GET_MODE (value), op2);
+ }
+
+ /* Check for an addition with OP2 a constant integer and our first
+- operand a PLUS of a virtual register and something else. In that
+- case, we want to emit the sum of the virtual register and the
+- constant first and then add the other value. This allows virtual
+- register instantiation to simply modify the constant rather than
+- creating another one around this addition. */
+- if (binoptab == add_optab && GET_CODE (op2) == CONST_INT
++ operand a PLUS of a virtual register and something else. In that
++ case, we want to emit the sum of the virtual register and the
++ constant first and then add the other value. This allows virtual
++ register instantiation to simply modify the constant rather than
++ creating another one around this addition. */
++ if (code == PLUS && GET_CODE (op2) == CONST_INT
+ && GET_CODE (XEXP (value, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (value, 0), 0)) == REG
+ && REGNO (XEXP (XEXP (value, 0), 0)) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (XEXP (XEXP (value, 0), 0)) <= LAST_VIRTUAL_REGISTER)
+ {
+- rtx temp = expand_binop (GET_MODE (value), binoptab,
+- XEXP (XEXP (value, 0), 0), op2,
+- subtarget, 0, OPTAB_LIB_WIDEN);
+- return expand_binop (GET_MODE (value), binoptab, temp,
+- force_operand (XEXP (XEXP (value, 0), 1), 0),
+- target, 0, OPTAB_LIB_WIDEN);
++ rtx temp = expand_simple_binop (GET_MODE (value), code,
++ XEXP (XEXP (value, 0), 0), op2,
++ subtarget, 0, OPTAB_LIB_WIDEN);
++ return expand_simple_binop (GET_MODE (value), code, temp,
++ force_operand (XEXP (XEXP (value,
++ 0), 1), 0),
++ target, 0, OPTAB_LIB_WIDEN);
++ }
++
++ op1 = force_operand (XEXP (value, 0), subtarget);
++ op2 = force_operand (op2, NULL_RTX);
++ switch (code)
++ {
++ case MULT:
++ return expand_mult (GET_MODE (value), op1, op2, target, 1);
++ case DIV:
++ if (!INTEGRAL_MODE_P (GET_MODE (value)))
++ return expand_simple_binop (GET_MODE (value), code, op1, op2,
++ target, 1, OPTAB_LIB_WIDEN);
++ else
++ return expand_divmod (0,
++ FLOAT_MODE_P (GET_MODE (value))
++ ? RDIV_EXPR : TRUNC_DIV_EXPR,
++ GET_MODE (value), op1, op2, target, 0);
++ break;
++ case MOD:
++ return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
++ target, 0);
++ break;
++ case UDIV:
++ return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
++ target, 1);
++ break;
++ case UMOD:
++ return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
++ target, 1);
++ break;
++ case ASHIFTRT:
++ return expand_simple_binop (GET_MODE (value), code, op1, op2,
++ target, 0, OPTAB_LIB_WIDEN);
++ break;
++ default:
++ return expand_simple_binop (GET_MODE (value), code, op1, op2,
++ target, 1, OPTAB_LIB_WIDEN);
+ }
+-
+- tmp = force_operand (XEXP (value, 0), subtarget);
+- return expand_binop (GET_MODE (value), binoptab, tmp,
+- force_operand (op2, NULL_RTX),
+- target, 0, OPTAB_LIB_WIDEN);
+- /* We give UNSIGNEDP = 0 to expand_binop
+- because the only operations we are expanding here are signed ones. */
++ }
++ if (GET_RTX_CLASS (code) == '1')
++ {
++ op1 = force_operand (XEXP (value, 0), NULL_RTX);
++ return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+ }
+
+ #ifdef INSN_SCHEDULING
+--- gcc/testsuite/gcc.dg/20020729-1.c.jj 2002-08-03 01:08:28.000000000 +0200
++++ gcc/testsuite/gcc.dg/20020729-1.c 2002-08-03 01:08:28.000000000 +0200
+@@ -0,0 +1,51 @@
++/* { dg-do compile { target i?86-*-* } } */
++/* { dg-options "-O2 -march=k6" } */
++
++static inline void *
++baz (void *s, unsigned long c, unsigned int count)
++{
++ int d0, d1;
++ __asm__ __volatile__ (""
++ : "=&c" (d0), "=&D" (d1)
++ :"a" (c), "q" (count), "0" (count / 4), "1" ((long) s)
++ :"memory");
++ return s;
++}
++
++struct A
++{
++ unsigned long *a;
++};
++
++inline static void *
++bar (struct A *x, int y)
++{
++ char *ptr;
++
++ ptr = (void *) x->a[y >> 12];
++ ptr += y % (1UL << 12);
++ return (void *) ptr;
++}
++
++int
++foo (struct A *x, unsigned int *y, int z, int u)
++{
++ int a, b, c, d, e;
++
++ z += *y;
++ c = z + u;
++ a = (z >> 12) + 1;
++ do
++ {
++ b = (a << 12);
++ d = b - z;
++ e = c - z;
++ if (e < d)
++ d = e;
++ baz (bar (x, z), 0, d);
++ z = b;
++ a++;
++ }
++ while (z < c);
++ return 0;
++}
--- /dev/null
+2002-05-05 Jakub Jelinek <jakub@redhat.com>
+
+ * config/sparc/sparc.md (ashlsi3): If shift count is const1_rtx,
+ use add instead of shift.
+ (ashldi3_sp64): Likewise.
+ (ashlsi3_const1, ashldi3_const1): Remove.
+ * config/sparc/sparc.h (PREDICATE_CODES): Add const1_operand.
+ * config/sparc/sparc.c (const1_operand): New.
+
+--- gcc/config/sparc/sparc.md.jj Sun May 5 21:56:45 2002
++++ gcc/config/sparc/sparc.md Sun May 5 23:33:31 2002
+@@ -7559,18 +7559,13 @@
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
++ if (operands[2] == const1_rtx)
++ return \"add\\t%1, %1, %0\";
+ return \"sll\\t%1, %2, %0\";
+ }"
+- [(set_attr "type" "shift")])
+-
+-;; We special case multiplication by two, as add can be done
+-;; in both ALUs, while shift only in IEU0 on UltraSPARC.
+-(define_insn "*ashlsi3_const1"
+- [(set (match_operand:SI 0 "register_operand" "=r")
+- (ashift:SI (match_operand:SI 1 "register_operand" "r")
+- (const_int 1)))]
+- ""
+- "add\\t%1, %1, %0")
++ [(set (attr "type")
++ (if_then_else (match_operand 2 "const1_operand" "")
++ (const_string "ialu") (const_string "shift")))])
+
+ (define_expand "ashldi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+@@ -7588,15 +7583,6 @@
+ }
+ }")
+
+-;; We special case multiplication by two, as add can be done
+-;; in both ALUs, while shift only in IEU0 on UltraSPARC.
+-(define_insn "*ashldi3_const1"
+- [(set (match_operand:DI 0 "register_operand" "=r")
+- (ashift:DI (match_operand:DI 1 "register_operand" "r")
+- (const_int 1)))]
+- "TARGET_ARCH64"
+- "add\\t%1, %1, %0")
+-
+ (define_insn "*ashldi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+@@ -7608,9 +7594,13 @@
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 63)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
+
++ if (operands[2] == const1_rtx)
++ return \"add\\t%1, %1, %0\";
+ return \"sllx\\t%1, %2, %0\";
+ }"
+- [(set_attr "type" "shift")])
++ [(set (attr "type")
++ (if_then_else (match_operand 2 "const1_operand" "")
++ (const_string "ialu") (const_string "shift")))])
+
+ ;; XXX UGH!
+ (define_insn "ashldi3_v8plus"
+--- gcc/config/sparc/sparc.h.jj Fri May 3 22:57:33 2002
++++ gcc/config/sparc/sparc.h Sun May 5 23:20:48 2002
+@@ -3014,6 +3014,7 @@ do { \
+
+ #define PREDICATE_CODES \
+ {"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
++{"const1_operand", {CONST_INT}}, \
+ {"fp_zero_operand", {CONST_DOUBLE}}, \
+ {"fp_register_operand", {SUBREG, REG}}, \
+ {"intreg_operand", {SUBREG, REG}}, \
+--- gcc/config/sparc/sparc.c.jj Fri May 3 22:57:33 2002
++++ gcc/config/sparc/sparc.c Sun May 5 23:24:18 2002
+@@ -478,6 +478,16 @@ reg_or_0_operand (op, mode)
+ return 0;
+ }
+
++/* Return non-zero only if OP is const1_rtx. */
++
++int
++const1_operand (op, mode)
++ rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ return op == const1_rtx;
++}
++
+ /* Nonzero if OP is a floating point value with value 0.0. */
+
+ int
--- /dev/null
+2002-06-04 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.c-torture/compile/20020604-1.c: New test.
+
+--- gcc/testsuite/gcc.c-torture/compile/20020604-1.c.jj Thu Apr 11 16:25:15 2002
++++ gcc/testsuite/gcc.c-torture/compile/20020604-1.c Mon Jun 3 17:43:12 2002
+@@ -0,0 +1,86 @@
++/* This testcase ICEd at -O2 on IA-32, because
++ (insn 141 139 142 (set (subreg:SF (reg:QI 72) 0)
++ (plus:SF (reg:SF 73)
++ (reg:SF 76))) 525 {*fop_sf_comm_nosse} (insn_list 134 (nil))
++ (expr_list:REG_DEAD (reg:SF 73) (nil)))
++ couldn't be reloaded. */
++
++void
++foo (unsigned int n, int x, int y, unsigned char *z)
++{
++ int a, b;
++ float c[2048][4];
++
++ switch (x)
++ {
++ case 0x1906:
++ a = b = -1;
++ break;
++ case 0x190A:
++ a = b = -1;
++ break;
++ case 0x8049:
++ a = b = -1;
++ break;
++ case 0x1907:
++ a = 1;
++ b = 2;
++ break;
++ default:
++ return;
++ }
++
++ if (a >= 0)
++ {
++ unsigned char *d = z;
++ unsigned int i;
++ for (i = 0; i < n; i++)
++ {
++ do
++ {
++ union
++ {
++ float r;
++ unsigned int i;
++ }
++ e;
++ e.r = c[i][1];
++ d[a] =
++ ((e.i >= 0x3f7f0000) ? ((int) e.i <
++ 0) ? (unsigned char) 0
++ : (unsigned char) 255 : (e.r =
++ e.r * (255.0F / 256.0F) +
++ 32768.0F, (unsigned char) e.i));
++ }
++ while (0);
++ d += y;
++ }
++ }
++
++ if (b >= 0)
++ {
++ unsigned char *d = z;
++ unsigned int i;
++ for (i = 0; i < n; i++)
++ {
++ do
++ {
++ union
++ {
++ float r;
++ unsigned int i;
++ }
++ e;
++ e.r = c[i][2];
++ d[b] =
++ ((e.i >= 0x3f7f0000) ? ((int) e.i <
++ 0) ? (unsigned char) 0
++ : (unsigned char) 255 : (e.r =
++ e.r * (255.0F / 256.0F) +
++ 32768.0F, (unsigned char) e.i));
++ }
++ while (0);
++ d += y;
++ }
++ }
++}
--- /dev/null
+2002-05-08 Tom Rix <trix@redhat.com>
+
+ * gcc.c-torture/execute/20020508-1.c: New test.
+ * gcc.c-torture/execute/20020508-2.c: New test.
+ * gcc.c-torture/execute/20020508-3.c: New test.
+
+--- gcc/testsuite/gcc.c-torture/execute/20020508-1.c.jj Wed May 15 14:22:47 2002
++++ gcc/testsuite/gcc.c-torture/execute/20020508-1.c Wed May 15 14:22:47 2002
+@@ -0,0 +1,104 @@
++/* This tests the rotate patterns that some machines support. */
++
++#include <limits.h>
++
++#ifndef CHAR_BIT
++#define CHAR_BIT 8
++#endif
++
++#define ROR(a,b) (((a) >> (b)) | ((a) << ((sizeof (a) * CHAR_BIT) - (b))))
++#define ROL(a,b) (((a) << (b)) | ((a) >> ((sizeof (a) * CHAR_BIT) - (b))))
++
++#define CHAR_VALUE ((unsigned char)0xf234U)
++#define SHORT_VALUE ((unsigned short)0xf234U)
++#define INT_VALUE 0xf234U
++#define LONG_VALUE 0xf2345678LU
++#define LL_VALUE 0xf2345678abcdef0LLU
++
++#define SHIFT1 4
++#define SHIFT2 ((sizeof (long long) * CHAR_BIT) - SHIFT1)
++
++unsigned char uc = CHAR_VALUE;
++unsigned short us = SHORT_VALUE;
++unsigned int ui = INT_VALUE;
++unsigned long ul = LONG_VALUE;
++unsigned long long ull = LL_VALUE;
++int shift1 = SHIFT1;
++int shift2 = SHIFT2;
++
++main ()
++{
++ if (ROR (uc, shift1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (uc, SHIFT1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (us, shift1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (us, SHIFT1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ui, shift1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ui, SHIFT1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ul, shift1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ul, SHIFT1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ull, shift1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ull, SHIFT1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ull, shift2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROR (ull, SHIFT2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (uc, shift1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (uc, SHIFT1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (us, shift1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (us, SHIFT1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ui, shift1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ui, SHIFT1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ul, shift1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ul, SHIFT1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ull, shift1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ull, SHIFT1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ull, shift2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (ull, SHIFT2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ exit (0);
++}
+--- gcc/testsuite/gcc.c-torture/execute/20020508-2.c.jj Wed May 15 14:22:47 2002
++++ gcc/testsuite/gcc.c-torture/execute/20020508-2.c Wed May 15 14:22:47 2002
+@@ -0,0 +1,102 @@
++#include <limits.h>
++
++#ifndef CHAR_BIT
++#define CHAR_BIT 8
++#endif
++
++#define ROR(a,b) (((a) >> (b)) | ((a) << ((sizeof (a) * CHAR_BIT) - (b))))
++#define ROL(a,b) (((a) << (b)) | ((a) >> ((sizeof (a) * CHAR_BIT) - (b))))
++
++#define CHAR_VALUE ((char)0x1234)
++#define SHORT_VALUE ((short)0x1234)
++#define INT_VALUE ((int)0x1234)
++#define LONG_VALUE ((long)0x12345678L)
++#define LL_VALUE ((long long)0x12345678abcdef0LL)
++
++#define SHIFT1 4
++#define SHIFT2 ((sizeof (long long) * CHAR_BIT) - SHIFT1)
++
++char c = CHAR_VALUE;
++short s = SHORT_VALUE;
++int i = INT_VALUE;
++long l = LONG_VALUE;
++long long ll = LL_VALUE;
++int shift1 = SHIFT1;
++int shift2 = SHIFT2;
++
++main ()
++{
++ if (ROR (c, shift1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (c, SHIFT1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (s, shift1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (s, SHIFT1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (i, shift1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (i, SHIFT1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (l, shift1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (l, SHIFT1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, shift1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, SHIFT1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, shift2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROR (ll, SHIFT2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (c, shift1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (c, SHIFT1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (s, shift1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (s, SHIFT1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (i, shift1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (i, SHIFT1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (l, shift1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (l, SHIFT1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, shift1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, SHIFT1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, shift2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (ll, SHIFT2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ exit (0);
++}
+--- gcc/testsuite/gcc.c-torture/execute/20020508-3.c.jj Wed May 15 14:22:47 2002
++++ gcc/testsuite/gcc.c-torture/execute/20020508-3.c Wed May 15 14:22:47 2002
+@@ -0,0 +1,102 @@
++#include <limits.h>
++
++#ifndef CHAR_BIT
++#define CHAR_BIT 8
++#endif
++
++#define ROR(a,b) (((a) >> (b)) | ((a) << ((sizeof (a) * CHAR_BIT) - (b))))
++#define ROL(a,b) (((a) << (b)) | ((a) >> ((sizeof (a) * CHAR_BIT) - (b))))
++
++#define CHAR_VALUE ((char)0xf234)
++#define SHORT_VALUE ((short)0xf234)
++#define INT_VALUE ((int)0xf234)
++#define LONG_VALUE ((long)0xf2345678L)
++#define LL_VALUE ((long long)0xf2345678abcdef0LL)
++
++#define SHIFT1 4
++#define SHIFT2 ((sizeof (long long) * CHAR_BIT) - SHIFT1)
++
++char c = CHAR_VALUE;
++short s = SHORT_VALUE;
++int i = INT_VALUE;
++long l = LONG_VALUE;
++long long ll = LL_VALUE;
++int shift1 = SHIFT1;
++int shift2 = SHIFT2;
++
++main ()
++{
++ if (ROR (c, shift1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (c, SHIFT1) != ROR (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (s, shift1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (s, SHIFT1) != ROR (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (i, shift1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (i, SHIFT1) != ROR (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (l, shift1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (l, SHIFT1) != ROR (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, shift1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, SHIFT1) != ROR (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROR (ll, shift2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROR (ll, SHIFT2) != ROR (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (c, shift1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (c, SHIFT1) != ROL (CHAR_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (s, shift1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (s, SHIFT1) != ROL (SHORT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (i, shift1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (i, SHIFT1) != ROL (INT_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (l, shift1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (l, SHIFT1) != ROL (LONG_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, shift1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, SHIFT1) != ROL (LL_VALUE, SHIFT1))
++ abort ();
++
++ if (ROL (ll, shift2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ if (ROL (ll, SHIFT2) != ROL (LL_VALUE, SHIFT2))
++ abort ();
++
++ exit (0);
++}
--- /dev/null
+2002-08-21 Richard Henderson <rth@redhat.com>
+
+ * config/i386/i386-protos.h (i386_output_dwarf_dtprel): Add
+ prototype.
+ * config/i386/i386.c (i386_output_dwarf_dtprel): New.
+ * config/i386/i386.h (ASM_OUTPUT_DWARF_DTPREL): Define.
+ * dwarf2.h (DW_OP_GNU_push_tls_address): Add.
+ (DW_OP_lo_user): Define to 0xe0.
+ * dwarf2out.c (INTERNAL_DW_OP_tls_addr): Define.
+ (dwarf_stack_op_name, sizeof_loc_descr): Handle a few more OPs.
+ (output_loc_operands): Handle INTERNAL_DW_OP_tls_addr.
+ (loc_descriptor_from_tree): Handle DECL_THREAD_LOCAL variables.
+ (add_AT_location_description): Pass descr instead of rtl.
+ (add_location_or_const_value_attribute, add_bound_info,
+ gen_subprogram_die): Adjust its callers.
+ (rtl_for_decl_location): Avoid constant pool references.
+
+--- gcc/config/i386/i386-protos.h 20 Aug 2002 17:20:36 -0000 1.1.1.1
++++ gcc/config/i386/i386-protos.h 20 Aug 2002 22:35:02 -0000
+@@ -113,6 +113,7 @@ extern const char *output_fix_trunc PARA
+ extern const char *output_fp_compare PARAMS ((rtx, rtx*, int, int));
+
+ extern void i386_dwarf_output_addr_const PARAMS ((FILE*, rtx));
++extern void i386_output_dwarf_dtprel PARAMS ((FILE*, int, rtx));
+ extern rtx i386_simplify_dwarf_addr PARAMS ((rtx));
+
+ extern void ix86_expand_clear PARAMS ((rtx));
+--- gcc/config/i386/i386.c 20 Aug 2002 17:20:36 -0000 1.1.1.1
++++ gcc/config/i386/i386.c 20 Aug 2002 22:35:02 -0000
+@@ -5921,6 +5921,33 @@ i386_dwarf_output_addr_const (file, x)
+ fputc ('\n', file);
+ }
+
++/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
++ We need to emit DTP-relative relocations. */
++
++void
++i386_output_dwarf_dtprel (file, size, x)
++ FILE *file;
++ int size;
++ rtx x;
++{
++ switch (size)
++ {
++ case 4:
++ fputs (ASM_LONG, file);
++ break;
++ case 8:
++#ifdef ASM_QUAD
++ fputs (ASM_QUAD, file);
++ break;
++#endif
++ default:
++ abort ();
++ }
++
++ output_addr_const (file, x);
++ fputs ("@DTPOFF", file);
++}
++
+ /* In the name of slightly smaller debug output, and to cater to
+ general assembler losage, recognize PIC+GOTOFF and turn it back
+ into a direct symbol reference. */
+--- gcc/config/i386/i386.h 20 Aug 2002 17:20:36 -0000 1.1.1.1
++++ gcc/config/i386/i386.h 20 Aug 2002 22:35:02 -0000
+@@ -2899,6 +2899,13 @@ extern int const svr4_dbx_register_map[F
+ #define ASM_SIMPLIFY_DWARF_ADDR(X) \
+ i386_simplify_dwarf_addr (X)
+
++/* Emit a dtp-relative reference to a TLS variable. */
++
++#ifdef HAVE_AS_TLS
++#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \
++ i386_output_dwarf_dtprel (FILE, SIZE, X)
++#endif
++
+ /* Switch to init or fini section via SECTION_OP, emit a call to FUNC,
+ and switch back. For x86 we do this only to save a few bytes that
+ would otherwise be unused in the text section. */
+--- gcc/dwarf2.h 20 Aug 2002 17:20:19 -0000 1.1.1.1
++++ gcc/dwarf2.h 20 Aug 2002 22:35:02 -0000
+@@ -399,10 +399,12 @@ enum dwarf_location_atom
+ DW_OP_push_object_address = 0x97,
+ DW_OP_call2 = 0x98,
+ DW_OP_call4 = 0x99,
+- DW_OP_calli = 0x9a
++ DW_OP_call_ref = 0x9a,
++ /* GNU extensions. */
++ DW_OP_GNU_push_tls_address = 0xe0
+ };
+
+-#define DW_OP_lo_user 0x80 /* Implementation-defined range start. */
++#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */
+ #define DW_OP_hi_user 0xff /* Implementation-defined range end. */
+
+ /* Type encodings. */
+--- gcc/dwarf2out.c 20 Aug 2002 17:20:19 -0000 1.1.1.1
++++ gcc/dwarf2out.c 20 Aug 2002 22:40:42 -0000
+@@ -2169,6 +2169,11 @@ dwarf2out_frame_finish ()
+ /* And now, the subset of the debugging information support code necessary
+ for emitting location expressions. */
+
++/* We need some way to distinguish DW_OP_addr with a direct symbol
++ relocation from DW_OP_addr with a dtp-relative symbol relocation. */
++#define INTERNAL_DW_OP_tls_addr (0x100 + DW_OP_addr)
++
++
+ typedef struct dw_val_struct *dw_val_ref;
+ typedef struct die_struct *dw_die_ref;
+ typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
+@@ -2294,6 +2299,7 @@ dwarf_stack_op_name (op)
+ switch (op)
+ {
+ case DW_OP_addr:
++ case INTERNAL_DW_OP_tls_addr:
+ return "DW_OP_addr";
+ case DW_OP_deref:
+ return "DW_OP_deref";
+@@ -2583,6 +2589,16 @@ dwarf_stack_op_name (op)
+ return "DW_OP_xderef_size";
+ case DW_OP_nop:
+ return "DW_OP_nop";
++ case DW_OP_push_object_address:
++ return "DW_OP_push_object_address";
++ case DW_OP_call2:
++ return "DW_OP_call2";
++ case DW_OP_call4:
++ return "DW_OP_call4";
++ case DW_OP_call_ref:
++ return "DW_OP_call_ref";
++ case DW_OP_GNU_push_tls_address:
++ return "DW_OP_GNU_push_tls_address";
+ default:
+ return "OP_<unknown>";
+ }
+@@ -2640,6 +2656,7 @@ size_of_loc_descr (loc)
+ switch (loc->dw_loc_opc)
+ {
+ case DW_OP_addr:
++ case INTERNAL_DW_OP_tls_addr:
+ size += DWARF2_ADDR_SIZE;
+ break;
+ case DW_OP_const1u:
+@@ -2725,6 +2742,15 @@ size_of_loc_descr (loc)
+ case DW_OP_xderef_size:
+ size += 1;
+ break;
++ case DW_OP_call2:
++ size += 2;
++ break;
++ case DW_OP_call4:
++ size += 4;
++ break;
++ case DW_OP_call_ref:
++ size += DWARF2_ADDR_SIZE;
++ break;
+ default:
+ break;
+ }
+@@ -2874,6 +2900,17 @@ output_loc_operands (loc)
+ case DW_OP_xderef_size:
+ dw2_asm_output_data (1, val1->v.val_int, NULL);
+ break;
++
++ case INTERNAL_DW_OP_tls_addr:
++#ifdef ASM_OUTPUT_DWARF_DTPREL
++ ASM_OUTPUT_DWARF_DTPREL (asm_out_file, DWARF2_ADDR_SIZE,
++ val1->v.val_addr);
++ fputc ('\n', asm_out_file);
++#else
++ abort ();
++#endif
++ break;
++
+ default:
+ /* Other codes have no operands. */
+ break;
+@@ -3598,7 +3635,8 @@ static unsigned int simple_field_decl_al
+ static unsigned HOST_WIDE_INT simple_type_size_in_bits PARAMS ((tree));
+ static HOST_WIDE_INT field_byte_offset PARAMS ((tree));
+ static void add_AT_location_description PARAMS ((dw_die_ref,
+- enum dwarf_attribute, rtx));
++ enum dwarf_attribute,
++ dw_loc_descr_ref));
+ static void add_data_member_location_attribute PARAMS ((dw_die_ref, tree));
+ static void add_const_value_attribute PARAMS ((dw_die_ref, rtx));
+ static rtx rtl_for_decl_location PARAMS ((tree));
+@@ -8031,6 +8069,41 @@ loc_descriptor_from_tree (loc, addressp)
+ : 0);
+
+ case VAR_DECL:
++ if (DECL_THREAD_LOCAL (loc))
++ {
++ rtx rtl;
++
++#ifndef ASM_OUTPUT_DWARF_DTPREL
++ /* If this is not defined, we have no way to emit the data. */
++ return 0;
++#endif
++ /* The way DW_OP_GNU_push_tls_address is specified, we can only
++ look up addresses of objects in the current module. */
++ if (DECL_P (loc) && TREE_PUBLIC (loc) && !MODULE_LOCAL_P (loc))
++ return 0;
++
++ rtl = rtl_for_decl_location (loc);
++ if (rtl == NULL_RTX)
++ return 0;
++
++ if (GET_CODE (rtl) != MEM)
++ return 0;
++ rtl = XEXP (rtl, 0);
++ if (! CONSTANT_P (rtl))
++ return 0;
++
++ ret = new_loc_descr (INTERNAL_DW_OP_tls_addr, 0, 0);
++ ret->dw_loc_oprnd1.val_class = dw_val_class_addr;
++ ret->dw_loc_oprnd1.v.val_addr = rtl;
++
++ ret1 = new_loc_descr (DW_OP_GNU_push_tls_address, 0, 0);
++ add_loc_descr (&ret, ret1);
++
++ indirect_p = 1;
++ break;
++ }
++ /* FALLTHRU */
++
+ case PARM_DECL:
+ {
+ rtx rtl = rtl_for_decl_location (loc);
+@@ -8531,14 +8604,12 @@ field_byte_offset (decl)
+ whole parameters. Note that the location attributes for struct fields are
+ generated by the routine `data_member_location_attribute' below. */
+
+-static void
+-add_AT_location_description (die, attr_kind, rtl)
++static inline void
++add_AT_location_description (die, attr_kind, descr)
+ dw_die_ref die;
+ enum dwarf_attribute attr_kind;
+- rtx rtl;
++ dw_loc_descr_ref descr;
+ {
+- dw_loc_descr_ref descr = loc_descriptor (rtl);
+-
+ if (descr != 0)
+ add_AT_loc (die, attr_kind, descr);
+ }
+@@ -8963,6 +9034,13 @@ rtl_for_decl_location (decl)
+ if (rtl)
+ rtl = ASM_SIMPLIFY_DWARF_ADDR (rtl);
+ #endif
++
++ /* If we don't look past the constant pool, we risk emitting a
++ reference to a constant pool entry that isn't referenced from
++ code, and thus is not emitted. */
++ if (rtl)
++ rtl = avoid_constant_pool_reference (rtl);
++
+ return rtl;
+ }
+
+@@ -8983,6 +9061,7 @@ add_location_or_const_value_attribute (d
+ tree decl;
+ {
+ rtx rtl;
++ dw_loc_descr_ref descr;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return;
+@@ -8993,16 +9072,11 @@ add_location_or_const_value_attribute (d
+ if (rtl == NULL_RTX)
+ return;
+
+- /* If we don't look past the constant pool, we risk emitting a
+- reference to a constant pool entry that isn't referenced from
+- code, and thus is not emitted. */
+- rtl = avoid_constant_pool_reference (rtl);
+-
+ switch (GET_CODE (rtl))
+ {
+ case ADDRESSOF:
+- /* The address of a variable that was optimized away; don't emit
+- anything. */
++ /* The address of a variable that was optimized away;
++ don't emit anything. */
+ break;
+
+ case CONST_INT:
+@@ -9017,12 +9091,24 @@ add_location_or_const_value_attribute (d
+ break;
+
+ case MEM:
+- case REG:
+- case SUBREG:
+- case CONCAT:
+- add_AT_location_description (die, DW_AT_location, rtl);
++ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++ {
++ /* Need loc_descriptor_from_tree since that's where we know
++ how to handle TLS variables. Want the object's address
++ since the top-level DW_AT_location assumes such. See
++ the confusion in loc_descriptor for reference. */
++ descr = loc_descriptor_from_tree (decl, 1);
++ }
++ else
++ {
++ case REG:
++ case SUBREG:
++ case CONCAT:
++ descr = loc_descriptor (rtl);
++ }
++ add_AT_location_description (die, DW_AT_location, descr);
+ break;
+-
++
+ default:
+ abort ();
+ }
+@@ -9154,7 +9240,8 @@ add_bound_info (subrange_die, bound_attr
+
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+ add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+- add_AT_location_description (decl_die, DW_AT_location, loc);
++ add_AT_location_description (decl_die, DW_AT_location,
++ loc_descriptor (loc));
+ add_AT_die_ref (subrange_die, bound_attr, decl_die);
+ }
+
+@@ -10359,7 +10446,7 @@ gen_subprogram_die (decl, context_die)
+ is not part of the state saved/restored for inline functions. */
+ if (current_function_needs_context)
+ add_AT_location_description (subr_die, DW_AT_static_link,
+- lookup_static_chain (decl));
++ loc_descriptor (lookup_static_chain (decl)));
+ #endif
+ }
+
--- /dev/null
+--- gcc/cp/lex.c.jj Sat May 25 00:02:23 2002
++++ gcc/cp/lex.c Wed Jun 19 19:33:51 2002
+@@ -396,6 +396,7 @@ static const struct resword reswords[] =
+ { "__restrict__", RID_RESTRICT, 0 },
+ { "__signed", RID_SIGNED, 0 },
+ { "__signed__", RID_SIGNED, 0 },
++ { "__thread", RID_THREAD, 0 },
+ { "__typeof", RID_TYPEOF, 0 },
+ { "__typeof__", RID_TYPEOF, 0 },
+ { "__volatile", RID_VOLATILE, 0 },
+@@ -502,6 +503,7 @@ const short rid_to_yy[RID_MAX] =
+ /* RID_BOUNDED */ 0,
+ /* RID_UNBOUNDED */ 0,
+ /* RID_COMPLEX */ TYPESPEC,
++ /* RID_THREAD */ SCSPEC,
+
+ /* C++ */
+ /* RID_FRIEND */ SCSPEC,
+--- gcc/cp/decl.c.jj Wed Jun 19 19:33:51 2002
++++ gcc/cp/decl.c Wed Jun 19 19:33:51 2002
+@@ -7122,7 +7122,8 @@ check_tag_decl (declspecs)
+ || value == ridpointers[(int) RID_VIRTUAL]
+ || value == ridpointers[(int) RID_CONST]
+ || value == ridpointers[(int) RID_VOLATILE]
+- || value == ridpointers[(int) RID_EXPLICIT])
++ || value == ridpointers[(int) RID_EXPLICIT]
++ || value == ridpointers[(int) RID_THREAD])
+ ob_modifier = value;
+ }
+
+@@ -7596,6 +7597,12 @@ static tree
+ obscure_complex_init (decl, init)
+ tree decl, init;
+ {
++ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++ {
++ error ("run-time initialization of thread-local storage");
++ return NULL_TREE;
++ }
++
+ if (! flag_no_inline && TREE_STATIC (decl))
+ {
+ if (extract_init (decl, init))
+@@ -9290,6 +9297,16 @@ grokvardecl (type, declarator, specbits_
+ TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
+ }
+
++ if (RIDBIT_SETP (RID_THREAD, specbits))
++ {
++ if (targetm.have_tls)
++ DECL_THREAD_LOCAL (decl) = 1;
++ else
++ /* A mere warning is sure to result in improper semantics
++ at runtime. Don't bother to allow this to compile. */
++ error ("thread-local storage not supported for this target");
++ }
++
+ if (TREE_PUBLIC (decl))
+ {
+ /* [basic.link]: A name with no linkage (notably, the name of a class
+@@ -10192,10 +10209,22 @@ grokdeclarator (declarator, declspecs, d
+ }
+ else if (RIDBIT_SETP (i, specbits))
+ pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
++
++ /* Diagnose "__thread extern". Recall that this list
++ is in the reverse order seen in the text. */
++ if (i == (int)RID_THREAD)
++ {
++ if (RIDBIT_SETP (RID_EXTERN, specbits))
++ error ("`__thread' before `extern'");
++ if (RIDBIT_SETP (RID_STATIC, specbits))
++ error ("`__thread' before `static'");
++ }
++
+ if (i == (int)RID_EXTERN
+ && TREE_PURPOSE (spec) == error_mark_node)
+ /* This extern was part of a language linkage. */
+ extern_langp = 1;
++
+ RIDBIT_SET (i, specbits);
+ goto found;
+ }
+@@ -10492,6 +10521,7 @@ grokdeclarator (declarator, declspecs, d
+ {
+ if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++;
+ if (RIDBIT_SETP (RID_EXTERN, specbits) && !extern_langp) nclasses++;
++ if (RIDBIT_SETP (RID_THREAD, specbits)) nclasses++;
+ if (decl_context == PARM && nclasses > 0)
+ error ("storage class specifiers invalid in parameter declarations");
+ if (RIDBIT_SETP (RID_TYPEDEF, specbits))
+@@ -10523,6 +10553,13 @@ grokdeclarator (declarator, declspecs, d
+ /* Warn about storage classes that are invalid for certain
+ kinds of declarations (parameters, typenames, etc.). */
+
++ /* "static __thread" and "extern __thread" are allowed. */
++ if (nclasses == 2
++ && RIDBIT_SETP (RID_THREAD, specbits)
++ && (RIDBIT_SETP (RID_EXTERN, specbits)
++ || RIDBIT_SETP (RID_STATIC, specbits)))
++ nclasses = 1;
++
+ if (nclasses > 1)
+ error ("multiple storage classes in declaration of `%s'", name);
+ else if (decl_context != NORMAL && nclasses > 0)
+@@ -10578,6 +10615,7 @@ grokdeclarator (declarator, declspecs, d
+ RIDBIT_RESET (RID_REGISTER, specbits);
+ RIDBIT_RESET (RID_AUTO, specbits);
+ RIDBIT_RESET (RID_EXTERN, specbits);
++ RIDBIT_RESET (RID_THREAD, specbits);
+ }
+ }
+ else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag)
+@@ -10600,6 +10638,14 @@ grokdeclarator (declarator, declspecs, d
+ if (RIDBIT_SETP (RID_AUTO, specbits))
+ error ("top-level declaration of `%s' specifies `auto'", name);
+ }
++ else if (RIDBIT_SETP (RID_THREAD, specbits)
++ && !RIDBIT_SETP (RID_EXTERN, specbits)
++ && !RIDBIT_SETP (RID_STATIC, specbits))
++ {
++ error ("function-scope `%s' implicitly auto and declared `__thread'",
++ name);
++ RIDBIT_RESET (RID_THREAD, specbits);
++ }
+
+ if (nclasses > 0 && friendp)
+ error ("storage class specifiers invalid in friend function declarations");
+@@ -11800,6 +11846,8 @@ friend declaration requires class-key, i
+ error ("storage class `auto' invalid for function `%s'", name);
+ else if (RIDBIT_SETP (RID_REGISTER, specbits))
+ error ("storage class `register' invalid for function `%s'", name);
++ else if (RIDBIT_SETP (RID_THREAD, specbits))
++ error ("storage class `__thread' invalid for function `%s'", name);
+
+ /* Function declaration not at top level.
+ Storage classes other than `extern' are not allowed
+--- gcc/doc/extend.texi.jj Wed Jun 19 19:33:51 2002
++++ gcc/doc/extend.texi Wed Jun 19 19:33:51 2002
+@@ -432,6 +432,7 @@ extensions, accepted by GCC in C89 mode
+ * Target Builtins:: Built-in functions specific to particular targets.
+ * Pragmas:: Pragmas accepted by GCC.
+ * Unnamed Fields:: Unnamed struct/union fields within structs/unions.
++* Thread-Local:: Per-thread variables.
+ @end menu
+
+ @node Statement Exprs
+@@ -6119,6 +6120,265 @@ It is ambiguous which @code{a} is being
+ Such constructs are not supported and must be avoided. In the future,
+ such constructs may be detected and treated as compilation errors.
+
++@node Thread-Local
++@section Thread-Local Storage
++@cindex Thread-Local Storage
++@cindex TLS
++@cindex __thread
++
++Thread-local storage (@acronym{TLS}) is a mechanism by which variables
++are allocated such that there is one instance of the variable per extant
++thread. The run-time model GCC uses to implement this originates
++in the IA-64 processor-specific ABI, but has since been migrated
++to other processors as well. It requires significant support from
++the linker (@command{ld}), dynamic linker (@command{ld.so}), and
++system libraries (@file{libc.so} and @file{libpthread.so}), so it
++is not available everywhere.
++
++At the user level, the extension is visible with a new storage
++class keyword: @code{__thread}. For example:
++
++@example
++__thread int i;
++extern __thread struct state s;
++static __thread char *p;
++@end example
++
++The @code{__thread} specifier may be used alone, with the @code{extern}
++or @code{static} specifiers, but with no other storage class specifier.
++When used with @code{extern} or @code{static}, @code{__thread} must appear
++immediately after the other storage class specifier.
++
++The @code{__thread} specifier may be applied to any global, file-scoped
++static, function-scoped static, or static data member of a class. It may
++not be applied to block-scoped automatic or non-static data member.
++
++When the address-of operator is applied to a thread-local variable, it is
++evaluated at run-time and returns the address of the current thread's
++instance of that variable. An address so obtained may be used by any
++thread. When a thread terminates, any pointers to thread-local variables
++in that thread become invalid.
++
++No static initialization may refer to the address of a thread-local variable.
++
++In C++, if an initializer is present for a thread-local variable, it must
++be a @var{constant-expression}, as defined in 5.19.2 of the ANSI/ISO C++
++standard.
++
++See @uref{http://people.redhat.com/drepper/tls.pdf,
++ELF Handling For Thread-Local Storage} for a detailed explanation of
++the four thread-local storage addressing models, and how the run-time
++is expected to function.
++
++@menu
++* C99 Thread-Local Edits::
++* C++98 Thread-Local Edits::
++@end menu
++
++@node C99 Thread-Local Edits
++@subsection ISO/IEC 9899:1999 Edits for Thread-Local Storage
++
++The following are a set of changes to ISO/IEC 9899:1999 (aka C99)
++that document the exact semantics of the language extension.
++
++@itemize @bullet
++@item
++@cite{5.1.2 Execution environments}
++
++Add new text after paragraph 1
++
++@quotation
++Within either execution environment, a @dfn{thread} is a flow of
++control within a program. It is implementation defined whether
++or not there may be more than one thread associated with a program.
++It is implementation defined how threads beyond the first are
++created, the name and type of the function called at thread
++startup, and how threads may be terminated. However, objects
++with thread storage duration shall be initialized before thread
++startup.
++@end quotation
++
++@item
++@cite{6.2.4 Storage durations of objects}
++
++Add new text before paragraph 3
++
++@quotation
++An object whose identifier is declared with the storage-class
++specifier @w{@code{__thread}} has @dfn{thread storage duration}.
++Its lifetime is the entire execution of the thread, and its
++stored value is initialized only once, prior to thread startup.
++@end quotation
++
++@item
++@cite{6.4.1 Keywords}
++
++Add @code{__thread}.
++
++@item
++@cite{6.7.1 Storage-class specifiers}
++
++Add @code{__thread} to the list of storage class specifiers in
++paragraph 1.
++
++Change paragraph 2 to
++
++@quotation
++With the exception of @code{__thread}, at most one storage-class
++specifier may be given [@dots{}]. The @code{__thread} specifier may
++be used alone, or immediately following @code{extern} or
++@code{static}.
++@end quotation
++
++Add new text after paragraph 6
++
++@quotation
++The declaration of an identifier for a variable that has
++block scope that specifies @code{__thread} shall also
++specify either @code{extern} or @code{static}.
++
++The @code{__thread} specifier shall be used only with
++variables.
++@end quotation
++@end itemize
++
++@node C++98 Thread-Local Edits
++@subsection ISO/IEC 14882:1998 Edits for Thread-Local Storage
++
++The following are a set of changes to ISO/IEC 14882:1998 (aka C++98)
++that document the exact semantics of the language extension.
++
++@itemize @bullet
++@b{[intro.execution]}
++
++New text after paragraph 4
++
++@quotation
++A @dfn{thread} is a flow of control within the abstract machine.
++It is implementation defined whether or not there may be more than
++one thread.
++@end quotation
++
++New text after paragraph 7
++
++@quotation
++It is unspecified whether additional action must be taken to
++ensure when and whether side effects are visible to other threads.
++@end quotation
++
++@item
++@b{[lex.key]}
++
++Add @code{__thread}.
++
++@item
++@b{[basic.start.main]}
++
++Add after paragraph 5
++
++@quotation
++The thread that begins execution at the @code{main} function is called
++the @dfn{main thread}. It is implementation defined how functions
++beginning threads other than the main thread are designated or typed.
++A function so designated, as well as the @code{main} function, is called
++a @dfn{thread startup function}. It is implementation defined what
++happens if a thread startup function returns. It is implementation
++defined what happens to other threads when any thread calls @code{exit}.
++@end quotation
++
++@item
++@b{[basic.start.init]}
++
++Add after paragraph 4
++
++@quotation
++The storage for an object of thread storage duration shall be
++staticly initialized before the first statement of the thread startup
++function. An object of thread storage duration shall not require
++dynamic initialization.
++@end quotation
++
++@item
++@b{[basic.start.term]}
++
++Add after paragraph 3
++
++@quotation
++The type of an object with thread storage duration shall not have a
++non-trivial destructor, nor shall it be an array type whose elements
++(directly or indirectly) have non-trivial destructors.
++@end quotation
++
++@item
++@b{[basic.stc]}
++
++Add ``thread storage duration'' to the list in paragraph 1.
++
++Change paragraph 2
++
++@quotation
++Thread, static, and automatic storage durations are associated with
++objects introduced by declarations [@dots{}].
++@end quotation
++
++Add @code{__thread} to the list of specifiers in paragraph 3.
++
++@item
++@b{[basic.stc.thread]}
++
++New section before @b{[basic.stc.static]}
++
++@quotation
++The keyword @code{__thread} applied to an non-local object gives the
++object thread storage duration.
++
++A local variable or class data member declared both @code{static}
++and @code{__thread} gives the variable or member thread storage
++duration.
++@end quotation
++
++@item
++@b{[basic.stc.static]}
++
++Change paragraph 1
++
++@quotation
++All objects which have neither thread storage duration, dynamic
++storage duration nor are local [@dots{}].
++@end quotation
++
++@item
++@b{[dcl.stc]}
++
++Add @code{__thread} to the list in paragraph 1.
++
++Change paragraph 1
++
++@quotation
++With the exception of @code{__thread}, at most one
++@var{storage-class-specifier} shall appear in a given
++@var{decl-specifier-seq}. The @code{__thread} specifier may
++be used alone, or immediately following the @code{extern} or
++@code{static} specifiers. [@dots{}]
++@end quotation
++
++Add after paragraph 5
++
++@quotation
++The @code{__thread} specifier can be applied only to the names of objects
++and to anonymous unions.
++@end quotation
++
++@item
++@b{[class.mem]}
++
++Add after paragraph 6
++
++@quotation
++Non-@code{static} members shall not be @code{__thread}.
++@end quotation
++@end itemize
++
+ @node C++ Extensions
+ @chapter Extensions to the C++ Language
+ @cindex extensions, C++ language
+--- gcc/doc/invoke.texi.jj Tue May 21 20:27:44 2002
++++ gcc/doc/invoke.texi Wed Jun 19 19:33:52 2002
+@@ -674,7 +674,7 @@ in the following sections.
+ -fverbose-asm -fpack-struct -fstack-check @gol
+ -fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol
+ -fargument-alias -fargument-noalias @gol
+--fargument-noalias-global -fleading-underscore}
++-fargument-noalias-global -fleading-underscore -ftls-model=@var{model}}
+ @end table
+
+ @menu
+@@ -9910,6 +9910,14 @@ is to help link with legacy assembly cod
+
+ Be warned that you should know what you are doing when invoking this
+ option, and that not all targets provide complete support for it.
++
++@item -ftls-model=@var{model}
++Alter the thread-local storage model to be used (@pxref{Thread-Local}).
++The @var{model} argument should be one of @code{global-dynamic},
++@code{local-dynamic}, @code{initial-exec} or @code{local-exec}.
++
++The default without @option{-fpic} is @code{initial-exec}; with
++@option{-fpic} the default is @code{global-dynamic}.
+ @end table
+
+ @c man end
+--- gcc/config/i386/i386.c.jj Wed Jun 19 19:33:51 2002
++++ gcc/config/i386/i386.c Wed Jun 19 23:18:18 2002
+@@ -536,6 +536,10 @@ int const svr4_dbx_register_map[FIRST_PS
+ rtx ix86_compare_op0 = NULL_RTX;
+ rtx ix86_compare_op1 = NULL_RTX;
+
++/* The encoding characters for the four TLS models present in ELF. */
++
++static char const tls_model_chars[] = " GLil";
++
+ #define MAX_386_STACK_LOCALS 3
+ /* Size of the register save area. */
+ #define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16)
+@@ -544,6 +548,7 @@ rtx ix86_compare_op1 = NULL_RTX;
+ struct machine_function
+ {
+ rtx stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
++ const char *some_ld_name;
+ int save_varrargs_registers;
+ int accesses_prev_frame;
+ };
+@@ -596,6 +601,9 @@ enum cmodel ix86_cmodel;
+ /* Asm dialect. */
+ const char *ix86_asm_string;
+ enum asm_dialect ix86_asm_dialect = ASM_ATT;
++/* TLS dialext. */
++const char *ix86_tls_dialect_string;
++enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU;
+
+ /* which cpu are we scheduling for */
+ enum processor_type ix86_cpu;
+@@ -646,12 +654,17 @@ static char internal_label_prefix[16];
+ static int internal_label_prefix_len;
+ \f
+ static int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
++static int tls_symbolic_operand_1 PARAMS ((rtx, enum tls_model));
+ static void output_pic_addr_const PARAMS ((FILE *, rtx, int));
+ static void put_condition_code PARAMS ((enum rtx_code, enum machine_mode,
+ int, int, FILE *));
++static const char *get_some_local_dynamic_name PARAMS ((void));
++static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
++static rtx maybe_get_pool_constant PARAMS ((rtx));
+ static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx));
+ static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code,
+ rtx *, rtx *));
++static rtx get_thread_pointer PARAMS ((void));
+ static rtx gen_push PARAMS ((rtx));
+ static int memory_address_length PARAMS ((rtx addr));
+ static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type));
+@@ -820,6 +833,11 @@ static enum x86_64_reg_class merge_class
+ #undef TARGET_SCHED_REORDER
+ #define TARGET_SCHED_REORDER ix86_sched_reorder
+
++#ifdef HAVE_AS_TLS
++#undef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS true
++#endif
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
+ \f
+ /* Sometimes certain combinations of command options do not make
+@@ -1109,6 +1127,17 @@ override_options ()
+ ix86_branch_cost = i;
+ }
+
++ if (ix86_tls_dialect_string)
++ {
++ if (strcmp (ix86_tls_dialect_string, "gnu") == 0)
++ ix86_tls_dialect = TLS_DIALECT_GNU;
++ else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
++ ix86_tls_dialect = TLS_DIALECT_SUN;
++ else
++ error ("bad value (%s) for -mtls-dialect= switch",
++ ix86_tls_dialect_string);
++ }
++
+ /* Keep nonleaf frame pointers. */
+ if (TARGET_OMIT_LEAF_FRAME_POINTER)
+ flag_omit_frame_pointer = 1;
+@@ -3007,6 +3036,70 @@ local_symbolic_operand (op, mode)
+ return 0;
+ }
+
++/* Test for various thread-local symbols. See ix86_encode_section_info. */
++
++int
++tls_symbolic_operand (op, mode)
++ register rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ const char *symbol_str;
++
++ if (GET_CODE (op) != SYMBOL_REF)
++ return 0;
++ symbol_str = XSTR (op, 0);
++
++ if (symbol_str[0] != '%')
++ return 0;
++ return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars;
++}
++
++static int
++tls_symbolic_operand_1 (op, kind)
++ rtx op;
++ enum tls_model kind;
++{
++ const char *symbol_str;
++
++ if (GET_CODE (op) != SYMBOL_REF)
++ return 0;
++ symbol_str = XSTR (op, 0);
++
++ return symbol_str[0] == '%' && symbol_str[1] == tls_model_chars[kind];
++}
++
++int
++global_dynamic_symbolic_operand (op, mode)
++ register rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ return tls_symbolic_operand_1 (op, TLS_MODEL_GLOBAL_DYNAMIC);
++}
++
++int
++local_dynamic_symbolic_operand (op, mode)
++ register rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_DYNAMIC);
++}
++
++int
++initial_exec_symbolic_operand (op, mode)
++ register rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ return tls_symbolic_operand_1 (op, TLS_MODEL_INITIAL_EXEC);
++}
++
++int
++local_exec_symbolic_operand (op, mode)
++ register rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_EXEC);
++}
++
+ /* Test for a valid operand for a call instruction. Don't allow the
+ arg pointer register or virtual regs since they may decay into
+ reg + const, which the patterns can't handle. */
+@@ -3858,7 +3951,7 @@ ix86_asm_file_end (file)
+ {
+ rtx xops[2];
+
+- if (! TARGET_DEEP_BRANCH_PREDICTION || pic_label_name[0] == 0)
++ if (pic_label_name[0] == 0)
+ return;
+
+ /* The trick here is to create a linkonce section containing the
+@@ -3896,17 +3989,33 @@ ix86_asm_file_end (file)
+ output_asm_insn ("ret", xops);
+ }
+
+-void
+-load_pic_register ()
++/* Emit code for the SET_GOT patterns. */
++
++const char *
++output_set_got (dest)
++ rtx dest;
+ {
+- rtx gotsym, pclab;
++ rtx xops[3];
+
+- if (TARGET_64BIT)
+- abort ();
++ xops[0] = dest;
++ xops[1] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
++
++ if (! TARGET_DEEP_BRANCH_PREDICTION || !flag_pic)
++ {
++ xops[2] = gen_rtx_LABEL_REF (Pmode, gen_label_rtx ());
++
++ if (!flag_pic)
++ output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
++ else
++ output_asm_insn ("call\t%a2", xops);
+
+- gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
++ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
++ CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
+
+- if (TARGET_DEEP_BRANCH_PREDICTION)
++ if (flag_pic)
++ output_asm_insn ("pop{l}\t%0", xops);
++ }
++ else
+ {
+ if (! pic_label_name[0])
+ {
+@@ -3915,16 +4024,17 @@ load_pic_register ()
+ else
+ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
+ }
+- pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name));
+- }
++ xops[2] = gen_rtx_SYMBOL_REF (Pmode, pic_label_name);
++ xops[2] = gen_rtx_MEM (QImode, xops[2]);
++ output_asm_insn ("call\t%X2", xops);
++ }
++
++ if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
++ output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops);
+ else
+- {
+- pclab = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+- }
+-
+- emit_insn (gen_prologue_get_pc (pic_offset_table_rtx, pclab));
+-
+- emit_insn (gen_prologue_set_got (pic_offset_table_rtx, gotsym, pclab));
++ output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %a1+(.-%a2)}", xops);
++
++ return "";
+ }
+
+ /* Generate an "push" pattern for input ARG. */
+@@ -4253,7 +4363,15 @@ ix86_expand_prologue ()
+ #endif
+
+ if (pic_reg_used)
+- load_pic_register ();
++ {
++ insn = emit_insn (gen_set_got (pic_offset_table_rtx));
++
++ /* ??? The current_function_uses_pic_offset_table flag is woefully
++ inaccurate, as it isn't updated as code gets deleted. Allow the
++ thing to be removed. A better solution would be to actually get
++ proper liveness for ebx, as then we won't save/restore it too. */
++ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
++ }
+
+ /* If we are profiling, make sure no instructions are scheduled before
+ the call to mcount. However, if -fpic, the above call will have
+@@ -4694,6 +4812,114 @@ ix86_find_base_term (x)
+ return term;
+ }
+ \f
++/* Determine if a given RTX is a valid constant. We already know this
++ satisfies CONSTANT_P. */
++
++bool
++legitimate_constant_p (x)
++ rtx x;
++{
++ rtx inner;
++
++ switch (GET_CODE (x))
++ {
++ case SYMBOL_REF:
++ /* TLS symbols are not constant. */
++ if (tls_symbolic_operand (x, Pmode))
++ return false;
++ break;
++
++ case CONST:
++ inner = XEXP (x, 0);
++
++ /* Offsets of TLS symbols are never valid.
++ Discourage CSE from creating them. */
++ if (GET_CODE (inner) == PLUS
++ && tls_symbolic_operand (XEXP (inner, 0), Pmode))
++ return false;
++
++ /* Only some unspecs are valid as "constants". */
++ if (GET_CODE (inner) == UNSPEC)
++ switch (XINT (inner, 1))
++ {
++ case UNSPEC_TPOFF:
++ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
++ case UNSPEC_TP:
++ return true;
++ default:
++ return false;
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ /* Otherwise we handle everything else in the move patterns. */
++ return true;
++}
++
++/* Determine if a given RTX is a valid constant address. */
++
++bool
++constant_address_p (x)
++ rtx x;
++{
++ switch (GET_CODE (x))
++ {
++ case LABEL_REF:
++ case CONST_INT:
++ return true;
++
++ case CONST_DOUBLE:
++ return TARGET_64BIT;
++
++ case CONST:
++ case SYMBOL_REF:
++ return !flag_pic && legitimate_constant_p (x);
++
++ default:
++ return false;
++ }
++}
++
++/* Nonzero if the constant value X is a legitimate general operand
++ when generating PIC code. It is given that flag_pic is on and
++ that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
++
++bool
++legitimate_pic_operand_p (x)
++ rtx x;
++{
++ rtx inner;
++
++ switch (GET_CODE (x))
++ {
++ case CONST:
++ inner = XEXP (x, 0);
++
++ /* Only some unspecs are valid as "constants". */
++ if (GET_CODE (inner) == UNSPEC)
++ switch (XINT (inner, 1))
++ {
++ case UNSPEC_TPOFF:
++ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
++ case UNSPEC_TP:
++ return true;
++ default:
++ return false;
++ }
++ /* FALLTHRU */
++
++ case SYMBOL_REF:
++ case LABEL_REF:
++ return legitimate_pic_address_disp_p (x);
++
++ default:
++ return true;
++ }
++}
++
+ /* Determine if a given CONST RTX is a valid memory displacement
+ in PIC mode. */
+
+@@ -4701,6 +4927,8 @@ int
+ legitimate_pic_address_disp_p (disp)
+ register rtx disp;
+ {
++ bool saw_plus;
++
+ /* In 64bit mode we can allow direct addresses of symbols and labels
+ when they are not dynamic symbols. */
+ if (TARGET_64BIT)
+@@ -4737,25 +4965,39 @@ legitimate_pic_address_disp_p (disp)
+ return 1;
+ }
+
++ saw_plus = false;
+ if (GET_CODE (disp) == PLUS)
+ {
+ if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
+ return 0;
+ disp = XEXP (disp, 0);
++ saw_plus = true;
+ }
+
+ if (GET_CODE (disp) != UNSPEC
+ || XVECLEN (disp, 0) != 1)
+ return 0;
+
+- /* Must be @GOT or @GOTOFF. */
+ switch (XINT (disp, 1))
+ {
+- case 6: /* @GOT */
++ case UNSPEC_GOT:
++ if (saw_plus)
++ return false;
+ return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF;
+-
+- case 7: /* @GOTOFF */
++ case UNSPEC_GOTOFF:
+ return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++ case UNSPEC_GOTTPOFF:
++ if (saw_plus)
++ return false;
++ return initial_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++ case UNSPEC_NTPOFF:
++ if (saw_plus)
++ return false;
++ return local_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++ case UNSPEC_DTPOFF:
++ if (saw_plus)
++ return false;
++ return local_dynamic_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+ }
+
+ return 0;
+@@ -4882,12 +5124,6 @@ legitimate_address_p (mode, addr, strict
+ {
+ reason_rtx = disp;
+
+- if (!CONSTANT_ADDRESS_P (disp))
+- {
+- reason = "displacement is not constant";
+- goto report_error;
+- }
+-
+ if (TARGET_64BIT)
+ {
+ if (!x86_64_sign_extended_value (disp))
+@@ -4905,8 +5141,30 @@ legitimate_address_p (mode, addr, strict
+ }
+ }
+
+- if (flag_pic && SYMBOLIC_CONST (disp))
++ if (GET_CODE (disp) == CONST
++ && GET_CODE (XEXP (disp, 0)) == UNSPEC)
++ switch (XINT (XEXP (disp, 0), 1))
++ {
++ case UNSPEC_GOT:
++ case UNSPEC_GOTOFF:
++ case UNSPEC_GOTPCREL:
++ if (!flag_pic)
++ abort ();
++ goto is_legitimate_pic;
++
++ case UNSPEC_GOTTPOFF:
++ case UNSPEC_NTPOFF:
++ case UNSPEC_DTPOFF:
++ break;
++
++ default:
++ reason = "invalid address unspec";
++ goto report_error;
++ }
++
++ else if (flag_pic && SYMBOLIC_CONST (disp))
+ {
++ is_legitimate_pic:
+ if (TARGET_64BIT && (index || base))
+ {
+ reason = "non-constant pic memory reference";
+@@ -4949,6 +5207,11 @@ legitimate_address_p (mode, addr, strict
+ goto report_error;
+ }
+ }
++ else if (!CONSTANT_ADDRESS_P (disp))
++ {
++ reason = "displacement is not constant";
++ goto report_error;
++ }
+ }
+
+ /* Everything looks valid. */
+@@ -5129,7 +5392,102 @@ legitimize_pic_address (orig, reg)
+ }
+ return new;
+ }
++
++void
++ix86_encode_section_info (decl)
++ tree decl;
++{
++ bool local_p;
++ rtx rtl, symbol;
++
++ rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
++ if (GET_CODE (rtl) != MEM)
++ return;
++ symbol = XEXP (rtl, 0);
++ if (GET_CODE (symbol) != SYMBOL_REF)
++ return;
++
++ local_p = !DECL_P (decl) || !TREE_PUBLIC (decl) || MODULE_LOCAL_P (decl);
++
++ /* For basic x86, if using PIC, mark a SYMBOL_REF for a non-global
++ symbol so that we may access it directly in the GOT. */
++
++ if (flag_pic)
++ SYMBOL_REF_FLAG (symbol) = local_p;
++
++ /* For ELF, encode thread-local data with %[GLil] for "global dynamic",
++ "local dynamic", "initial exec" or "local exec" TLS models
++ respectively. */
++
++ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++ {
++ const char *symbol_str;
++ char *newstr;
++ size_t len;
++ enum tls_model kind;
++
++ if (!flag_pic)
++ {
++ if (local_p)
++ kind = TLS_MODEL_LOCAL_EXEC;
++ else
++ kind = TLS_MODEL_INITIAL_EXEC;
++ }
++ /* Local dynamic is inefficient when we're not combining the
++ parts of the address. */
++ else if (optimize && local_p)
++ kind = TLS_MODEL_LOCAL_DYNAMIC;
++ else
++ kind = TLS_MODEL_GLOBAL_DYNAMIC;
++ if (kind < flag_tls_default)
++ kind = flag_tls_default;
++
++ symbol_str = XSTR (symbol, 0);
++
++ if (symbol_str[0] == '%')
++ {
++ if (symbol_str[1] == tls_model_chars[kind])
++ return;
++ symbol_str += 2;
++ }
++ len = strlen (symbol_str) + 1;
++ newstr = alloca (len + 2);
++
++ newstr[0] = '%';
++ newstr[1] = tls_model_chars[kind];
++ memcpy (newstr + 2, symbol_str, len);
++
++ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1);
++ }
++}
++
++/* Undo the above when printing symbol names. */
++
++const char *
++ix86_strip_name_encoding (str)
++ const char *str;
++{
++ if (str[0] == '%')
++ str += 2;
++ if (str [0] == '*')
++ str += 1;
++ return str;
++}
+ \f
++/* Load the thread pointer into a register. */
++
++static rtx
++get_thread_pointer ()
++{
++ rtx tp;
++
++ tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
++ tp = gen_rtx_CONST (Pmode, tp);
++ tp = force_reg (Pmode, tp);
++
++ return tp;
++}
++
+ /* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+@@ -5167,6 +5525,84 @@ legitimize_address (x, oldx, mode)
+ debug_rtx (x);
+ }
+
++ log = tls_symbolic_operand (x, mode);
++ if (log)
++ {
++ rtx dest, base, off, pic;
++
++ switch (log)
++ {
++ case TLS_MODEL_GLOBAL_DYNAMIC:
++ dest = gen_reg_rtx (Pmode);
++ emit_insn (gen_tls_global_dynamic (dest, x));
++ break;
++
++ case TLS_MODEL_LOCAL_DYNAMIC:
++ base = gen_reg_rtx (Pmode);
++ emit_insn (gen_tls_local_dynamic_base (base));
++
++ off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF);
++ off = gen_rtx_CONST (Pmode, off);
++
++ return gen_rtx_PLUS (Pmode, base, off);
++
++ case TLS_MODEL_INITIAL_EXEC:
++ if (flag_pic)
++ {
++ current_function_uses_pic_offset_table = 1;
++ pic = pic_offset_table_rtx;
++ }
++ else
++ {
++ pic = gen_reg_rtx (Pmode);
++ emit_insn (gen_set_got (pic));
++ }
++
++ base = get_thread_pointer ();
++
++ off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_GOTTPOFF);
++ off = gen_rtx_CONST (Pmode, off);
++ off = gen_rtx_PLUS (Pmode, pic, off);
++ off = gen_rtx_MEM (Pmode, off);
++ RTX_UNCHANGING_P (off) = 1;
++ set_mem_alias_set (off, ix86_GOT_alias_set ());
++
++ /* Damn Sun for specifing a set of dynamic relocations without
++ considering the two-operand nature of the architecture!
++ We'd be much better off with a "GOTNTPOFF" relocation that
++ already contained the negated constant. */
++ /* ??? Using negl and reg+reg addressing appears to be a lose
++ size-wise. The negl is two bytes, just like the extra movl
++ incurred by the two-operand subl, but reg+reg addressing
++ uses the two-byte modrm form, unlike plain reg. */
++
++ dest = gen_reg_rtx (Pmode);
++ emit_insn (gen_subsi3 (dest, base, off));
++ break;
++
++ case TLS_MODEL_LOCAL_EXEC:
++ base = get_thread_pointer ();
++
++ off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x),
++ TARGET_GNU_TLS ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
++ off = gen_rtx_CONST (Pmode, off);
++
++ if (TARGET_GNU_TLS)
++ return gen_rtx_PLUS (Pmode, base, off);
++ else
++ {
++ dest = gen_reg_rtx (Pmode);
++ emit_insn (gen_subsi3 (dest, base, off));
++ }
++ break;
++
++ default:
++ abort ();
++ }
++
++ return dest;
++ }
++
+ if (flag_pic && SYMBOLIC_CONST (x))
+ return legitimize_pic_address (x, 0);
+
+@@ -5410,18 +5846,30 @@ output_pic_addr_const (file, x, code)
+ output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+ switch (XINT (x, 1))
+ {
+- case 6:
++ case UNSPEC_GOT:
+ fputs ("@GOT", file);
+ break;
+- case 7:
++ case UNSPEC_GOTOFF:
+ fputs ("@GOTOFF", file);
+ break;
+- case 8:
++ case UNSPEC_PLT:
+ fputs ("@PLT", file);
+ break;
+- case 15:
++ case UNSPEC_GOTPCREL:
+ fputs ("@GOTPCREL(%RIP)", file);
+ break;
++ case UNSPEC_GOTTPOFF:
++ fputs ("@GOTTPOFF", file);
++ break;
++ case UNSPEC_TPOFF:
++ fputs ("@TPOFF", file);
++ break;
++ case UNSPEC_NTPOFF:
++ fputs ("@NTPOFF", file);
++ break;
++ case UNSPEC_DTPOFF:
++ fputs ("@DTPOFF", file);
++ break;
+ default:
+ output_operand_lossage ("invalid UNSPEC as operand");
+ break;
+@@ -5710,6 +6158,43 @@ print_reg (x, code, file)
+ }
+ }
+
++/* Locate some local-dynamic symbol still in use by this function
++ so that we can print its name in some tls_local_dynamic_base
++ pattern. */
++
++static const char *
++get_some_local_dynamic_name ()
++{
++ rtx insn;
++
++ if (cfun->machine->some_ld_name)
++ return cfun->machine->some_ld_name;
++
++ for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
++ if (INSN_P (insn)
++ && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
++ return cfun->machine->some_ld_name;
++
++ abort ();
++}
++
++static int
++get_some_local_dynamic_name_1 (px, data)
++ rtx *px;
++ void *data ATTRIBUTE_UNUSED;
++{
++ rtx x = *px;
++
++ if (GET_CODE (x) == SYMBOL_REF
++ && local_dynamic_symbolic_operand (x, Pmode))
++ {
++ cfun->machine->some_ld_name = XSTR (x, 0);
++ return 1;
++ }
++
++ return 0;
++}
++
+ /* Meaning of CODE:
+ L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
+ C -- print opcode suffix for set/cmov insn.
+@@ -5734,6 +6219,7 @@ print_reg (x, code, file)
+ D -- print condition for SSE cmp instruction.
+ P -- if PIC, print an @PLT suffix.
+ X -- don't print any sort of PIC '@' suffix for a symbol.
++ & -- print some in-use local-dynamic symbol name.
+ */
+
+ void
+@@ -5751,6 +6237,10 @@ print_operand (file, x, code)
+ putc ('*', file);
+ return;
+
++ case '&':
++ assemble_name (file, get_some_local_dynamic_name ());
++ return;
++
+ case 'A':
+ if (ASSEMBLER_DIALECT == ASM_ATT)
+ putc ('*', file);
+@@ -6078,6 +6568,18 @@ print_operand (file, x, code)
+ REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
+ fprintf (file, "%s", dstr);
+ }
++
++ else if (GET_CODE (x) == CONST
++ && GET_CODE (XEXP (x, 0)) == UNSPEC
++ && XINT (XEXP (x, 0), 1) == UNSPEC_TP)
++ {
++ if (ASSEMBLER_DIALECT == ASM_INTEL)
++ fputs ("DWORD PTR ", file);
++ if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
++ putc ('%', file);
++ fputs ("gs:0", file);
++ }
++
+ else
+ {
+ if (code != 'P')
+@@ -6226,6 +6728,43 @@ print_operand_address (file, addr)
+ }
+ }
+ }
++
++bool
++output_addr_const_extra (file, x)
++ FILE *file;
++ rtx x;
++{
++ rtx op;
++
++ if (GET_CODE (x) != UNSPEC)
++ return false;
++
++ op = XVECEXP (x, 0, 0);
++ switch (XINT (x, 1))
++ {
++ case UNSPEC_GOTTPOFF:
++ output_addr_const (file, op);
++ fputs ("@GOTTPOFF", file);
++ break;
++ case UNSPEC_TPOFF:
++ output_addr_const (file, op);
++ fputs ("@TPOFF", file);
++ break;
++ case UNSPEC_NTPOFF:
++ output_addr_const (file, op);
++ fputs ("@NTPOFF", file);
++ break;
++ case UNSPEC_DTPOFF:
++ output_addr_const (file, op);
++ fputs ("@DTPOFF", file);
++ break;
++
++ default:
++ return false;
++ }
++
++ return true;
++}
+ \f
+ /* Split one or more DImode RTL references into pairs of SImode
+ references. The RTL can be REG, offsettable MEM, integer constant, or
+@@ -6763,51 +7302,117 @@ ix86_expand_clear (dest)
+ emit_insn (tmp);
+ }
+
++/* X is an unchanging MEM. If it is a constant pool reference, return
++ the constant pool rtx, else NULL. */
++
++static rtx
++maybe_get_pool_constant (x)
++ rtx x;
++{
++ x = XEXP (x, 0);
++
++ if (flag_pic)
++ {
++ if (GET_CODE (x) != PLUS)
++ return NULL_RTX;
++ if (XEXP (x, 0) != pic_offset_table_rtx)
++ return NULL_RTX;
++ x = XEXP (x, 1);
++ if (GET_CODE (x) != CONST)
++ return NULL_RTX;
++ x = XEXP (x, 0);
++ if (GET_CODE (x) != UNSPEC)
++ return NULL_RTX;
++ if (XINT (x, 1) != UNSPEC_GOTOFF)
++ return NULL_RTX;
++ x = XVECEXP (x, 0, 0);
++ }
++
++ if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
++ return get_pool_constant (x);
++
++ return NULL_RTX;
++}
++
+ void
+ ix86_expand_move (mode, operands)
+ enum machine_mode mode;
+ rtx operands[];
+ {
+ int strict = (reload_in_progress || reload_completed);
+- rtx insn;
++ rtx insn, op0, op1, tmp;
++
++ op0 = operands[0];
++ op1 = operands[1];
+
+- if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode))
++ /* ??? 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))
+ {
+- /* Emit insns to move operands[1] into operands[0]. */
++ 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 (GET_CODE (operands[0]) == MEM)
+- operands[1] = force_reg (Pmode, operands[1]);
++ if (tls_symbolic_operand (op1, Pmode))
++ {
++ op1 = legitimize_address (op1, op1, VOIDmode);
++ if (GET_CODE (op0) == MEM)
++ {
++ tmp = gen_reg_rtx (mode);
++ emit_insn (gen_rtx_SET (VOIDmode, tmp, op1));
++ op1 = tmp;
++ }
++ }
++ else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
++ {
++ if (GET_CODE (op0) == MEM)
++ op1 = force_reg (Pmode, op1);
+ else
+ {
+- rtx temp = operands[0];
++ rtx temp = op0;
+ if (GET_CODE (temp) != REG)
+ temp = gen_reg_rtx (Pmode);
+- temp = legitimize_pic_address (operands[1], temp);
+- if (temp == operands[0])
++ temp = legitimize_pic_address (op1, temp);
++ if (temp == op0)
+ return;
+- operands[1] = temp;
++ op1 = temp;
+ }
+ }
+ else
+ {
+- if (GET_CODE (operands[0]) == MEM
++ if (GET_CODE (op0) == MEM
+ && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
+- || !push_operand (operands[0], mode))
+- && GET_CODE (operands[1]) == MEM)
+- operands[1] = force_reg (mode, operands[1]);
+-
+- if (push_operand (operands[0], mode)
+- && ! general_no_elim_operand (operands[1], mode))
+- operands[1] = copy_to_mode_reg (mode, operands[1]);
++ || !push_operand (op0, mode))
++ && GET_CODE (op1) == MEM)
++ op1 = force_reg (mode, op1);
++
++ if (push_operand (op0, mode)
++ && ! general_no_elim_operand (op1, mode))
++ op1 = copy_to_mode_reg (mode, op1);
+
+ /* Force large constants in 64bit compilation into register
+ to get them CSEed. */
+ if (TARGET_64BIT && mode == DImode
+- && immediate_operand (operands[1], mode)
+- && !x86_64_zero_extended_value (operands[1])
+- && !register_operand (operands[0], mode)
++ && immediate_operand (op1, mode)
++ && !x86_64_zero_extended_value (op1)
++ && !register_operand (op0, mode)
+ && optimize && !reload_completed && !reload_in_progress)
+- operands[1] = copy_to_mode_reg (mode, operands[1]);
++ op1 = copy_to_mode_reg (mode, op1);
+
+ if (FLOAT_MODE_P (mode))
+ {
+@@ -6817,13 +7422,13 @@ ix86_expand_move (mode, operands)
+
+ if (strict)
+ ;
+- else if (GET_CODE (operands[1]) == CONST_DOUBLE
+- && register_operand (operands[0], mode))
+- operands[1] = validize_mem (force_const_mem (mode, operands[1]));
++ else if (GET_CODE (op1) == CONST_DOUBLE
++ && register_operand (op0, mode))
++ op1 = validize_mem (force_const_mem (mode, op1));
+ }
+ }
+
+- insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]);
++ insn = gen_rtx_SET (VOIDmode, op0, op1);
+
+ emit_insn (insn);
+ }
+@@ -8588,13 +9193,14 @@ ix86_split_to_parts (operand, parts, mod
+ if (size < 2 || size > 3)
+ abort ();
+
+- /* Optimize constant pool reference to immediates. This is used by fp moves,
+- that force all constants to memory to allow combining. */
+-
+- if (GET_CODE (operand) == MEM
+- && GET_CODE (XEXP (operand, 0)) == SYMBOL_REF
+- && CONSTANT_POOL_ADDRESS_P (XEXP (operand, 0)))
+- operand = get_pool_constant (XEXP (operand, 0));
++ /* Optimize constant pool reference to immediates. This is used by fp
++ moves, that force all constants to memory to allow combining. */
++ if (GET_CODE (operand) == MEM && RTX_UNCHANGING_P (operand))
++ {
++ rtx tmp = maybe_get_pool_constant (operand);
++ if (tmp)
++ operand = tmp;
++ }
+
+ if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand))
+ {
+@@ -9790,6 +10396,55 @@ ix86_expand_strlensi_unroll_1 (out, alig
+
+ emit_label (end_0_label);
+ }
++
++void
++ix86_expand_call (retval, fnaddr, callarg1, callarg2, pop)
++ rtx retval, fnaddr, callarg1, callarg2, pop;
++{
++ rtx use = NULL, call;
++
++ if (pop == const0_rtx)
++ pop = NULL;
++ if (TARGET_64BIT && pop)
++ abort ();
++
++ /* Static functions and indirect calls don't need the pic register. */
++ if (! TARGET_64BIT && flag_pic
++ && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
++ && ! SYMBOL_REF_FLAG (XEXP (fnaddr, 0)))
++ {
++ current_function_uses_pic_offset_table = 1;
++ use_reg (&use, pic_offset_table_rtx);
++ }
++
++ if (TARGET_64BIT && INTVAL (callarg2) >= 0)
++ {
++ rtx al = gen_rtx_REG (QImode, 0);
++ emit_move_insn (al, callarg2);
++ use_reg (&use, al);
++ }
++
++ if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
++ {
++ fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
++ fnaddr = gen_rtx_MEM (QImode, fnaddr);
++ }
++
++ call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
++ if (retval)
++ call = gen_rtx_SET (VOIDmode, retval, call);
++ if (pop)
++ {
++ pop = gen_rtx_PLUS (Pmode, stack_pointer_rtx, pop);
++ pop = gen_rtx_SET (VOIDmode, stack_pointer_rtx, pop);
++ call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, pop));
++ }
++
++ call = emit_call_insn (call);
++ if (use)
++ CALL_INSN_FUNCTION_USAGE (call) = use;
++}
++
+ \f
+ /* Clear stack slot assignments remembered from previous functions.
+ This is called from INIT_EXPANDERS once before RTL is emitted for each
+@@ -9849,6 +10504,24 @@ assign_386_stack_local (mode, n)
+
+ return ix86_stack_locals[(int) mode][n];
+ }
++
++/* Construct the SYMBOL_REF for the tls_get_addr function. */
++
++rtx
++ix86_tls_get_addr ()
++{
++ static rtx symbol;
++
++ if (!symbol)
++ {
++ symbol = gen_rtx_SYMBOL_REF (Pmode, (TARGET_GNU_TLS
++ ? "___tls_get_addr"
++ : "__tls_get_addr"));
++ ggc_add_rtx_root (&symbol, 1);
++ }
++
++ return symbol;
++}
+ \f
+ /* Calculate the length of the memory address in the instruction
+ encoding. Does not include the one-byte modrm, opcode, or prefix. */
+--- gcc/config/i386/i386-protos.h.jj Wed Jun 19 15:18:02 2002
++++ gcc/config/i386/i386-protos.h Wed Jun 19 19:33:52 2002
+@@ -28,7 +28,6 @@ extern int ix86_frame_pointer_required P
+ extern void ix86_setup_frame_addresses PARAMS ((void));
+
+ extern void ix86_asm_file_end PARAMS ((FILE *));
+-extern void load_pic_register PARAMS ((void));
+ extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
+ extern void ix86_expand_prologue PARAMS ((void));
+ extern void ix86_expand_epilogue PARAMS ((int));
+@@ -36,6 +35,9 @@ extern void ix86_expand_epilogue PARAMS
+ extern void ix86_output_addr_vec_elt PARAMS ((FILE *, int));
+ extern void ix86_output_addr_diff_elt PARAMS ((FILE *, int, int));
+
++extern void ix86_encode_section_info PARAMS ((tree));
++extern const char *ix86_strip_name_encoding PARAMS ((const char *));
++
+ #ifdef RTX_CODE
+ extern int ix86_aligned_p PARAMS ((rtx));
+
+@@ -51,6 +53,11 @@ extern int x86_64_immediate_operand PARA
+ extern int x86_64_zext_immediate_operand PARAMS ((rtx, enum machine_mode));
+ extern int const_int_1_operand PARAMS ((rtx, enum machine_mode));
+ extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int tls_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int global_dynamic_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int local_dynamic_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int initial_exec_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int local_exec_symbolic_operand PARAMS ((rtx, enum machine_mode));
+ extern int pic_symbolic_operand PARAMS ((rtx, enum machine_mode));
+ extern int call_insn_operand PARAMS ((rtx, enum machine_mode));
+ extern int constant_call_address_operand PARAMS ((rtx, enum machine_mode));
+@@ -84,6 +91,9 @@ extern int ix86_expand_movstr PARAMS ((r
+ extern int ix86_expand_clrstr PARAMS ((rtx, rtx, rtx));
+ extern int ix86_expand_strlen PARAMS ((rtx, rtx, rtx, rtx));
+
++extern bool legitimate_constant_p PARAMS ((rtx));
++extern bool constant_address_p PARAMS ((rtx));
++extern bool legitimate_pic_operand_p PARAMS ((rtx));
+ extern int legitimate_pic_address_disp_p PARAMS ((rtx));
+ extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
+ extern rtx legitimize_pic_address PARAMS ((rtx, rtx));
+@@ -92,10 +102,12 @@ extern rtx legitimize_address PARAMS ((r
+ extern void print_reg PARAMS ((rtx, int, FILE*));
+ extern void print_operand PARAMS ((FILE*, rtx, int));
+ extern void print_operand_address PARAMS ((FILE*, rtx));
++extern bool output_addr_const_extra PARAMS ((FILE*, rtx));
+
+ extern void split_di PARAMS ((rtx[], int, rtx[], rtx[]));
+ extern void split_ti PARAMS ((rtx[], int, rtx[], rtx[]));
+
++extern const char *output_set_got PARAMS ((rtx));
+ extern const char *output_387_binary_op PARAMS ((rtx, rtx*));
+ extern const char *output_fix_trunc PARAMS ((rtx, rtx*));
+ extern const char *output_fp_compare PARAMS ((rtx, rtx*, int, int));
+@@ -121,6 +133,7 @@ extern void ix86_expand_branch PARAMS ((
+ extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
+ extern int ix86_expand_int_movcc PARAMS ((rtx[]));
+ extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
++extern void ix86_expand_call PARAMS ((rtx, rtx, rtx, rtx, rtx));
+ extern void x86_initialize_trampoline PARAMS ((rtx, rtx, rtx));
+ extern rtx ix86_zero_extend_to_Pmode PARAMS ((rtx));
+ extern void ix86_split_long_move PARAMS ((rtx[]));
+@@ -181,6 +194,8 @@ extern rtx ix86_expand_builtin PARAMS ((
+
+ #endif
+
++extern rtx ix86_tls_get_addr PARAMS ((void));
++
+ #ifdef TREE_CODE
+ extern int ix86_return_pops_args PARAMS ((tree, tree, int));
+ extern tree ix86_build_va_list PARAMS ((void));
+--- gcc/config/i386/i386.h.jj Wed Jun 19 19:33:51 2002
++++ gcc/config/i386/i386.h Wed Jun 19 20:20:56 2002
+@@ -282,6 +282,9 @@ extern int x86_prefetch_sse;
+
+ #define TARGET_RED_ZONE (!(target_flags & MASK_NO_RED_ZONE))
+
++#define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
++#define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN)
++
+ /* WARNING: Do not mark empty strings for translation, as calling
+ gettext on an empty string does NOT return an empty
+ string. */
+@@ -451,6 +454,8 @@ extern int ix86_arch;
+ "" /* Undocumented. */ }, \
+ { "asm=", &ix86_asm_string, \
+ N_("Use given assembler dialect") }, \
++ { "tls-dialect=", &ix86_tls_dialect_string, \
++ N_("Use given thread-local storage dialect") }, \
+ SUBTARGET_OPTIONS \
+ }
+
+@@ -1934,15 +1939,12 @@ do { \
+
+ #define MAX_REGS_PER_ADDRESS 2
+
+-#define CONSTANT_ADDRESS_P(X) \
+- (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+- || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
+- || GET_CODE (X) == CONST_DOUBLE)
++#define CONSTANT_ADDRESS_P(X) constant_address_p (X)
+
+ /* Nonzero if the constant value X is a legitimate general operand.
+ It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+
+-#define LEGITIMATE_CONSTANT_P(X) 1
++#define LEGITIMATE_CONSTANT_P(X) legitimate_constant_p (X)
+
+ #ifdef REG_OK_STRICT
+ #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+@@ -2005,9 +2007,7 @@ do { \
+ when generating PIC code. It is given that flag_pic is on and
+ that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
+
+-#define LEGITIMATE_PIC_OPERAND_P(X) \
+- (! SYMBOLIC_CONST (X) \
+- || legitimate_pic_address_disp_p (X))
++#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X)
+
+ #define SYMBOLIC_CONST(X) \
+ (GET_CODE (X) == SYMBOL_REF \
+@@ -2251,33 +2251,23 @@ enum ix86_builtins
+ On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol
+ so that we may access it directly in the GOT. */
+
+-#define ENCODE_SECTION_INFO(DECL) \
+-do { \
+- if (flag_pic) \
+- { \
+- rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
+- ? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \
+- \
+- if (GET_CODE (rtl) == MEM) \
+- { \
+- if (TARGET_DEBUG_ADDR \
+- && TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd') \
+- { \
+- fprintf (stderr, "Encode %s, public = %d\n", \
+- IDENTIFIER_POINTER (DECL_NAME (DECL)), \
+- TREE_PUBLIC (DECL)); \
+- } \
+- \
+- SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
+- = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
+- || ! TREE_PUBLIC (DECL) \
+- || MODULE_LOCAL_P (DECL)); \
+- } \
+- } \
+-} while (0)
+-
++#define ENCODE_SECTION_INFO(DECL) ix86_encode_section_info(DECL)
+ #define REDO_SECTION_INFO_P(DECL) 1
+
++#define STRIP_NAME_ENCODING(VAR,STR) ((VAR) = ix86_strip_name_encoding (STR))
++
++#define ASM_OUTPUT_LABELREF(FILE,NAME) \
++ do { \
++ const char *xname = (NAME); \
++ if (xname[0] == '%') \
++ xname += 2; \
++ if (xname[0] == '*') \
++ xname += 1; \
++ else \
++ fputs (user_label_prefix, FILE); \
++ fputs (xname, FILE); \
++ } while (0)
++
+ /* The `FINALIZE_PIC' macro serves as a hook to emit these special
+ codes once the function is being compiled into assembly code, but
+ not before. (It is not done before, because in the case of
+@@ -2923,7 +2913,7 @@ extern int const svr4_dbx_register_map[F
+ print_operand function. */
+
+ #define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+- ((CODE) == '*' || (CODE) == '+')
++ ((CODE) == '*' || (CODE) == '+' || (CODE) == '&')
+
+ /* Print the name of a register based on its machine mode and number.
+ If CODE is 'w', pretend the mode is HImode.
+@@ -2942,6 +2932,12 @@ extern int const svr4_dbx_register_map[F
+ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
+ print_operand_address ((FILE), (ADDR))
+
++#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \
++do { \
++ if (! output_addr_const_extra (FILE, (X))) \
++ goto FAIL; \
++} while (0);
++
+ /* Print the name of a register for based on its machine mode and number.
+ This macro is used to print debugging output.
+ This macro is different from PRINT_REG in that it may be used in
+@@ -3071,7 +3067,12 @@ extern int const svr4_dbx_register_map[F
+ {"memory_displacement_operand", {MEM}}, \
+ {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
+ LABEL_REF, SUBREG, REG, MEM, AND}}, \
+- {"long_memory_operand", {MEM}},
++ {"long_memory_operand", {MEM}}, \
++ {"tls_symbolic_operand", {SYMBOL_REF}}, \
++ {"global_dynamic_symbolic_operand", {SYMBOL_REF}}, \
++ {"local_dynamic_symbolic_operand", {SYMBOL_REF}}, \
++ {"initial_exec_symbolic_operand", {SYMBOL_REF}}, \
++ {"local_exec_symbolic_operand", {SYMBOL_REF}},
+
+ /* A list of predicates that do special things with modes, and so
+ should not elicit warnings for VOIDmode match_operand. */
+@@ -3112,6 +3113,16 @@ enum asm_dialect {
+ };
+ extern const char *ix86_asm_string;
+ extern enum asm_dialect ix86_asm_dialect;
++
++enum tls_dialect
++{
++ TLS_DIALECT_GNU,
++ TLS_DIALECT_SUN
++};
++
++extern enum tls_dialect ix86_tls_dialect;
++extern const char *ix86_tls_dialect_string;
++
+ /* Value of -mcmodel specified by user. */
+ extern const char *ix86_cmodel_string;
+ extern enum cmodel ix86_cmodel;
+--- gcc/config/i386/i386.md.jj Tue Jun 4 20:28:36 2002
++++ gcc/config/i386/i386.md Wed Jun 19 19:33:52 2002
+@@ -49,55 +49,59 @@
+ ;; 'k' Likewise, print the SImode name of the register.
+ ;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
+ ;; 'y' Print "st(0)" instead of "st" as a register.
+-;;
++
+ ;; UNSPEC usage:
+-;; 0 This is a `scas' operation. The mode of the UNSPEC is always SImode.
+-;; operand 0 is the memory address to scan.
+-;; operand 1 is a register containing the value to scan for. The mode
+-;; of the scas opcode will be the same as the mode of this operand.
+-;; operand 2 is the known alignment of operand 0.
+-;; 1 This is a `sin' operation. The mode of the UNSPEC is MODE_FLOAT.
+-;; operand 0 is the argument for `sin'.
+-;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT.
+-;; operand 0 is the argument for `cos'.
+-;; 3 This is part of a `stack probe' operation. The mode of the UNSPEC is
+-;; always SImode. operand 0 is the size of the stack allocation.
+-;; 4 This is the source of a fake SET of the frame pointer which is used to
+-;; prevent insns referencing it being scheduled across the initial
+-;; decrement of the stack pointer.
+-;; 5 This is a `bsf' operation.
+-;; 6 This is the @GOT offset of a PIC address.
+-;; 7 This is the @GOTOFF offset of a PIC address.
+-;; 8 This is a reference to a symbol's @PLT address.
+-;; 9 This is an `fnstsw' operation.
+-;; 10 This is a `sahf' operation.
+-;; 11 This is a `fstcw' operation
+-;; 12 This is behaviour of add when setting carry flag.
+-;; 13 This is a `eh_return' placeholder.
+-
+-;; For SSE/MMX support:
+-;; 30 This is `fix', guaranteed to be truncating.
+-;; 31 This is a `emms' operation.
+-;; 32 This is a `maskmov' operation.
+-;; 33 This is a `movmsk' operation.
+-;; 34 This is a `non-temporal' move.
+-;; 36 This is used to distinguish COMISS from UCOMISS.
+-;; 37 This is a `ldmxcsr' operation.
+-;; 38 This is a forced `movaps' instruction (rather than whatever movti does)
+-;; 39 This is a forced `movups' instruction (rather than whatever movti does)
+-;; 40 This is a `stmxcsr' operation.
+-;; 41 This is a `shuffle' operation.
+-;; 42 This is a `rcp' operation.
+-;; 43 This is a `rsqsrt' operation.
+-;; 44 This is a `sfence' operation.
+-;; 45 This is a noop to prevent excessive combiner cleverness.
+-;; 46 This is a `femms' operation.
+-;; 49 This is a 'pavgusb' operation.
+-;; 50 This is a `pfrcp' operation.
+-;; 51 This is a `pfrcpit1' operation.
+-;; 52 This is a `pfrcpit2' operation.
+-;; 53 This is a `pfrsqrt' operation.
+-;; 54 This is a `pfrsqrit1' operation.
++;; ??? Note that the 3.1 branch, unlike mainline, has not had all
++;; of the uses of UNSPEC replaced with their symbolic constants.
++;; Thus you cannot change these arbitrarily without pain.
++
++(define_constants
++ [(UNSPEC_SCAS 0)
++ (UNSPEC_SIN 1)
++ (UNSPEC_COS 2)
++ (UNSPEC_STACK_PROBE 3)
++ (UNSPEC_STACK_ALLOC 4)
++ (UNSPEC_BSF 5)
++ (UNSPEC_GOT 6)
++ (UNSPEC_GOTOFF 7)
++ (UNSPEC_PLT 8)
++ (UNSPEC_FNSTSW 9)
++ (UNSPEC_SAHF 10)
++ (UNSPEC_FSTCW 11)
++ (UNSPEC_FLDCW 12)
++ (UNSPEC_ADD_CARRY 12)
++ (UNSPEC_EH_RETURN 13)
++ (UNSPEC_GOTPCREL 15)
++ (UNSPEC_SET_GOT 16)
++
++ ; For TLS support:
++ (UNSPEC_GOTTPOFF 20)
++ (UNSPEC_TPOFF 21)
++ (UNSPEC_NTPOFF 22)
++ (UNSPEC_DTPOFF 23)
++ (UNSPEC_TP 24)
++ (UNSPEC_TLS_GD 25)
++ (UNSPEC_TLS_LD_BASE 26)
++
++ ; For SSE/MMX support:
++ (UNSPEC_FIX 30)
++ (UNSPEC_MASKMOV 32)
++ (UNSPEC_MOVMSK 33)
++ (UNSPEC_MOVNT 34)
++ (UNSPEC_MOVA 38)
++ (UNSPEC_MOVU 39)
++ (UNSPEC_SHUFFLE 41)
++ (UNSPEC_RCP 42)
++ (UNSPEC_RSQRT 43)
++ (UNSPEC_SFENCE 44)
++ (UNSPEC_NOP 45) ; prevents combiner cleverness
++ (UNSPEC_PAVGUSB 49)
++ (UNSPEC_PFRCP 50)
++ (UNSPEC_PFRCPIT1 51)
++ (UNSPEC_PFRCPIT2 52)
++ (UNSPEC_PFRSQRT 53)
++ (UNSPEC_PFRSQIT1 54)
++ ])
+
+ ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
+ ;; from i386.c.
+@@ -1759,7 +1763,7 @@
+ return "lea{l}\t{%1, %0|%0, %1}";
+
+ default:
+- if (flag_pic && SYMBOLIC_CONST (operands[1]))
++ if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1]))
+ abort();
+ return "mov{l}\t{%1, %0|%0, %1}";
+ }
+@@ -2525,7 +2529,7 @@
+ case TYPE_LEA:
+ return "lea{q}\t{%a1, %0|%0, %a1}";
+ default:
+- if (flag_pic && SYMBOLIC_CONST (operands[1]))
++ if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1]))
+ abort ();
+ if (get_attr_mode (insn) == MODE_SI)
+ return "mov{l}\t{%k1, %k0|%k0, %k1}";
+@@ -13474,21 +13478,8 @@
+ (match_operand:SI 3 "" "")))])]
+ "!TARGET_64BIT"
+ {
+- if (operands[3] == const0_rtx)
+- {
+- emit_insn (gen_call (operands[0], operands[1], constm1_rtx));
+- DONE;
+- }
+- /* Static functions and indirect calls don't need
+- current_function_uses_pic_offset_table. */
+- if (flag_pic
+- && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+- && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+- current_function_uses_pic_offset_table = 1;
+- if (! call_insn_operand (XEXP (operands[0], 0), Pmode))
+- XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+- if (TARGET_64BIT)
+- abort();
++ ix86_expand_call (NULL, operands[0], operands[1], operands[2], operands[3]);
++ DONE;
+ })
+
+ (define_insn "*call_pop_0"
+@@ -13530,37 +13521,12 @@
+ [(call (match_operand:QI 0 "" "")
+ (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))]
+- ;; Operand 1 not used on the i386.
+ ""
+ {
+- rtx insn;
+- /* Static functions and indirect calls don't need
+- current_function_uses_pic_offset_table. */
+- if (flag_pic
+- && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+- && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+- current_function_uses_pic_offset_table = 1;
+-
+- if (! call_insn_operand (XEXP (operands[0], 0), Pmode))
+- XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+- if (TARGET_64BIT && INTVAL (operands[2]) >= 0)
+- {
+- rtx reg = gen_rtx_REG (QImode, 0);
+- emit_move_insn (reg, operands[2]);
+- insn = emit_call_insn (gen_call_exp (operands[0], operands[1]));
+- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
+- DONE;
+- }
+- insn = emit_call_insn (gen_call_exp (operands[0], operands[1]));
+- DONE;
++ ix86_expand_call (NULL, operands[0], operands[1], operands[2], NULL);
++ DONE;
+ })
+
+-(define_expand "call_exp"
+- [(call (match_operand:QI 0 "" "")
+- (match_operand 1 "" ""))]
+- ""
+- "")
+-
+ (define_insn "*call_0"
+ [(call (mem:QI (match_operand 0 "constant_call_address_operand" ""))
+ (match_operand 1 "" ""))]
+@@ -13612,7 +13578,6 @@
+ [(set_attr "type" "call")])
+
+ ;; Call subroutine, returning value in operand 0
+-;; (which must be a hard register).
+
+ (define_expand "call_value_pop"
+ [(parallel [(set (match_operand 0 "" "")
+@@ -13623,20 +13588,9 @@
+ (match_operand:SI 4 "" "")))])]
+ "!TARGET_64BIT"
+ {
+- if (operands[4] == const0_rtx)
+- {
+- emit_insn (gen_call_value (operands[0], operands[1], operands[2],
+- constm1_rtx));
+- DONE;
+- }
+- /* Static functions and indirect calls don't need
+- current_function_uses_pic_offset_table. */
+- if (flag_pic
+- && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+- && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+- current_function_uses_pic_offset_table = 1;
+- if (! call_insn_operand (XEXP (operands[1], 0), Pmode))
+- XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
++ ix86_expand_call (operands[0], operands[1], operands[2],
++ operands[3], operands[4]);
++ DONE;
+ })
+
+ (define_expand "call_value"
+@@ -13647,36 +13601,10 @@
+ ;; Operand 2 not used on the i386.
+ ""
+ {
+- rtx insn;
+- /* Static functions and indirect calls don't need
+- current_function_uses_pic_offset_table. */
+- if (flag_pic
+- && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+- && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+- current_function_uses_pic_offset_table = 1;
+- if (! call_insn_operand (XEXP (operands[1], 0), Pmode))
+- XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+- if (TARGET_64BIT && INTVAL (operands[3]) >= 0)
+- {
+- rtx reg = gen_rtx_REG (QImode, 0);
+- emit_move_insn (reg, operands[3]);
+- insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1],
+- operands[2]));
+- use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
+- DONE;
+- }
+- insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1],
+- operands[2]));
++ ix86_expand_call (operands[0], operands[1], operands[2], operands[3], NULL);
+ DONE;
+ })
+
+-(define_expand "call_value_exp"
+- [(set (match_operand 0 "" "")
+- (call (match_operand:QI 1 "" "")
+- (match_operand:SI 2 "" "")))]
+- ""
+- "")
+-
+ ;; Call subroutine returning any type.
+
+ (define_expand "untyped_call"
+@@ -13693,12 +13621,10 @@
+ simply pretend the untyped call returns a complex long double
+ value. */
+
+- emit_call_insn (TARGET_FLOAT_RETURNS_IN_80387
+- ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG),
+- operands[0], const0_rtx,
+- GEN_INT (SSE_REGPARM_MAX - 1))
+- : gen_call (operands[0], const0_rtx,
+- GEN_INT (SSE_REGPARM_MAX - 1)));
++ ix86_expand_call ((TARGET_FLOAT_RETURNS_IN_80387
++ ? gen_rtx_REG (XCmode, FIRST_FLOAT_REG) : NULL),
++ operands[0], const0_rtx, GEN_INT (SSE_REGPARM_MAX - 1),
++ NULL);
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+@@ -13781,45 +13707,39 @@
+ ""
+ "ix86_expand_prologue (); DONE;")
+
+-(define_insn "prologue_set_got"
++(define_expand "set_got"
++ [(parallel [(set (match_operand:SI 0 "register_operand" "")
++ (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++ (clobber (reg:CC 17))])]
++ "!TARGET_64BIT"
++ "")
++
++(define_insn "*set_got_nopic"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+- (unspec_volatile:SI
+- [(plus:SI (match_dup 0)
+- (plus:SI (match_operand:SI 1 "symbolic_operand" "")
+- (minus:SI (pc) (match_operand 2 "" ""))))] 1))
++ (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
+ (clobber (reg:CC 17))]
+- "!TARGET_64BIT"
+-{
+- if (GET_CODE (operands[2]) == LABEL_REF)
+- operands[2] = XEXP (operands[2], 0);
+- if (TARGET_DEEP_BRANCH_PREDICTION)
+- return "add{l}\t{%1, %0|%0, %1}";
+- else
+- return "add{l}\t{%1+[.-%X2], %0|%0, %a1+(.-%X2)}";
+-}
+- [(set_attr "type" "alu")
+- ; Since this insn may have two constant operands, we must set the
+- ; length manually.
+- (set_attr "length_immediate" "4")
+- (set_attr "mode" "SI")])
++ "!TARGET_64BIT && !flag_pic"
++ { return output_set_got (operands[0]); }
++ [(set_attr "type" "multi")
++ (set_attr "length" "11")])
++
++(define_insn "*set_got_deep"
++ [(set (match_operand:SI 0 "register_operand" "=b")
++ (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++ (clobber (reg:CC 17))]
++ "!TARGET_64BIT && TARGET_DEEP_BRANCH_PREDICTION"
++ { return output_set_got (operands[0]); }
++ [(set_attr "type" "multi")
++ (set_attr "length" "11")])
+
+-(define_insn "prologue_get_pc"
++(define_insn "*set_got_nodeep"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+- (unspec_volatile:SI [(plus:SI (pc) (match_operand 1 "" ""))] 2))]
++ (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++ (clobber (reg:CC 17))]
+ "!TARGET_64BIT"
+-{
+- if (GET_CODE (operands[1]) == LABEL_REF)
+- operands[1] = XEXP (operands[1], 0);
+- output_asm_insn ("call\t%X1", operands);
+- if (! TARGET_DEEP_BRANCH_PREDICTION)
+- {
+- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+- CODE_LABEL_NUMBER (operands[1]));
+- return "pop{l}\t%0";
+- }
+- RET;
+-}
+- [(set_attr "type" "multi")])
++ { return output_set_got (operands[0]); }
++ [(set_attr "type" "multi")
++ (set_attr "length" "12")])
+
+ (define_expand "epilogue"
+ [(const_int 1)]
+@@ -13996,6 +13916,127 @@
+ ;; ffshi2 is not useful -- 4 word prefix ops are needed, which is larger
+ ;; and slower than the two-byte movzx insn needed to do the work in SImode.
+ \f
++;; Thread-local storage patterns for ELF.
++;;
++;; Note that these code sequences must appear exactly as shown
++;; in order to allow linker relaxation.
++
++(define_insn "*tls_global_dynamic_gnu"
++ [(set (match_operand:SI 0 "register_operand" "=a")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++ (match_operand:SI 2 "tls_symbolic_operand" "")
++ (match_operand:SI 3 "call_insn_operand" "")]
++ UNSPEC_TLS_GD))
++ (clobber (match_scratch:SI 4 "=d"))
++ (clobber (match_scratch:SI 5 "=c"))
++ (clobber (reg:CC 17))]
++ "TARGET_GNU_TLS"
++ "lea{l}\t{%a2@TLSGD(,%1,1), %0|%0, %a2@TLSGD[%1*1]}\;call\t%P3"
++ [(set_attr "type" "multi")
++ (set_attr "length" "12")])
++
++(define_insn "*tls_global_dynamic_sun"
++ [(set (match_operand:SI 0 "register_operand" "=a")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++ (match_operand:SI 2 "tls_symbolic_operand" "")
++ (match_operand:SI 3 "call_insn_operand" "")]
++ UNSPEC_TLS_GD))
++ (clobber (match_scratch:SI 4 "=d"))
++ (clobber (match_scratch:SI 5 "=c"))
++ (clobber (reg:CC 17))]
++ "TARGET_SUN_TLS"
++ "lea{l}\t{%a2@DTLNDX(%1), %4|%4, %a2@DTLNDX[%1]}
++ push{l}\t%4\;call\t%a2@TLSPLT\;pop{l}\t%4\;nop"
++ [(set_attr "type" "multi")
++ (set_attr "length" "14")])
++
++(define_expand "tls_global_dynamic"
++ [(parallel [(set (match_operand:SI 0 "register_operand" "")
++ (unspec:SI
++ [(match_dup 2)
++ (match_operand:SI 1 "tls_symbolic_operand" "")
++ (match_dup 3)]
++ UNSPEC_TLS_GD))
++ (clobber (match_scratch:SI 4 ""))
++ (clobber (match_scratch:SI 5 ""))
++ (clobber (reg:CC 17))])]
++ ""
++{
++ if (!flag_pic)
++ abort ();
++ current_function_uses_pic_offset_table = 1;
++ operands[2] = pic_offset_table_rtx;
++ operands[3] = ix86_tls_get_addr ();
++})
++
++(define_insn "*tls_local_dynamic_base_gnu"
++ [(set (match_operand:SI 0 "register_operand" "=a")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++ (match_operand:SI 2 "call_insn_operand" "")]
++ UNSPEC_TLS_LD_BASE))
++ (clobber (match_scratch:SI 3 "=d"))
++ (clobber (match_scratch:SI 4 "=c"))
++ (clobber (reg:CC 17))]
++ "TARGET_GNU_TLS"
++ "lea{l}\t{%&@TLSLDM(%1), %0|%0, %&@TLSLDM[%1]}\;call\t%P2"
++ [(set_attr "type" "multi")
++ (set_attr "length" "11")])
++
++(define_insn "*tls_local_dynamic_base_sun"
++ [(set (match_operand:SI 0 "register_operand" "=a")
++ (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++ (match_operand:SI 2 "call_insn_operand" "")]
++ UNSPEC_TLS_LD_BASE))
++ (clobber (match_scratch:SI 3 "=d"))
++ (clobber (match_scratch:SI 4 "=c"))
++ (clobber (reg:CC 17))]
++ "TARGET_SUN_TLS"
++ "lea{l}\t{%&@TMDNX(%1), %3|%3, %&@TMDNX[%1]}
++ push{l}\t%3\;call\t%&@TLSPLT\;pop{l}\t%3"
++ [(set_attr "type" "multi")
++ (set_attr "length" "13")])
++
++(define_expand "tls_local_dynamic_base"
++ [(parallel [(set (match_operand:SI 0 "register_operand" "")
++ (unspec:SI [(match_dup 1) (match_dup 2)]
++ UNSPEC_TLS_LD_BASE))
++ (clobber (match_scratch:SI 3 ""))
++ (clobber (match_scratch:SI 4 ""))
++ (clobber (reg:CC 17))])]
++ ""
++{
++ if (!flag_pic)
++ abort ();
++ current_function_uses_pic_offset_table = 1;
++ operands[1] = pic_offset_table_rtx;
++ operands[2] = ix86_tls_get_addr ();
++})
++
++;; Local dynamic of a single variable is a lose. Show combine how
++;; to convert that back to global dynamic.
++
++(define_insn_and_split "*tls_local_dynamic_once"
++ [(set (match_operand:SI 0 "register_operand" "=a")
++ (plus:SI (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++ (match_operand:SI 2 "call_insn_operand" "")]
++ UNSPEC_TLS_LD_BASE)
++ (const:SI (unspec:SI
++ [(match_operand:SI 3 "tls_symbolic_operand" "")]
++ UNSPEC_DTPOFF))))
++ (clobber (match_scratch:SI 4 "=d"))
++ (clobber (match_scratch:SI 5 "=c"))
++ (clobber (reg:CC 17))]
++ ""
++ "#"
++ ""
++ [(parallel [(set (match_dup 0)
++ (unspec:SI [(match_dup 1) (match_dup 3) (match_dup 2)]
++ UNSPEC_TLS_GD))
++ (clobber (match_dup 4))
++ (clobber (match_dup 5))
++ (clobber (reg:CC 17))])]
++ "")
++\f
+ ;; These patterns match the binary 387 instructions for addM3, subM3,
+ ;; mulM3 and divM3. There are three patterns for each of DFmode and
+ ;; SFmode. The first is the normal insn, the second the same insn but
+@@ -16835,7 +16876,7 @@
+ [(label_ref (match_operand 0 "" ""))]
+ "!TARGET_64BIT && flag_pic"
+ {
+- load_pic_register ();
++ emit_insn (gen_set_got (pic_offset_table_rtx));
+ DONE;
+ })
+ \f
+--- gcc/config/ia64/ia64-protos.h.jj Tue Apr 23 20:28:20 2002
++++ gcc/config/ia64/ia64-protos.h Wed Jun 19 19:33:52 2002
+@@ -31,6 +31,7 @@ extern int call_operand PARAMS((rtx, enu
+ extern int sdata_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int got_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int symbolic_operand PARAMS((rtx, enum machine_mode));
++extern int tls_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int function_operand PARAMS((rtx, enum machine_mode));
+ extern int setjmp_operand PARAMS((rtx, enum machine_mode));
+ extern int move_operand PARAMS((rtx, enum machine_mode));
+@@ -67,6 +68,7 @@ extern int general_tfmode_operand PARAMS
+ extern int destination_tfmode_operand PARAMS((rtx, enum machine_mode));
+ extern int tfreg_or_fp01_operand PARAMS((rtx, enum machine_mode));
+
++extern rtx ia64_expand_move PARAMS ((rtx, rtx));
+ extern int ia64_move_ok PARAMS((rtx, rtx));
+ extern int ia64_depz_field_mask PARAMS((rtx, rtx));
+ extern rtx ia64_gp_save_reg PARAMS((int));
+--- gcc/config/ia64/ia64.c.jj Wed Jun 19 22:36:54 2002
++++ gcc/config/ia64/ia64.c Wed Jun 19 22:46:07 2002
+@@ -95,6 +95,13 @@ static const char * const ia64_output_re
+ /* String used with the -mfixed-range= option. */
+ const char *ia64_fixed_range_string;
+
++/* Determines whether we use adds, addl, or movl to generate our
++ TLS immediate offsets. */
++int ia64_tls_size = 22;
++
++/* String used with the -mtls-size= option. */
++const char *ia64_tls_size_string;
++
+ /* Determines whether we run our final scheduling pass or not. We always
+ avoid the normal second scheduling pass. */
+ static int ia64_flag_schedule_insns2;
+@@ -104,6 +111,8 @@ static int ia64_flag_schedule_insns2;
+
+ unsigned int ia64_section_threshold;
+ \f
++static rtx gen_tls_get_addr PARAMS ((void));
++static rtx gen_thread_pointer PARAMS ((void));
+ static int find_gr_spill PARAMS ((int));
+ static int next_scratch_gr_reg PARAMS ((void));
+ static void mark_reg_gr_used_mask PARAMS ((rtx, void *));
+@@ -214,6 +223,11 @@ static const struct attribute_spec ia64_
+ #undef TARGET_SCHED_CYCLE_DISPLAY
+ #define TARGET_SCHED_CYCLE_DISPLAY ia64_cycle_display
+
++#ifdef HAVE_AS_TLS
++#undef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS true
++#endif
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
+ \f
+ /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */
+@@ -250,7 +264,10 @@ sdata_symbolic_operand (op, mode)
+ if (CONSTANT_POOL_ADDRESS_P (op))
+ return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
+ else
+- return XSTR (op, 0)[0] == SDATA_NAME_FLAG_CHAR;
++ {
++ const char *str = XSTR (op, 0);
++ return (str[0] == ENCODE_SECTION_INFO_CHAR && str[1] == 's');
++ }
+
+ default:
+ break;
+@@ -324,6 +341,35 @@ symbolic_operand (op, mode)
+ return 0;
+ }
+
++/* Return tls_model if OP refers to a TLS symbol. */
++
++int
++tls_symbolic_operand (op, mode)
++ rtx op;
++ enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++ const char *str;
++
++ if (GET_CODE (op) != SYMBOL_REF)
++ return 0;
++ str = XSTR (op, 0);
++ if (str[0] != ENCODE_SECTION_INFO_CHAR)
++ return 0;
++ switch (str[1])
++ {
++ case 'G':
++ return TLS_MODEL_GLOBAL_DYNAMIC;
++ case 'L':
++ return TLS_MODEL_LOCAL_DYNAMIC;
++ case 'i':
++ return TLS_MODEL_INITIAL_EXEC;
++ case 'l':
++ return TLS_MODEL_LOCAL_EXEC;
++ }
++ return 0;
++}
++
++
+ /* Return 1 if OP refers to a function. */
+
+ int
+@@ -922,6 +968,9 @@ ia64_expand_load_address (dest, src, scr
+ else
+ temp = dest;
+
++ if (tls_symbolic_operand (src, Pmode))
++ abort ();
++
+ if (TARGET_AUTO_PIC)
+ emit_insn (gen_load_gprel64 (temp, src));
+ else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src))
+@@ -964,6 +1013,185 @@ ia64_expand_load_address (dest, src, scr
+ emit_move_insn (dest, temp);
+ }
+
++static rtx
++gen_tls_get_addr ()
++{
++ static rtx tga;
++ if (!tga)
++ {
++ tga = init_one_libfunc ("__tls_get_addr");
++ ggc_add_rtx_root (&tga, 1);
++ }
++ return tga;
++}
++
++static rtx
++gen_thread_pointer ()
++{
++ static rtx tp;
++ if (!tp)
++ {
++ tp = gen_rtx_REG (Pmode, 13);
++ RTX_UNCHANGING_P (tp) = 1;
++ ggc_add_rtx_root (&tp, 1);
++ }
++ return tp;
++}
++
++rtx
++ia64_expand_move (op0, op1)
++ rtx op0, op1;
++{
++ enum machine_mode mode = GET_MODE (op0);
++
++ if (!reload_in_progress && !reload_completed && !ia64_move_ok (op0, op1))
++ op1 = force_reg (mode, op1);
++
++ if (mode == Pmode)
++ {
++ enum tls_model tls_kind;
++ if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
++ {
++ rtx tga_op1, tga_op2, tga_ret, tga_eqv, tmp, insns;
++
++ switch (tls_kind)
++ {
++ case TLS_MODEL_GLOBAL_DYNAMIC:
++ start_sequence ();
++
++ tga_op1 = gen_reg_rtx (Pmode);
++ emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1));
++ tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
++ RTX_UNCHANGING_P (tga_op1) = 1;
++
++ tga_op2 = gen_reg_rtx (Pmode);
++ emit_insn (gen_load_ltoff_dtprel (tga_op2, op1));
++ tga_op2 = gen_rtx_MEM (Pmode, tga_op2);
++ RTX_UNCHANGING_P (tga_op2) = 1;
++
++ tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX,
++ LCT_CONST, Pmode, 2, tga_op1,
++ Pmode, tga_op2, Pmode);
++
++ insns = get_insns ();
++ end_sequence ();
++
++ emit_libcall_block (insns, op0, tga_ret, op1);
++ return NULL_RTX;
++
++ case TLS_MODEL_LOCAL_DYNAMIC:
++ /* ??? This isn't the completely proper way to do local-dynamic
++ If the call to __tls_get_addr is used only by a single symbol,
++ then we should (somehow) move the dtprel to the second arg
++ to avoid the extra add. */
++ start_sequence ();
++
++ tga_op1 = gen_reg_rtx (Pmode);
++ emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1));
++ tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
++ RTX_UNCHANGING_P (tga_op1) = 1;
++
++ tga_op2 = const0_rtx;
++
++ tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX,
++ LCT_CONST, Pmode, 2, tga_op1,
++ Pmode, tga_op2, Pmode);
++
++ insns = get_insns ();
++ end_sequence ();
++
++ tga_eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
++ UNSPEC_LD_BASE);
++ tmp = gen_reg_rtx (Pmode);
++ emit_libcall_block (insns, tmp, tga_ret, tga_eqv);
++
++ if (register_operand (op0, Pmode))
++ tga_ret = op0;
++ else
++ tga_ret = gen_reg_rtx (Pmode);
++ if (TARGET_TLS64)
++ {
++ emit_insn (gen_load_dtprel (tga_ret, op1));
++ emit_insn (gen_adddi3 (tga_ret, tmp, tga_ret));
++ }
++ else
++ emit_insn (gen_add_dtprel (tga_ret, tmp, op1));
++ if (tga_ret == op0)
++ return NULL_RTX;
++ op1 = tga_ret;
++ break;
++
++ case TLS_MODEL_INITIAL_EXEC:
++ tmp = gen_reg_rtx (Pmode);
++ emit_insn (gen_load_ltoff_tprel (tmp, op1));
++ tmp = gen_rtx_MEM (Pmode, tmp);
++ RTX_UNCHANGING_P (tmp) = 1;
++ tmp = force_reg (Pmode, tmp);
++
++ if (register_operand (op0, Pmode))
++ op1 = op0;
++ else
++ op1 = gen_reg_rtx (Pmode);
++ emit_insn (gen_adddi3 (op1, tmp, gen_thread_pointer ()));
++ if (op1 == op0)
++ return NULL_RTX;
++ break;
++
++ case TLS_MODEL_LOCAL_EXEC:
++ if (register_operand (op0, Pmode))
++ tmp = op0;
++ else
++ tmp = gen_reg_rtx (Pmode);
++ if (TARGET_TLS64)
++ {
++ emit_insn (gen_load_tprel (tmp, op1));
++ emit_insn (gen_adddi3 (tmp, gen_thread_pointer (), tmp));
++ }
++ else
++ emit_insn (gen_add_tprel (tmp, gen_thread_pointer (), op1));
++ if (tmp == op0)
++ return NULL_RTX;
++ op1 = tmp;
++ break;
++
++ default:
++ abort ();
++ }
++ }
++ else if (!TARGET_NO_PIC && symbolic_operand (op1, DImode))
++ {
++ /* Before optimization starts, delay committing to any particular
++ type of PIC address load. If this function gets deferred, we
++ may acquire information that changes the value of the
++ sdata_symbolic_operand predicate.
++
++ But don't delay for function pointers. Loading a function address
++ actually loads the address of the descriptor not the function.
++ If we represent these as SYMBOL_REFs, then they get cse'd with
++ calls, and we end up with calls to the descriptor address instead
++ of calls to the function address. Functions are not candidates
++ for sdata anyways.
++
++ Don't delay for LABEL_REF because the splitter loses REG_LABEL
++ notes. Don't delay for pool addresses on general principals;
++ they'll never become non-local behind our back. */
++
++ if (rtx_equal_function_value_matters
++ && GET_CODE (op1) != LABEL_REF
++ && ! (GET_CODE (op1) == SYMBOL_REF
++ && (SYMBOL_REF_FLAG (op1)
++ || CONSTANT_POOL_ADDRESS_P (op1)
++ || STRING_POOL_ADDRESS_P (op1))))
++ emit_insn (gen_movdi_symbolic (op0, op1));
++ else
++ ia64_expand_load_address (op0, op1, NULL_RTX);
++ return NULL_RTX;
++ }
++ }
++
++ return op1;
++}
++
+ rtx
+ ia64_gp_save_reg (setjmp_p)
+ int setjmp_p;
+@@ -3944,6 +4172,16 @@ ia64_override_options ()
+ if (ia64_fixed_range_string)
+ fix_range (ia64_fixed_range_string);
+
++ if (ia64_tls_size_string)
++ {
++ char *end;
++ unsigned long tmp = strtoul (ia64_tls_size_string, &end, 10);
++ if (*end || (tmp != 14 && tmp != 22 && tmp != 64))
++ error ("bad value (%s) for -mtls-size= switch", ia64_tls_size_string);
++ else
++ ia64_tls_size = tmp;
++ }
++
+ ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload;
+ flag_schedule_insns_after_reload = 0;
+
+@@ -4607,6 +4845,13 @@ rtx_needs_barrier (x, flags, pred)
+ need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 2), flags, pred);
+ break;
+
++ case UNSPEC_LTOFF_DTPMOD:
++ case UNSPEC_LTOFF_DTPREL:
++ case UNSPEC_DTPREL:
++ case UNSPEC_LTOFF_TPREL:
++ case UNSPEC_TPREL:
++ break;
++
+ default:
+ abort ();
+ }
+@@ -6872,6 +7117,9 @@ ia64_encode_section_info (decl)
+ tree decl;
+ {
+ const char *symbol_str;
++ bool is_local, is_small;
++ rtx symbol;
++ char encoding = 0;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+@@ -6885,75 +7133,111 @@ ia64_encode_section_info (decl)
+ || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
+ return;
+
+- symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
++ symbol = XEXP (DECL_RTL (decl), 0);
++ symbol_str = XSTR (symbol, 0);
++
++ /* A non-decl is an entry in the constant pool. */
++ if (!DECL_P (decl))
++ is_local = true;
++ /* Static variables are always local. */
++ else if (! TREE_PUBLIC (decl))
++ is_local = true;
++ /* A variable is local if the user tells us so. */
++ else if (MODULE_LOCAL_P (decl))
++ is_local = true;
++ /* Otherwise, variables defined outside this object may not be local. */
++ else if (DECL_EXTERNAL (decl))
++ is_local = false;
++ /* Linkonce and weak data are never local. */
++ else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
++ is_local = false;
++ /* If PIC, then assume that any global name can be overridden by
++ symbols resolved from other modules. */
++ else if (flag_pic)
++ is_local = false;
++ /* Uninitialized COMMON variable may be unified with symbols
++ resolved from other modules. */
++ else if (DECL_COMMON (decl)
++ && (DECL_INITIAL (decl) == NULL
++ || DECL_INITIAL (decl) == error_mark_node))
++ is_local = false;
++ /* Otherwise we're left with initialized (or non-common) global data
++ which is of necessity defined locally. */
++ else
++ is_local = true;
+
+- /* We assume that -fpic is used only to create a shared library (dso).
+- With -fpic, no global data can ever be sdata.
+- Without -fpic, global common uninitialized data can never be sdata, since
+- it can unify with a real definition in a dso. */
+- /* ??? Actually, we can put globals in sdata, as long as we don't use gprel
+- to access them. The linker may then be able to do linker relaxation to
+- optimize references to them. Currently sdata implies use of gprel. */
+- /* We need the DECL_EXTERNAL check for C++. static class data members get
+- both TREE_STATIC and DECL_EXTERNAL set, to indicate that they are
+- statically allocated, but the space is allocated somewhere else. Such
+- decls can not be own data. */
+- if (! TARGET_NO_SDATA
+- && ((TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)
+- && ! (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+- && ! (TREE_PUBLIC (decl)
+- && (flag_pic
+- || (DECL_COMMON (decl)
+- && (DECL_INITIAL (decl) == 0
+- || DECL_INITIAL (decl) == error_mark_node)))))
+- || MODULE_LOCAL_P (decl))
+- /* Either the variable must be declared without a section attribute,
+- or the section must be sdata or sbss. */
+- && (DECL_SECTION_NAME (decl) == 0
+- || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+- ".sdata")
+- || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+- ".sbss")))
++ is_small = false;
++ if (TARGET_NO_SDATA)
++ ;
++ else if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
++ {
++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
++ if (strcmp (section, ".sdata") == 0
++ || strcmp (section, ".sbss") == 0)
++ is_small = true;
++ }
++ else
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+- /* If the variable has already been defined in the output file, then it
+- is too late to put it in sdata if it wasn't put there in the first
+- place. The test is here rather than above, because if it is already
+- in sdata, then it can stay there. */
+-
+- if (TREE_ASM_WRITTEN (decl))
+- ;
+-
+- /* If this is an incomplete type with size 0, then we can't put it in
+- sdata because it might be too big when completed.
+- Objects bigger than threshold should have SDATA_NAME_FLAG_CHAR
+- added if they are in .sdata or .sbss explicitely. */
+- else if (((size > 0
+- && size <= (HOST_WIDE_INT) ia64_section_threshold)
+- || DECL_SECTION_NAME (decl))
+- && symbol_str[0] != SDATA_NAME_FLAG_CHAR)
+- {
+- size_t len = strlen (symbol_str);
+- char *newstr = alloca (len + 1);
+- const char *string;
++ /* If this is an incomplete type with size 0, then we can't put it
++ in sdata because it might be too big when completed. */
++ if (size > 0 && size <= ia64_section_threshold)
++ is_small = true;
++ }
+
+- *newstr = SDATA_NAME_FLAG_CHAR;
+- memcpy (newstr + 1, symbol_str, len + 1);
+-
+- string = ggc_alloc_string (newstr, len + 1);
+- XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
++ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++ {
++ enum tls_model kind;
++ if (!flag_pic)
++ {
++ if (is_local)
++ kind = TLS_MODEL_LOCAL_EXEC;
++ else
++ kind = TLS_MODEL_INITIAL_EXEC;
+ }
+- }
+- /* This decl is marked as being in small data/bss but it shouldn't
+- be; one likely explanation for this is that the decl has been
+- moved into a different section from the one it was in when
+- ENCODE_SECTION_INFO was first called. Remove the '@'. */
+- else if (symbol_str[0] == SDATA_NAME_FLAG_CHAR)
++ else if (is_local)
++ kind = TLS_MODEL_LOCAL_DYNAMIC;
++ else
++ kind = TLS_MODEL_GLOBAL_DYNAMIC;
++ if (kind < flag_tls_default)
++ kind = flag_tls_default;
++
++ encoding = " GLil"[kind];
++ }
++ /* Determine if DECL will wind up in .sdata/.sbss. */
++ else if (is_local && is_small)
++ encoding = 's';
++
++ /* Finally, encode this into the symbol string. */
++ if (encoding)
+ {
+- XSTR (XEXP (DECL_RTL (decl), 0), 0)
+- = ggc_strdup (symbol_str + 1);
++ char *newstr;
++ size_t len;
++
++ if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
++ {
++ if (encoding == symbol_str[1])
++ return;
++ /* ??? Sdata became thread or thread becaome not thread. Lose. */
++ abort ();
++ }
++
++ len = strlen (symbol_str);
++ newstr = alloca (len + 3);
++ newstr[0] = ENCODE_SECTION_INFO_CHAR;
++ newstr[1] = encoding;
++ memcpy (newstr + 2, symbol_str, len + 1);
++
++ XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2);
+ }
++
++ /* This decl is marked as being in small data/bss but it shouldn't be;
++ one likely explanation for this is that the decl has been moved into
++ a different section from the one it was in when encode_section_info
++ was first called. Remove the encoding. */
++ else if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
++ XSTR (symbol, 0) = ggc_strdup (symbol_str + 2);
+ }
+ \f
+ /* Output assembly directives for prologue regions. */
+--- gcc/config/ia64/ia64.h.jj Tue Apr 23 20:28:21 2002
++++ gcc/config/ia64/ia64.h Wed Jun 19 19:33:52 2002
+@@ -109,6 +109,11 @@ extern int target_flags;
+
+ #define TARGET_DWARF2_ASM (target_flags & MASK_DWARF2_ASM)
+
++extern int ia64_tls_size;
++#define TARGET_TLS14 (ia64_tls_size == 14)
++#define TARGET_TLS22 (ia64_tls_size == 22)
++#define TARGET_TLS64 (ia64_tls_size == 64)
++
+ /* This macro defines names of command options to set and clear bits in
+ `target_flags'. Its definition is an initializer with a subgrouping for
+ each command option. */
+@@ -177,10 +182,13 @@ extern int target_flags;
+ subgrouping for each command option. */
+
+ extern const char *ia64_fixed_range_string;
++extern const char *ia64_tls_size_string;
+ #define TARGET_OPTIONS \
+ { \
+ { "fixed-range=", &ia64_fixed_range_string, \
+ N_("Specify range of registers to make fixed")}, \
++ { "tls-size=", &ia64_tls_size_string, \
++ N_("Specify bit size of immediate TLS offsets")}, \
+ }
+
+ /* Sometimes certain combinations of command options do not make sense on a
+@@ -1801,7 +1809,7 @@ do { \
+ && (DECL_ONE_ONLY (DECL) || DECL_WEAK (DECL) || DECL_COMMON (DECL) \
+ || DECL_SECTION_NAME (DECL) != 0))
+
+-#define SDATA_NAME_FLAG_CHAR '@'
++#define ENCODE_SECTION_INFO_CHAR '@'
+
+ #define IA64_DEFAULT_GVALUE 8
+
+@@ -1811,8 +1819,8 @@ do { \
+ #define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \
+ do { \
+ (VAR) = (SYMBOL_NAME); \
+- if ((VAR)[0] == SDATA_NAME_FLAG_CHAR) \
+- (VAR)++; \
++ if ((VAR)[0] == ENCODE_SECTION_INFO_CHAR) \
++ (VAR) += 2; \
+ if ((VAR)[0] == '*') \
+ (VAR)++; \
+ } while (0)
+--- gcc/config/ia64/ia64.md.jj Tue Apr 23 20:28:21 2002
++++ gcc/config/ia64/ia64.md Wed Jun 19 19:33:52 2002
+@@ -68,7 +68,19 @@
+ ;; 23 cycle display
+ ;; 24 addp4
+ ;; 25 prologue_use
+-;;
++
++;; More unspec:
++
++(define_constants
++ [; Relocations
++ (UNSPEC_LTOFF_DTPMOD 14)
++ (UNSPEC_LTOFF_DTPREL 15)
++ (UNSPEC_DTPREL 16)
++ (UNSPEC_LTOFF_TPREL 17)
++ (UNSPEC_TPREL 18)
++ (UNSPEC_LD_BASE 26)
++ ])
++
+ ;; unspec_volatile:
+ ;; 0 alloc
+ ;; 1 blockage
+@@ -272,12 +284,12 @@
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (QImode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
+@@ -297,12 +309,12 @@
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (HImode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
+@@ -322,12 +334,12 @@
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (SImode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn "*movsi_internal"
+ [(set (match_operand:SI 0 "destination_operand" "=r,r,r,r, m, r,*f,*f, r,*d")
+@@ -351,32 +363,12 @@
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (DImode, operands[1]);
+- if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
+- {
+- /* Before optimization starts, delay committing to any particular
+- type of PIC address load. If this function gets deferred, we
+- may acquire information that changes the value of the
+- sdata_symbolic_operand predicate. */
+- /* But don't delay for function pointers. Loading a function address
+- actually loads the address of the descriptor not the function.
+- If we represent these as SYMBOL_REFs, then they get cse'd with
+- calls, and we end up with calls to the descriptor address instead of
+- calls to the function address. Functions are not candidates for
+- sdata anyways. */
+- if (rtx_equal_function_value_matters
+- && ! (GET_CODE (operands[1]) == SYMBOL_REF
+- && SYMBOL_REF_FLAG (operands[1])))
+- emit_insn (gen_movdi_symbolic (operands[0], operands[1], gen_reg_rtx (DImode)));
+- else
+- ia64_expand_load_address (operands[0], operands[1], NULL_RTX);
+- DONE;
+- }
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ ;; This is used during early compilation to delay the decision on
+ ;; how to refer to a variable as long as possible. This is especially
+@@ -384,19 +376,22 @@
+ ;; deferred functions, since we may acquire additional information
+ ;; on the variables used in the meantime.
+
+-;; ??? This causes us to lose REG_LABEL notes, because the insn splitter
+-;; does not attempt to preserve any REG_NOTES on the input instruction.
+-
+ (define_insn_and_split "movdi_symbolic"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operand:DI 1 "symbolic_operand" "s"))
+- (clobber (match_operand:DI 2 "register_operand" "+r"))
++ (clobber (match_scratch:DI 2 "=r"))
+ (use (reg:DI 1))]
+ ""
+ "* abort ();"
+- ""
++ "!no_new_pseudos || reload_completed"
+ [(const_int 0)]
+- "ia64_expand_load_address (operands[0], operands[1], operands[2]); DONE;")
++{
++ rtx scratch = operands[2];
++ if (!reload_completed)
++ gen_reg_rtx (Pmode);
++ ia64_expand_load_address (operands[0], operands[1], scratch);
++ DONE;
++})
+
+ (define_insn "*movdi_internal"
+ [(set (match_operand:DI 0 "destination_operand"
+@@ -510,6 +505,131 @@
+ "addl %0 = @ltoff(%1), gp"
+ [(set_attr "itanium_class" "ialu")])
+
++(define_insn "load_ltoff_dtpmod"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (reg:DI 1)
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_LTOFF_DTPMOD)))]
++ ""
++ "addl %0 = @ltoff(@dtpmod(%1)), gp"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_insn "load_ltoff_dtprel"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (reg:DI 1)
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_LTOFF_DTPREL)))]
++ ""
++ "addl %0 = @ltoff(@dtprel(%1)), gp"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_expand "load_dtprel"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_DTPREL))]
++ ""
++ "")
++
++(define_insn "*load_dtprel64"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_DTPREL))]
++ "TARGET_TLS64"
++ "movl %0 = @dtprel(%1)"
++ [(set_attr "itanium_class" "long_i")])
++
++(define_insn "*load_dtprel22"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_DTPREL))]
++ ""
++ "addl %0 = @dtprel(%1), r0"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_expand "add_dtprel"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (plus:DI (match_operand:DI 1 "register_operand" "")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_DTPREL)))]
++ "!TARGET_TLS64"
++ "")
++
++(define_insn "*add_dtprel14"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" "r")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_DTPREL)))]
++ "TARGET_TLS14"
++ "adds %0 = @dtprel(%2), %1"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_insn "*add_dtprel22"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" "a")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_DTPREL)))]
++ "TARGET_TLS22"
++ "addl %0 = @dtprel(%2), %1"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_insn "load_ltoff_tprel"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (reg:DI 1)
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_LTOFF_TPREL)))]
++ ""
++ "addl %0 = @ltoff(@tprel(%1)), gp"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_expand "load_tprel"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_TPREL))]
++ ""
++ "")
++
++(define_insn "*load_tprel64"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_TPREL))]
++ "TARGET_TLS64"
++ "movl %0 = @tprel(%1)"
++ [(set_attr "itanium_class" "long_i")])
++
++(define_insn "*load_tprel22"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++ UNSPEC_TPREL))]
++ ""
++ "addl %0 = @tprel(%1), r0"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_expand "add_tprel"
++ [(set (match_operand:DI 0 "register_operand" "")
++ (plus:DI (match_operand:DI 1 "register_operand" "")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_TPREL)))]
++ "!TARGET_TLS64"
++ "")
++
++(define_insn "*add_tprel14"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" "r")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_TPREL)))]
++ "TARGET_TLS14"
++ "adds %0 = @tprel(%2), %1"
++ [(set_attr "itanium_class" "ialu")])
++
++(define_insn "*add_tprel22"
++ [(set (match_operand:DI 0 "register_operand" "=r")
++ (plus:DI (match_operand:DI 1 "register_operand" "a")
++ (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++ UNSPEC_TPREL)))]
++ "TARGET_TLS22"
++ "addl %0 = @tprel(%2), %1"
++ [(set_attr "itanium_class" "ialu")])
++
+ ;; With no offsettable memory references, we've got to have a scratch
+ ;; around to play with the second word.
+ (define_expand "movti"
+@@ -517,12 +637,12 @@
+ (match_operand:TI 1 "general_operand" ""))
+ (clobber (match_scratch:DI 2 ""))])]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (TImode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn_and_split "*movti_internal"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
+@@ -639,12 +759,12 @@
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (SFmode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
+@@ -665,12 +785,12 @@
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+- "
+ {
+- if (! reload_in_progress && ! reload_completed
+- && ! ia64_move_ok (operands[0], operands[1]))
+- operands[1] = force_reg (DFmode, operands[1]);
+-}")
++ rtx op1 = ia64_expand_move (operands[0], operands[1]);
++ if (!op1)
++ DONE;
++ operands[1] = op1;
++})
+
+ (define_insn "*movdf_internal"
+ [(set (match_operand:DF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
+--- gcc/config/ia64/sysv4.h.jj Mon Jun 3 17:24:18 2002
++++ gcc/config/ia64/sysv4.h Wed Jun 19 19:33:52 2002
+@@ -42,8 +42,7 @@ extern int size_directive_output;
+ #undef ASM_OUTPUT_ALIGNED_LOCAL
+ #define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+ do { \
+- if ((DECL) \
+- && XSTR (XEXP (DECL_RTL (DECL), 0), 0)[0] == SDATA_NAME_FLAG_CHAR) \
++ if ((DECL) && sdata_symbolic_operand (XEXP (DECL_RTL (DECL), 0), Pmode)) \
+ sbss_section (); \
+ else \
+ bss_section (); \
+@@ -62,8 +61,8 @@ do { \
+ #define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+ do { \
+ const char *name_ = NAME; \
+- if (*name_ == SDATA_NAME_FLAG_CHAR) \
+- name_++; \
++ if (*name_ == ENCODE_SECTION_INFO_CHAR) \
++ name_ += 2; \
+ if (*name_ == '*') \
+ name_++; \
+ else \
+@@ -149,9 +148,11 @@ do { \
+ 0 .text
+ 1 .rodata
+ 2 .data
+- 3 .sdata
+- 4 .bss
++ 3 .bss
++ 4 .sdata
+ 5 .sbss
++ 6 .tdata
++ 7 .tbss
+ */
+ #define DO_SELECT_SECTION(SECNUM, DECL, RELOC) \
+ do \
+@@ -167,9 +168,10 @@ do { \
+ } \
+ else if (TREE_CODE (DECL) == VAR_DECL) \
+ { \
+- if (XSTR (XEXP (DECL_RTL (DECL), 0), 0)[0] \
+- == SDATA_NAME_FLAG_CHAR) \
+- SECNUM = 3; \
++ if (DECL_THREAD_LOCAL (DECL)) \
++ SECNUM = 6; \
++ else if (sdata_symbolic_operand (XEXP (DECL_RTL (DECL), 0), Pmode))\
++ SECNUM = 4; \
+ /* ??? We need the extra RELOC check, because the default \
+ is to only check RELOC if flag_pic is set, and we don't \
+ set flag_pic (yet?). */ \
+@@ -184,13 +186,18 @@ do { \
+ SECNUM = 0x201; \
+ else \
+ SECNUM = 0x301; \
++ \
++ if (SECNUM >= 2 \
++ && (!DECL_INITIAL (DECL) \
++ || DECL_INITIAL (DECL) == error_mark_node)) \
++ SECNUM++; \
+ } \
+ /* This could be a CONSTRUCTOR containing ADDR_EXPR of a VAR_DECL, \
+ in which case we can't put it in a shared library rodata. */ \
+ else if (flag_pic && (RELOC)) \
+- SECNUM = 3; \
+- else \
+ SECNUM = 2; \
++ else \
++ SECNUM = 1; \
+ } \
+ while (0)
+
+@@ -206,8 +213,8 @@ do { \
+ text_section, \
+ const_section, \
+ data_section, \
+- sdata_section, \
+ bss_section, \
++ sdata_section, \
+ sbss_section \
+ }; \
+ \
+@@ -217,6 +224,12 @@ do { \
+ \
+ switch (sec) \
+ { \
++ case 6: \
++ named_section (NULL_TREE, ".tdata", RELOC); \
++ break; \
++ case 7: \
++ named_section (NULL_TREE, ".tbss", RELOC); \
++ break; \
+ case 0x101: \
+ mergeable_string_section (DECL, ALIGN, 0); \
+ break; \
+@@ -244,9 +257,11 @@ do { \
+ { ".text.", ".gnu.linkonce.t." }, \
+ { ".rodata.", ".gnu.linkonce.r." }, \
+ { ".data.", ".gnu.linkonce.d." }, \
+- { ".sdata.", ".gnu.linkonce.s." }, \
+ { ".bss.", ".gnu.linkonce.b." }, \
+- { ".sbss.", ".gnu.linkonce.sb." } \
++ { ".sdata.", ".gnu.linkonce.s." }, \
++ { ".sbss.", ".gnu.linkonce.sb." }, \
++ { ".tdata.", ".gnu.linkonce.td." }, \
++ { ".tbss.", ".gnu.linkonce.tb." } \
+ }; \
+ \
+ int nlen, plen, sec; \
+--- gcc/config/elfos.h.jj Tue Dec 18 01:30:48 2001
++++ gcc/config/elfos.h Wed Jun 19 19:33:52 2002
+@@ -288,24 +288,28 @@ const_section () \
+ const char *name; \
+ char *string; \
+ const char *prefix; \
+- static const char *const prefixes[4][2] = \
++ static const char *const prefixes[][2] = \
+ { \
+ { ".text.", ".gnu.linkonce.t." }, \
+ { ".rodata.", ".gnu.linkonce.r." }, \
+ { ".data.", ".gnu.linkonce.d." }, \
+- { ".bss.", ".gnu.linkonce.b." } \
++ { ".bss.", ".gnu.linkonce.b." }, \
++ { ".tdata", ".gnu.linkonce.td." }, \
++ { ".tbss", ".gnu.linkonce.tb." }, \
+ }; \
+ \
+ if (TREE_CODE (DECL) == FUNCTION_DECL) \
+ sec = 0; \
+ else if (DECL_INITIAL (DECL) == 0 \
+ || DECL_INITIAL (DECL) == error_mark_node) \
+- sec = 3; \
++ sec = 3; \
+ else if (DECL_READONLY_SECTION (DECL, RELOC)) \
+ sec = 1; \
+ else \
+ sec = 2; \
+- \
++ if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) \
++ sec = (sec == 3 ? 5 : 4); \
++ \
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
+ /* Strip off any encoding in name. */ \
+ STRIP_NAME_ENCODING (name, name); \
+@@ -367,10 +371,18 @@ const_section () \
+ } \
+ else if (TREE_CODE (DECL) == VAR_DECL) \
+ { \
+- if (!TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
+- || !DECL_INITIAL (DECL) \
+- || (DECL_INITIAL (DECL) != error_mark_node \
+- && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
++ if (DECL_THREAD_LOCAL (DECL)) \
++ { \
++ if (!DECL_INITIAL (DECL) \
++ || DECL_INITIAL (DECL) == error_mark_node) \
++ named_section (NULL_TREE, ".tbss", RELOC); \
++ else \
++ named_section (NULL_TREE, ".tdata", RELOC); \
++ } \
++ else if (!TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
++ || !DECL_INITIAL (DECL) \
++ || (DECL_INITIAL (DECL) != error_mark_node \
++ && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
+ { \
+ if (flag_pic && ((RELOC) & 2)) \
+ named_section (NULL_TREE, ".data.rel", RELOC); \
+--- gcc/fixinc/fixincl.x.jj Thu May 2 12:15:15 2002
++++ gcc/fixinc/fixincl.x Wed Jun 19 19:33:52 2002
+@@ -5,7 +5,7 @@
+ * files which are fixed to work correctly with ANSI C and placed in a
+ * directory that GNU C will search.
+ *
+- * This file contains 142 fixup descriptions.
++ * This file contains 143 fixup descriptions.
+ *
+ * See README for more information.
+ *
+@@ -4568,6 +4568,41 @@ static const char* apzSysz_Stdlib_For_Su
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
++ * Description of Thread_Keyword fix
++ */
++tSCC zThread_KeywordName[] =
++ "thread_keyword";
++
++/*
++ * File name selection pattern
++ */
++tSCC zThread_KeywordList[] =
++ "|pthread.h|bits/sigthread.h|";
++/*
++ * Machine/OS name selection pattern
++ */
++#define apzThread_KeywordMachs (const char**)NULL
++
++/*
++ * content selection pattern - do fix if pattern found
++ */
++tSCC zThread_KeywordSelect0[] =
++ " __thread([,)])";
++
++#define THREAD_KEYWORD_TEST_CT 1
++static tTestDesc aThread_KeywordTests[] = {
++ { TT_EGREP, zThread_KeywordSelect0, (regex_t*)NULL }, };
++
++/*
++ * Fix Command Arguments for Thread_Keyword
++ */
++static const char* apzThread_KeywordPatch[] = {
++ "format",
++ " __thr%1",
++ (char*)NULL };
++
++/* * * * * * * * * * * * * * * * * * * * * * * * * *
++ *
+ * Description of Tinfo_Cplusplus fix
+ */
+ tSCC zTinfo_CplusplusName[] =
+@@ -5581,9 +5616,9 @@ static const char* apzX11_SprintfPatch[]
+ *
+ * List of all fixes
+ */
+-#define REGEX_COUNT 151
++#define REGEX_COUNT 152
+ #define MACH_LIST_SIZE_LIMIT 279
+-#define FIX_COUNT 142
++#define FIX_COUNT 143
+
+ /*
+ * Enumerate the fixes
+@@ -5705,6 +5740,7 @@ typedef enum {
+ SVR4_PROFIL_FIXIDX,
+ SYSV68_STRING_FIXIDX,
+ SYSZ_STDLIB_FOR_SUN_FIXIDX,
++ THREAD_KEYWORD_FIXIDX,
+ TINFO_CPLUSPLUS_FIXIDX,
+ ULTRIX_ATEXIT_PARAM_FIXIDX,
+ ULTRIX_ATOF_PARAM_FIXIDX,
+@@ -6314,6 +6350,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
+ SYSZ_STDLIB_FOR_SUN_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+ aSysz_Stdlib_For_SunTests, apzSysz_Stdlib_For_SunPatch, 0 },
+
++ { zThread_KeywordName, zThread_KeywordList,
++ apzThread_KeywordMachs,
++ THREAD_KEYWORD_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
++ aThread_KeywordTests, apzThread_KeywordPatch, 0 },
++
+ { zTinfo_CplusplusName, zTinfo_CplusplusList,
+ apzTinfo_CplusplusMachs,
+ TINFO_CPLUSPLUS_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+--- gcc/fixinc/inclhack.def.jj Thu May 2 12:15:17 2002
++++ gcc/fixinc/inclhack.def Wed Jun 19 19:33:52 2002
+@@ -1,4 +1,3 @@
+-
+ /* -*- Mode: C -*- */
+
+ autogen definitions fixincl;
+@@ -2886,6 +2885,24 @@ fix = {
+ };
+
+
++/*
++ * __thread is now a keyword.
++ */
++fix = {
++ hackname = thread_keyword;
++ files = "pthread.h";
++ files = "bits/sigthread.h";
++ select = " __thread([,)])";
++ c_fix = format;
++ c_fix_arg = " __thr%1";
++
++ test_text =
++ "extern int pthread_create (pthread_t *__restrict __thread,\n"
++ "extern int pthread_kill (pthread_t __thread, int __signo);\n"
++ "extern int pthread_cancel (pthread_t __thread);";
++};
++
++
+ /*
+ * if the #if says _cplusplus, not the double underscore __cplusplus
+ * that it should be
+--- gcc/testsuite/g++.dg/dg.exp.jj Thu Feb 14 13:26:12 2002
++++ gcc/testsuite/g++.dg/dg.exp Wed Jun 19 19:33:52 2002
+@@ -28,10 +28,12 @@ if ![info exists DEFAULT_CXXFLAGS] then
+ # Initialize `dg'.
+ dg-init
+
+-# Gather a list of all tests, excluding those in special/; those are handled
+-# well, specially.
+-set all [lsort [find $srcdir/$subdir *.C]]
+-set tests [prune [prune $all $srcdir/$subdir/special/*] $srcdir/$subdir/debug/*]
++# Gather a list of all tests, with the exception of those in directories
++# that are handled specially.
++set tests [lsort [find $srcdir/$subdir *.C]]
++set tests [prune $tests $srcdir/$subdir/debug/*]
++set tests [prune $tests $srcdir/$subdir/special/*]
++set tests [prune $tests $srcdir/$subdir/tls/*]
+
+ # Main loop.
+ dg-runtest $tests "" $DEFAULT_CXXFLAGS
+--- gcc/testsuite/g++.dg/tls/diag-1.C.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/diag-1.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,30 @@
++/* Valid __thread specifiers. */
++
++__thread int g1;
++extern __thread int g2;
++static __thread int g3;
++
++void foo()
++{
++ extern __thread int l1;
++ static __thread int l2;
++}
++
++struct A {
++ static __thread int i;
++};
++
++__thread int A::i = 42;
++
++template <typename T> struct B {
++ static __thread T t;
++};
++
++template <typename T>
++__thread T B<T>::t = 42;
++
++void bar ()
++{
++ int j = B<int>::t;
++ int k = B<const int>::t;
++}
+--- gcc/testsuite/g++.dg/tls/diag-2.C.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/diag-2.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,25 @@
++/* Invalid __thread specifiers. */
++
++__thread extern int g1; /* { dg-error "`__thread' before `extern'" } */
++__thread static int g2; /* { dg-error "`__thread' before `static'" } */
++__thread __thread int g3; /* { dg-error "duplicate `__thread'" } */
++typedef __thread int g4; /* { dg-error "multiple storage classes" } */
++
++void foo()
++{
++ __thread int l1; /* { dg-error "implicitly auto and declared `__thread'" } */
++ auto __thread int l2; /* { dg-error "multiple storage classes" } */
++ __thread extern int l3; /* { dg-error "`__thread' before `extern'" } */
++ register __thread int l4; /* { dg-error "multiple storage classes" } */
++}
++
++__thread void f1 (); /* { dg-error "invalid for function" } */
++extern __thread void f2 (); /* { dg-error "invalid for function" } */
++static __thread void f3 (); /* { dg-error "invalid for function" } */
++__thread void f4 () { } /* { dg-error "invalid for function" } */
++
++void bar(__thread int p1); /* { dg-error "(invalid in parameter)|(specified for parameter)" } */
++
++struct A {
++ __thread int i; /* { dg-error "specified for field" } */
++};
+--- gcc/testsuite/g++.dg/tls/init-1.C.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/init-1.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,13 @@
++/* Valid initializations. */
++
++__thread int i = 42;
++
++static int j;
++__thread int *p = &j;
++
++/* Note that this is valid in C++ (unlike C) as a run-time initialization. */
++int *q = &i;
++
++/* Valid because "const int k" is an integral constant expression in C++. */
++__thread const int k = 42;
++__thread const int l = k;
+--- gcc/testsuite/g++.dg/tls/init-2.C.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/init-2.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,13 @@
++/* Invalid initializations. */
++
++extern __thread int i;
++__thread int *p = &i; /* { dg-error "run-time initialization" } */
++
++extern int f();
++__thread int j = f(); /* { dg-error "run-time initialization" } */
++
++struct S
++{
++ S();
++};
++__thread S s; /* { dg-error "run-time initialization" } */
+--- gcc/testsuite/g++.dg/tls/tls.exp.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/tls.exp Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,44 @@
++# Copyright (C) 2002 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++# GCC testsuite that uses the `dg.exp' driver.
++
++# Load support procs.
++load_lib g++-dg.exp
++
++# Test for thread-local data supported by the platform. If it
++# isn't, everything will fail with the "not supported" message.
++
++set comp_output [g++_target_compile \
++ "$srcdir/$subdir/trivial.C" "trivial.S" assembly ""]
++if { [string match "*not supported*" $comp_output] } {
++ return 0
++}
++
++# If a testcase doesn't have special options, use these.
++global DEFAULT_CXXFLAGS
++if ![info exists DEFAULT_CXXFLAGS] then {
++ set DEFAULT_CXXFLAGS " -ansi -pedantic-errors -Wno-long-long"
++}
++
++# Initialize `dg'.
++dg-init
++
++# Main loop.
++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
++
++# All done.
++dg-finish
+--- gcc/testsuite/g++.dg/tls/trivial.C.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/trivial.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1 @@
++__thread int i;
+--- gcc/testsuite/gcc.dg/tls/diag-1.c.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/diag-1.c Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,11 @@
++/* Valid __thread specifiers. */
++
++__thread int g1;
++extern __thread int g2;
++static __thread int g3;
++
++void foo()
++{
++ extern __thread int l1;
++ static __thread int l2;
++}
+--- gcc/testsuite/gcc.dg/tls/diag-2.c.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/diag-2.c Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,21 @@
++/* Invalid __thread specifiers. */
++
++__thread extern int g1; /* { dg-error "`__thread' before `extern'" } */
++__thread static int g2; /* { dg-error "`__thread' before `static'" } */
++__thread __thread int g3; /* { dg-error "duplicate `__thread'" } */
++typedef __thread int g4; /* { dg-error "multiple storage classes" } */
++
++void foo()
++{
++ __thread int l1; /* { dg-error "implicitly auto and declared `__thread'" } */
++ auto __thread int l2; /* { dg-error "multiple storage classes" } */
++ __thread extern int l3; /* { dg-error "`__thread' before `extern'" } */
++ register __thread int l4; /* { dg-error "multiple storage classes" } */
++}
++
++__thread void f1 (); /* { dg-error "invalid storage class for function" } */
++extern __thread void f2 (); /* { dg-error "invalid storage class for function" } */
++static __thread void f3 (); /* { dg-error "invalid storage class for function" } */
++__thread void f4 () { } /* { dg-error "function definition declared `__thread'" } */
++
++void bar(__thread int p1); /* { dg-error "storage class specified for parameter" } */
+--- gcc/testsuite/gcc.dg/tls/init-1.c.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/init-1.c Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,4 @@
++/* Invalid initializations. */
++
++extern __thread int i;
++int *p = &i; /* { dg-error "initializer element is not constant" } */
+--- gcc/testsuite/gcc.dg/tls/tls.exp.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/tls.exp Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,45 @@
++# Copyright (C) 2002 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++# GCC testsuite that uses the `dg.exp' driver.
++
++# Load support procs.
++load_lib gcc-dg.exp
++
++# Test for thread-local data supported by the platform. If it
++# isn't, everything will fail with the "not supported" message.
++
++set comp_output [gcc_target_compile \
++ "$srcdir/$subdir/trivial.c" "trivial.S" assembly ""]
++if { [string match "*not supported*" $comp_output] } {
++ return 0
++}
++
++# If a testcase doesn't have special options, use these.
++global DEFAULT_CFLAGS
++if ![info exists DEFAULT_CFLAGS] then {
++ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
++}
++
++# Initialize `dg'.
++dg-init
++
++# Main loop.
++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
++ "" $DEFAULT_CFLAGS
++
++# All done.
++dg-finish
+--- gcc/testsuite/gcc.dg/tls/trivial.c.jj Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/trivial.c Wed Jun 19 19:33:52 2002
+@@ -0,0 +1 @@
++__thread int i;
+--- gcc/c-common.h.jj Wed Apr 17 15:34:36 2002
++++ gcc/c-common.h Wed Jun 19 19:33:52 2002
+@@ -58,7 +58,7 @@ enum rid
+ RID_VOLATILE, RID_SIGNED, RID_AUTO, RID_RESTRICT,
+
+ /* C extensions */
+- RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX,
++ RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_THREAD,
+
+ /* C++ */
+ RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,
+--- gcc/c-decl.c.jj Wed Jun 19 19:33:50 2002
++++ gcc/c-decl.c Wed Jun 19 19:33:52 2002
+@@ -3571,9 +3571,19 @@ start_decl (declarator, declspecs, initi
+ /* ANSI specifies that a tentative definition which is not merged with
+ a non-tentative definition behaves exactly like a definition with an
+ initializer equal to zero. (Section 3.7.2)
+- -fno-common gives strict ANSI behavior. Usually you don't want it.
+- This matters only for variables with external linkage. */
+- if (! flag_no_common || ! TREE_PUBLIC (decl))
++
++ -fno-common gives strict ANSI behavior, though this tends to break
++ a large body of code that grew up without this rule.
++
++ Thread-local variables are never common, since there's no entrenched
++ body of code to break, and it allows more efficient variable references
++ in the presense of dynamic linking. */
++
++ if (TREE_CODE (decl) == VAR_DECL
++ && !initialized
++ && TREE_PUBLIC (decl)
++ && !DECL_THREAD_LOCAL (decl)
++ && !flag_no_common)
+ DECL_COMMON (decl) = 1;
+
+ /* Set attributes here so if duplicate decl, will have proper attributes. */
+@@ -4172,7 +4182,7 @@ grokdeclarator (declarator, declspecs, d
+ enum rid i = C_RID_CODE (id);
+ if ((int) i <= (int) RID_LAST_MODIFIER)
+ {
+- if (i == RID_LONG && (specbits & (1 << (int) i)))
++ if (i == RID_LONG && (specbits & (1 << (int) RID_LONG)))
+ {
+ if (longlong)
+ error ("`long long long' is too long for GCC");
+@@ -4186,6 +4196,19 @@ grokdeclarator (declarator, declspecs, d
+ }
+ else if (specbits & (1 << (int) i))
+ pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
++
++ /* Diagnose "__thread extern". Recall that this list
++ is in the reverse order seen in the text. */
++ if (i == RID_THREAD
++ && (specbits & (1 << (int) RID_EXTERN
++ | 1 << (int) RID_STATIC)))
++ {
++ if (specbits & 1 << (int) RID_EXTERN)
++ error ("`__thread' before `extern'");
++ else
++ error ("`__thread' before `static'");
++ }
++
+ specbits |= 1 << (int) i;
+ goto found;
+ }
+@@ -4438,6 +4461,12 @@ grokdeclarator (declarator, declspecs, d
+ if (specbits & 1 << (int) RID_REGISTER) nclasses++;
+ if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
+
++ /* "static __thread" and "extern __thread" are allowed. */
++ if ((specbits & (1 << (int) RID_THREAD
++ | 1 << (int) RID_STATIC
++ | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
++ nclasses++;
++
+ /* Warn about storage classes that are invalid for certain
+ kinds of declarations (parameters, typenames, etc.). */
+
+@@ -4447,7 +4476,8 @@ grokdeclarator (declarator, declspecs, d
+ && (specbits
+ & ((1 << (int) RID_REGISTER)
+ | (1 << (int) RID_AUTO)
+- | (1 << (int) RID_TYPEDEF))))
++ | (1 << (int) RID_TYPEDEF)
++ | (1 << (int) RID_THREAD))))
+ {
+ if (specbits & 1 << (int) RID_AUTO
+ && (pedantic || current_binding_level == global_binding_level))
+@@ -4456,8 +4486,10 @@ grokdeclarator (declarator, declspecs, d
+ error ("function definition declared `register'");
+ if (specbits & 1 << (int) RID_TYPEDEF)
+ error ("function definition declared `typedef'");
++ if (specbits & 1 << (int) RID_THREAD)
++ error ("function definition declared `__thread'");
+ specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+- | (1 << (int) RID_AUTO));
++ | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
+ }
+ else if (decl_context != NORMAL && nclasses > 0)
+ {
+@@ -4480,7 +4512,7 @@ grokdeclarator (declarator, declspecs, d
+ }
+ specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+ | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
+- | (1 << (int) RID_EXTERN));
++ | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
+ }
+ }
+ else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
+@@ -4491,12 +4523,25 @@ grokdeclarator (declarator, declspecs, d
+ else
+ error ("`%s' has both `extern' and initializer", name);
+ }
+- else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
+- && current_binding_level != global_binding_level)
+- error ("nested function `%s' declared `extern'", name);
+- else if (current_binding_level == global_binding_level
+- && specbits & (1 << (int) RID_AUTO))
+- error ("top-level declaration of `%s' specifies `auto'", name);
++ else if (current_binding_level == global_binding_level)
++ {
++ if (specbits & 1 << (int) RID_AUTO)
++ error ("top-level declaration of `%s' specifies `auto'", name);
++ }
++ else
++ {
++ if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
++ error ("nested function `%s' declared `extern'", name);
++ else if ((specbits & (1 << (int) RID_THREAD
++ | 1 << (int) RID_EXTERN
++ | 1 << (int) RID_STATIC))
++ == (1 << (int) RID_THREAD))
++ {
++ error ("function-scope `%s' implicitly auto and declared `__thread'",
++ name);
++ specbits &= ~(1 << (int) RID_THREAD);
++ }
++ }
+ }
+
+ /* Now figure out the structure of the declarator proper.
+@@ -5095,6 +5140,8 @@ grokdeclarator (declarator, declspecs, d
+ pedwarn ("invalid storage class for function `%s'", name);
+ if (specbits & (1 << (int) RID_REGISTER))
+ error ("invalid storage class for function `%s'", name);
++ if (specbits & (1 << (int) RID_THREAD))
++ error ("invalid storage class for function `%s'", name);
+ /* Function declaration not at top level.
+ Storage classes other than `extern' are not allowed
+ and `extern' makes no difference. */
+@@ -5187,22 +5234,32 @@ grokdeclarator (declarator, declspecs, d
+ pedwarn_with_decl (decl, "variable `%s' declared `inline'");
+
+ DECL_EXTERNAL (decl) = extern_ref;
++
+ /* At top level, the presence of a `static' or `register' storage
+ class specifier, or the absence of all storage class specifiers
+ makes this declaration a definition (perhaps tentative). Also,
+ the absence of both `static' and `register' makes it public. */
+ if (current_binding_level == global_binding_level)
+ {
+- TREE_PUBLIC (decl)
+- = !(specbits
+- & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)));
+- TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
++ TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
++ | (1 << (int) RID_REGISTER)));
++ TREE_STATIC (decl) = !extern_ref;
+ }
+ /* Not at top level, only `static' makes a static definition. */
+ else
+ {
+ TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
+- TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
++ TREE_PUBLIC (decl) = extern_ref;
++ }
++
++ if (specbits & 1 << (int) RID_THREAD)
++ {
++ if (targetm.have_tls)
++ DECL_THREAD_LOCAL (decl) = 1;
++ else
++ /* A mere warning is sure to result in improper semantics
++ at runtime. Don't bother to allow this to compile. */
++ error ("thread-local storage not supported for this target");
+ }
+ }
+
+--- gcc/c-parse.in.jj Wed Apr 17 15:34:46 2002
++++ gcc/c-parse.in Wed Jun 19 19:33:52 2002
+@@ -3329,6 +3329,7 @@ static const struct resword reswords[] =
+ { "__restrict__", RID_RESTRICT, 0 },
+ { "__signed", RID_SIGNED, 0 },
+ { "__signed__", RID_SIGNED, 0 },
++ { "__thread", RID_THREAD, 0 },
+ { "__typeof", RID_TYPEOF, 0 },
+ { "__typeof__", RID_TYPEOF, 0 },
+ { "__unbounded", RID_UNBOUNDED, 0 },
+@@ -3424,6 +3425,7 @@ static const short rid_to_yy[RID_MAX] =
+ /* RID_BOUNDED */ TYPE_QUAL,
+ /* RID_UNBOUNDED */ TYPE_QUAL,
+ /* RID_COMPLEX */ TYPESPEC,
++ /* RID_THREAD */ SCSPEC,
+
+ /* C++ */
+ /* RID_FRIEND */ 0,
+--- gcc/config.in.jj Sat Jun 8 00:38:25 2002
++++ gcc/config.in Wed Jun 19 19:33:52 2002
+@@ -523,6 +523,9 @@
+ /* Define if your assembler supports marking sections with SHF_MERGE flag. */
+ #undef HAVE_GAS_SHF_MERGE
+
++/* Define if your assembler supports thread-local storage. */
++#undef HAVE_AS_TLS
++
+ /* Define if your assembler supports explicit relocations. */
+ #undef HAVE_AS_EXPLICIT_RELOCS
+
+--- gcc/flags.h.jj Sat Mar 23 12:02:51 2002
++++ gcc/flags.h Wed Jun 19 19:33:52 2002
+@@ -450,11 +450,22 @@ extern int flag_pretend_float;
+
+ extern int flag_pedantic_errors;
+
+-/* Nonzero means generate position-independent code.
+- This is not fully implemented yet. */
++/* Nonzero means generate position-independent code. 1 vs 2 for a
++ target-dependent "small" or "large" mode. */
+
+ extern int flag_pic;
+
++/* Set to the default thread-local storage (tls) model to use. */
++
++enum tls_model {
++ TLS_MODEL_GLOBAL_DYNAMIC = 1,
++ TLS_MODEL_LOCAL_DYNAMIC,
++ TLS_MODEL_INITIAL_EXEC,
++ TLS_MODEL_LOCAL_EXEC
++};
++
++extern enum tls_model flag_tls_default;
++
+ /* Nonzero means generate extra code for exception handling and enable
+ exception handling. */
+
+--- gcc/configure.in.jj Sat Jun 8 00:38:27 2002
++++ gcc/configure.in Wed Jun 19 19:33:52 2002
+@@ -1715,6 +1715,72 @@ if test x"$gcc_cv_as_shf_merge" = xyes;
+ fi
+ AC_MSG_RESULT($gcc_cv_as_shf_merge)
+
++AC_MSG_CHECKING(assembler thread-local storage support)
++gcc_cv_as_tls=no
++conftest_s=
++tls_first_major=
++tls_first_minor=
++case "$target" in
++changequote(,)dnl
++ i[34567]86-*-*)
++changequote([,])dnl
++ conftest_s='
++ .section ".tdata","awT",@progbits
++foo: .long 25
++ .text
++ movl %gs:0, %eax
++ leal foo@TLSGD(,%ebx,1), %eax
++ leal foo@TLSLDM(%ebx), %eax
++ leal foo@DTPOFF(%eax), %edx
++ movl foo@GOTTPOFF(%ebx), %eax
++ subl foo@GOTTPOFF(%ebx), %eax
++ movl $foo@TPOFF, %eax
++ subl $foo@TPOFF, %eax
++ leal foo@NTPOFF(%ecx), %eax'
++ tls_first_major=2
++ tls_first_minor=13
++ ;;
++ ia64-*-*)
++ conftest_s='
++ .section ".tdata","awT",@progbits
++foo: data8 25
++ .text
++ addl r16 = @ltoff(@dtpmod(foo#)), gp
++ addl r17 = @ltoff(@dtprel(foo#)), gp
++ addl r18 = @ltoff(@tprel(foo#)), gp
++ addl r19 = @dtprel(foo#), gp
++ adds r21 = @dtprel(foo#), r13
++ movl r23 = @dtprel(foo#)
++ addl r20 = @tprel(foo#), gp
++ adds r22 = @tprel(foo#), r13
++ movl r24 = @tprel(foo#)'
++ tls_first_major=2
++ tls_first_minor=13
++ ;;
++esac
++if test -z "$tls_first_major"; then
++ :
++elif test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
++then
++ if test "$gcc_cv_gas_major_version" -eq "$tls_first_major" \
++ -a "$gcc_cv_gas_minor_version" -ge "$tls_first_minor" \
++ -o "$gcc_cv_gas_major_version" -gt "$tls_first_major"; then
++ gcc_cv_as_tls=yes
++ fi
++elif test x$gcc_cv_as != x; then
++ echo "$conftest_s" > conftest.s
++ if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
++ then
++ gcc_cv_as_tls=yes
++ fi
++ rm -f conftest.s conftest.o
++fi
++if test "$gcc_cv_as_tls" = yes; then
++ AC_DEFINE(HAVE_AS_TLS, 1,
++ [Define if your assembler supports thread-local storage.])
++fi
++AC_MSG_RESULT($gcc_cv_as_tls)
++
+ case "$target" in
+ # All TARGET_ABI_OSF targets.
+ alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*)
+--- gcc/configure.jj Sat Jun 8 00:38:27 2002
++++ gcc/configure Wed Jun 19 22:28:09 2002
+@@ -7391,6 +7391,73 @@ EOF
+ fi
+ echo "$ac_t""$gcc_cv_as_shf_merge" 1>&6
+
++echo $ac_n "checking assembler thread-local storage support""... $ac_c" 1>&6
++echo "configure:7399: checking assembler thread-local storage support" >&5
++gcc_cv_as_tls=no
++conftest_s=
++tls_first_major=
++tls_first_minor=
++case "$target" in
++ i[34567]86-*-*)
++ conftest_s='
++ .section ".tdata","awT",@progbits
++foo: .long 25
++ .text
++ movl %gs:0, %eax
++ leal foo@TLSGD(,%ebx,1), %eax
++ leal foo@TLSLDM(%ebx), %eax
++ leal foo@DTPOFF(%eax), %edx
++ movl foo@GOTTPOFF(%ebx), %eax
++ subl foo@GOTTPOFF(%ebx), %eax
++ movl $foo@TPOFF, %eax
++ subl $foo@TPOFF, %eax
++ leal foo@NTPOFF(%ecx), %eax'
++ tls_first_major=2
++ tls_first_minor=13
++ ;;
++ ia64-*-*)
++ conftest_s='
++ .section ".tdata","awT",@progbits
++foo: data8 25
++ .text
++ addl r16 = @ltoff(@dtpmod(foo#)), gp
++ addl r17 = @ltoff(@dtprel(foo#)), gp
++ addl r18 = @ltoff(@tprel(foo#)), gp
++ addl r19 = @dtprel(foo#), gp
++ adds r21 = @dtprel(foo#), r13
++ movl r23 = @dtprel(foo#)
++ addl r20 = @tprel(foo#), gp
++ adds r22 = @tprel(foo#), r13
++ movl r24 = @tprel(foo#)'
++ tls_first_major=2
++ tls_first_minor=13
++ ;;
++esac
++if test -z "$tls_first_major"; then
++ :
++elif test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
++then
++ if test "$gcc_cv_gas_major_version" -eq "$tls_first_major" \
++ -a "$gcc_cv_gas_minor_version" -ge "$tls_first_minor" \
++ -o "$gcc_cv_gas_major_version" -gt "$tls_first_major"; then
++ gcc_cv_as_tls=yes
++ fi
++elif test x$gcc_cv_as != x; then
++ echo "$conftest_s" > conftest.s
++ if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
++ then
++ gcc_cv_as_tls=yes
++ fi
++ rm -f conftest.s conftest.o
++fi
++if test "$gcc_cv_as_tls" = yes; then
++ cat >> confdefs.h <<\EOF
++#define HAVE_AS_TLS 1
++EOF
++
++fi
++echo "$ac_t""$gcc_cv_as_tls" 1>&6
++
+ case "$target" in
+ # All TARGET_ABI_OSF targets.
+ alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*)
+--- gcc/output.h.jj Wed Jun 19 19:33:50 2002
++++ gcc/output.h Wed Jun 19 19:33:52 2002
+@@ -514,7 +514,8 @@ extern void no_asm_to_stream PARAMS ((FI
+ #define SECTION_STRINGS 0x10000 /* contains zero terminated strings without
+ embedded zeros */
+ #define SECTION_OVERRIDE 0x20000 /* allow override of default flags */
+-#define SECTION_MACH_DEP 0x40000 /* subsequent bits reserved for target */
++#define SECTION_TLS 0x40000 /* contains thread-local storage */
++#define SECTION_MACH_DEP 0x80000 /* subsequent bits reserved for target */
+
+ extern unsigned int get_named_section_flags PARAMS ((const char *));
+ extern bool set_named_section_flags PARAMS ((const char *, unsigned int));
+--- gcc/print-tree.c.jj Mon Mar 18 23:19:57 2002
++++ gcc/print-tree.c Wed Jun 19 19:33:52 2002
+@@ -363,6 +363,8 @@ print_node (file, prefix, node, indent)
+
+ if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
+ fputs (" in-text-section", file);
++ if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL (node))
++ fputs (" thread-local", file);
+
+ if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
+ fputs (" transparent-union", file);
+--- gcc/target-def.h.jj Tue Feb 12 16:19:14 2002
++++ gcc/target-def.h Wed Jun 19 19:33:52 2002
+@@ -98,6 +98,10 @@ Foundation, 59 Temple Place - Suite 330,
+ #define TARGET_HAVE_NAMED_SECTIONS false
+ #endif
+
++#ifndef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS false
++#endif
++
+ #ifndef TARGET_ASM_EXCEPTION_SECTION
+ #define TARGET_ASM_EXCEPTION_SECTION default_exception_section
+ #endif
+@@ -194,9 +198,10 @@ Foundation, 59 Temple Place - Suite 330,
+ TARGET_INIT_BUILTINS, \
+ TARGET_EXPAND_BUILTIN, \
+ TARGET_SECTION_TYPE_FLAGS, \
++ TARGET_CANNOT_MODIFY_JUMPS_P, \
+ TARGET_HAVE_NAMED_SECTIONS, \
+ TARGET_HAVE_CTORS_DTORS, \
+- TARGET_CANNOT_MODIFY_JUMPS_P \
++ TARGET_HAVE_TLS \
+ }
+
+ #include "hooks.h"
+--- gcc/target.h.jj Tue Feb 12 16:19:14 2002
++++ gcc/target.h Wed Jun 19 19:33:52 2002
+@@ -178,6 +178,10 @@ struct gcc_target
+ /* ??? Should be merged with SELECT_SECTION and UNIQUE_SECTION. */
+ unsigned int (* section_type_flags) PARAMS ((tree, const char *, int));
+
++ /* True if new jumps cannot be created, to replace existing ones or
++ not, at the current point in the compilation. */
++ bool (* cannot_modify_jumps_p) PARAMS ((void));
++
+ /* True if arbitrary sections are supported. */
+ bool have_named_sections;
+
+@@ -185,9 +189,8 @@ struct gcc_target
+ false if we're using collect2 for the job. */
+ bool have_ctors_dtors;
+
+- /* True if new jumps cannot be created, to replace existing ones or
+- not, at the current point in the compilation. */
+- bool (* cannot_modify_jumps_p) PARAMS ((void));
++ /* True if thread-local storage is supported. */
++ bool have_tls;
+ };
+
+ extern struct gcc_target targetm;
+--- gcc/toplev.c.jj Thu May 30 11:08:44 2002
++++ gcc/toplev.c Wed Jun 19 19:33:52 2002
+@@ -682,12 +682,15 @@ int flag_shared_data;
+ int flag_delayed_branch;
+
+ /* Nonzero if we are compiling pure (sharable) code.
+- Value is 1 if we are doing reasonable (i.e. simple
+- offset into offset table) pic. Value is 2 if we can
+- only perform register offsets. */
++ Value is 1 if we are doing "small" pic; value is 2 if we're doing
++ "large" pic. */
+
+ int flag_pic;
+
++/* Set to the default thread-local storage (tls) model to use. */
++
++enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
++
+ /* Nonzero means generate extra code for exception handling and enable
+ exception handling. */
+
+@@ -3609,6 +3612,7 @@ display_help ()
+ printf (_(" -finline-limit=<number> Limits the size of inlined functions to <number>\n"));
+ printf (_(" -fmessage-length=<number> Limits diagnostics messages lengths to <number> characters per line. 0 suppresses line-wrapping\n"));
+ printf (_(" -fdiagnostics-show-location=[once | every-line] Indicates how often source location information should be emitted, as prefix, at the beginning of diagnostics when line-wrapping\n"));
++ printf (_(" -ftls-model=[global-dynamic | local-dynamic | initial-exec | local-exec] Indicates the default thread-local storage code generation model\n"));
+
+ for (i = ARRAY_SIZE (f_options); i--;)
+ {
+@@ -3887,6 +3891,19 @@ decode_f_option (arg)
+ MAX_INLINE_INSNS);
+ set_param_value ("max-inline-insns", val);
+ }
++ else if ((option_value = skip_leading_substring (arg, "tls-model=")))
++ {
++ if (strcmp (option_value, "global-dynamic") == 0)
++ flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
++ else if (strcmp (option_value, "local-dynamic") == 0)
++ flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
++ else if (strcmp (option_value, "initial-exec") == 0)
++ flag_tls_default = TLS_MODEL_INITIAL_EXEC;
++ else if (strcmp (option_value, "local-exec") == 0)
++ flag_tls_default = TLS_MODEL_LOCAL_EXEC;
++ else
++ warning ("`%s': unknown tls-model option", arg - 2);
++ }
+ #ifdef INSN_SCHEDULING
+ else if ((option_value = skip_leading_substring (arg, "sched-verbose=")))
+ fix_sched_param ("verbose", option_value);
+--- gcc/tree.c.jj Sun Apr 28 23:20:20 2002
++++ gcc/tree.c Wed Jun 19 19:33:52 2002
+@@ -1510,12 +1510,13 @@ staticp (arg)
+ case FUNCTION_DECL:
+ /* Nested functions aren't static, since taking their address
+ involves a trampoline. */
+- return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+- && ! DECL_NON_ADDR_CONST_P (arg);
++ return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
++ && ! DECL_NON_ADDR_CONST_P (arg));
+
+ case VAR_DECL:
+- return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+- && ! DECL_NON_ADDR_CONST_P (arg);
++ return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
++ && ! DECL_THREAD_LOCAL (arg)
++ && ! DECL_NON_ADDR_CONST_P (arg));
+
+ case CONSTRUCTOR:
+ return TREE_STATIC (arg);
+--- gcc/tree.h.jj Wed Jun 19 19:33:50 2002
++++ gcc/tree.h Wed Jun 19 19:33:52 2002
+@@ -1614,6 +1614,10 @@ struct tree_type
+ /* In a FUNCTION_DECL, nonzero if the function cannot be inlined. */
+ #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
+
++/* In a VAR_DECL, nonzero if the data should be allocated from
++ thread-local storage. */
++#define DECL_THREAD_LOCAL(NODE) (VAR_DECL_CHECK (NODE)->decl.thread_local_flag)
++
+ /* In a FUNCTION_DECL, the saved representation of the body of the
+ entire function. Usually a COMPOUND_STMT, but in C++ this may also
+ be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK. */
+@@ -1792,7 +1796,8 @@ struct tree_decl
+ unsigned non_addressable : 1;
+ unsigned user_align : 1;
+ unsigned uninlinable : 1;
+- /* Three unused bits. */
++ unsigned thread_local_flag : 1;
++ /* Two unused bits. */
+
+ unsigned lang_flag_0 : 1;
+ unsigned lang_flag_1 : 1;
+--- gcc/varasm.c.jj Wed Jun 19 19:33:51 2002
++++ gcc/varasm.c Wed Jun 19 19:33:52 2002
+@@ -1599,14 +1599,24 @@ assemble_variable (decl, top_level, at_e
+
+ /* Handle uninitialized definitions. */
+
+- if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+- /* If the target can't output uninitialized but not common global data
+- in .bss, then we have to use .data. */
+-#if ! defined ASM_EMIT_BSS
+- && DECL_COMMON (decl)
++ /* If the decl has been given an explicit section name, then it
++ isn't common, and shouldn't be handled as such. */
++ if (DECL_SECTION_NAME (decl) || dont_output_data)
++ ;
++ /* We don't implement common thread-local data at present. */
++ else if (DECL_THREAD_LOCAL (decl))
++ {
++ if (DECL_COMMON (decl))
++ sorry ("thread-local COMMON data not implemented");
++ }
++#ifndef ASM_EMIT_BSS
++ /* If the target can't output uninitialized but not common global data
++ in .bss, then we have to use .data. */
++ else if (!DECL_COMMON (decl))
++ ;
+ #endif
+- && DECL_SECTION_NAME (decl) == NULL_TREE
+- && ! dont_output_data)
++ else if (DECL_INITIAL (decl) == 0
++ || DECL_INITIAL (decl) == error_mark_node)
+ {
+ unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ unsigned HOST_WIDE_INT rounded = size;
+@@ -5324,14 +5334,22 @@ default_section_type_flags (decl, name,
+ if (decl && DECL_ONE_ONLY (decl))
+ flags |= SECTION_LINKONCE;
+
++ if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++ flags |= SECTION_TLS | SECTION_WRITE;
++
+ if (strcmp (name, ".bss") == 0
+ || strncmp (name, ".bss.", 5) == 0
+ || strncmp (name, ".gnu.linkonce.b.", 16) == 0
+ || strcmp (name, ".sbss") == 0
+ || strncmp (name, ".sbss.", 6) == 0
+- || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
++ || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
++ || strcmp (name, ".tbss") == 0)
+ flags |= SECTION_BSS;
+
++ if (strcmp (name, ".tdata") == 0
++ || strcmp (name, ".tbss") == 0)
++ flags |= SECTION_TLS;
++
+ return flags;
+ }
+
+@@ -5374,6 +5392,8 @@ default_elf_asm_named_section (name, fla
+ *f++ = 'M';
+ if (flags & SECTION_STRINGS)
+ *f++ = 'S';
++ if (flags & SECTION_TLS)
++ *f++ = 'T';
+ *f = '\0';
+
+ if (flags & SECTION_BSS)
--- /dev/null
+2002-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ * expr.c (expand_expr) [ADDR_EXPR]: Force addresses of thread-local
+ variables into pseudo.
+
+ * gcc.dg/tls/opt-1.c: New test.
+
+--- gcc/testsuite/gcc.dg/tls/opt-1.c.jj 2002-07-30 13:57:33.000000000 +0200
++++ gcc/testsuite/gcc.dg/tls/opt-1.c 2002-07-30 13:56:40.000000000 +0200
+@@ -0,0 +1,28 @@
++/* { dg-do compile } */
++/* { dg-options "-O2 -fPIC" } */
++/* { dg-options "-O2 -fPIC -mcpu=i686" { target i?86-*-* } } */
++
++extern __thread int thr;
++
++static int x;
++
++static void
++bar (void)
++{
++ x = 1;
++}
++
++static void
++#ifdef __i386__
++__attribute__ ((regparm (3)))
++#endif
++foo (const char *x, void *y, int *z)
++{
++ bar ();
++}
++
++void
++test (const char *x, void *y)
++{
++ foo (x, y, &thr);
++}
+--- gcc/expr.c.jj 2002-07-30 12:49:43.000000000 +0200
++++ gcc/expr.c 2002-07-30 20:18:36.000000000 +0200
+@@ -8833,7 +8833,12 @@ expand_expr (exp, target, tmode, modifie
+ op0 = force_operand (XEXP (op0, 0), target);
+ }
+
+- if (flag_force_addr
++ if ((flag_force_addr
++ || (TREE_CODE (TREE_OPERAND (exp, 0)) == VAR_DECL
++ && DECL_THREAD_LOCAL (TREE_OPERAND (exp, 0))
++ && ! memory_address_p (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp,
++ 0))),
++ op0)))
+ && GET_CODE (op0) != REG
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
--- /dev/null
+2002-08-06 Aldy Hernandez <aldyh@redhat.com>
+
+ * c-decl.c (duplicate_decls): Error out for incompatible TLS
+ declarations.
+
+ * testsuite/gcc.dg/tls/diag-3.c: New.
+
+*** gcc/c-decl.c 1 Aug 2002 06:20:30 -0000 1.344
+--- gcc/c-decl.c 7 Aug 2002 01:01:55 -0000
+*************** duplicate_decls (newdecl, olddecl, diffe
+*** 1400,1405 ****
+--- 1400,1419 ----
+ }
+ error_with_decl (olddecl, "previous declaration of `%s'");
+ }
++ /* TLS cannot follow non-TLS declaration. */
++ else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
++ && !DECL_THREAD_LOCAL (olddecl) && DECL_THREAD_LOCAL (newdecl))
++ {
++ error_with_decl (newdecl, "thread-local declaration of `%s' follows non thread-local declaration");
++ error_with_decl (olddecl, "previous declaration of `%s'");
++ }
++ /* non-TLS declaration cannot follow TLS declaration. */
++ else if (TREE_CODE (olddecl) == VAR_DECL && TREE_CODE (newdecl) == VAR_DECL
++ && DECL_THREAD_LOCAL (olddecl) && !DECL_THREAD_LOCAL (newdecl))
++ {
++ error_with_decl (newdecl, "non thread-local declaration of `%s' follows thread-local declaration");
++ error_with_decl (olddecl, "previous declaration of `%s'");
++ }
+ else
+ {
+ errmsg = redeclaration_error_message (newdecl, olddecl);
+*** gcc/testsuite/gcc.dg/tls/diag-3.c 1 Jan 1970 00:00:00 -0000
+--- gcc/testsuite/gcc.dg/tls/diag-3.c 7 Aug 2002 01:01:55 -0000
+***************
+*** 0 ****
+--- 1,10 ----
++ /* Report invalid extern and __thread combinations. */
++
++ extern int j; /* { dg-error "previous declaration" } */
++ __thread int j; /* { dg-error "thread-local declaration" } */
++
++ extern __thread int i; /* { dg-error "previous declaration" } */
++ int i; /* { dg-error "non thread-local" } */
++
++ extern __thread int k; /* This is fine. */
++ __thread int k;
+
--- /dev/null
+2002-05-22 Richard Henderson <rth@redhat.com>
+
+ * varasm.c (default_section_type_flags): Handle tls data and
+ default sections.
+
+ * gcc.dg/tls/section-1.c: New test.
+
+2002-03-15 Jason Merrill <jason@redhat.com>
+
+ * varasm.c (assemble_variable): Call resolve_unique_section before
+ checking DECL_SECTION_NAME.
+
+--- gcc/testsuite/gcc.dg/tls/section-1.c.jj 2002-08-08 16:11:55.000000000 +0200
++++ gcc/testsuite/gcc.dg/tls/section-1.c 2002-08-08 16:19:08.000000000 +0200
+@@ -0,0 +1,11 @@
++/* Verify that we get errors for trying to put TLS data in
++ sections which can't work. */
++
++#define A(X) __attribute__((section(X)))
++
++__thread int i A("foo"); /* Ok */
++
++__thread int j A(".data"); /* { dg-error "causes a section type conflict" "conflict with .data section" { xfail *-*-* } } */
++
++int k A("bar");
++__thread int l A("bar"); /* { dg-error "causes a section type conflict" "conflict with user-defined section" } */
+--- gcc/varasm.c.jj 2002-08-01 20:58:53.000000000 +0200
++++ gcc/varasm.c 2002-08-08 16:10:15.000000000 +0200
+@@ -1597,6 +1597,13 @@ assemble_variable (decl, top_level, at_e
+ if (TREE_PUBLIC (decl))
+ maybe_assemble_visibility (decl);
+
++ /* Output any data that we will need to use the address of. */
++ if (DECL_INITIAL (decl) == error_mark_node)
++ reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
++ else if (DECL_INITIAL (decl))
++ reloc = output_addressed_constants (DECL_INITIAL (decl));
++ resolve_unique_section (decl, reloc, flag_data_sections);
++
+ /* Handle uninitialized definitions. */
+
+ /* If the decl has been given an explicit section name, then it
+@@ -1652,14 +1659,7 @@ assemble_variable (decl, top_level, at_e
+ if (TREE_PUBLIC (decl) && DECL_NAME (decl))
+ globalize_decl (decl);
+
+- /* Output any data that we will need to use the address of. */
+- if (DECL_INITIAL (decl) == error_mark_node)
+- reloc = contains_pointers_p (TREE_TYPE (decl)) ? 3 : 0;
+- else if (DECL_INITIAL (decl))
+- reloc = output_addressed_constants (DECL_INITIAL (decl));
+-
+ /* Switch to the appropriate section. */
+- resolve_unique_section (decl, reloc, flag_data_sections);
+ variable_section (decl, reloc);
+
+ /* dbxout.c needs to know this. */
+@@ -5343,11 +5343,14 @@ default_section_type_flags (decl, name,
+ || strcmp (name, ".sbss") == 0
+ || strncmp (name, ".sbss.", 6) == 0
+ || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
+- || strcmp (name, ".tbss") == 0)
++ || strcmp (name, ".tbss") == 0
++ || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ flags |= SECTION_BSS;
+
+ if (strcmp (name, ".tdata") == 0
+- || strcmp (name, ".tbss") == 0)
++ || strcmp (name, ".tbss") == 0
++ || strncmp (name, ".gnu.linkonce.td.", 17) == 0
++ || strncmp (name, ".gnu.linkonce.tb.", 17) == 0)
+ flags |= SECTION_TLS;
+
+ return flags;
--- /dev/null
+2002-08-08 Jakub Jelinek <jakub@redhat.com>
+
+ * config/i386/i386.c (legitimate_constant_p): UNSPEC_TP is not
+ legitimate constant.
+ (legitimate_pic_operand_p): Neither pic operand.
+ (legitimate_address_p): But legitimate address.
+ (get_thread_pointer): Generate MEM/u instead of CONST around
+ UNSPEC_TP.
+ (print_operand): Remove printing of UNSPEC_TP.
+ (print_operand_address): And print it here.
+
+ * gcc.dg/tls/opt-2.c: New test.
+
+--- gcc/config/i386/i386.c.jj 2002-08-07 22:18:39.000000000 +0200
++++ gcc/config/i386/i386.c 2002-08-08 18:18:18.000000000 +0200
+@@ -4850,8 +4850,6 @@ legitimate_constant_p (x)
+ {
+ case UNSPEC_TPOFF:
+ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
+- case UNSPEC_TP:
+- return true;
+ default:
+ return false;
+ }
+@@ -4914,8 +4912,6 @@ legitimate_pic_operand_p (x)
+ {
+ case UNSPEC_TPOFF:
+ return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
+- case UNSPEC_TP:
+- return true;
+ default:
+ return false;
+ }
+@@ -5054,6 +5050,13 @@ legitimate_address_p (mode, addr, strict
+ debug_rtx (addr);
+ }
+
++ if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP)
++ {
++ if (TARGET_DEBUG_ADDR)
++ fprintf (stderr, "Success.\n");
++ return TRUE;
++ }
++
+ if (ix86_decompose_address (addr, &parts) <= 0)
+ {
+ reason = "decomposition failed";
+@@ -5521,7 +5524,9 @@ get_thread_pointer ()
+ rtx tp;
+
+ tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
+- tp = gen_rtx_CONST (Pmode, tp);
++ tp = gen_rtx_MEM (Pmode, tp);
++ RTX_UNCHANGING_P (tp) = 1;
++ set_mem_alias_set (tp, ix86_GOT_alias_set ());
+ tp = force_reg (Pmode, tp);
+
+ return tp;
+@@ -6611,17 +6615,6 @@ print_operand (file, x, code)
+ fprintf (file, "%s", dstr);
+ }
+
+- else if (GET_CODE (x) == CONST
+- && GET_CODE (XEXP (x, 0)) == UNSPEC
+- && XINT (XEXP (x, 0), 1) == UNSPEC_TP)
+- {
+- if (ASSEMBLER_DIALECT == ASM_INTEL)
+- fputs ("DWORD PTR ", file);
+- if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
+- putc ('%', file);
+- fputs ("gs:0", file);
+- }
+-
+ else
+ {
+ if (code != 'P')
+@@ -6660,6 +6653,16 @@ print_operand_address (file, addr)
+ rtx base, index, disp;
+ int scale;
+
++ if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP)
++ {
++ if (ASSEMBLER_DIALECT == ASM_INTEL)
++ fputs ("DWORD PTR ", file);
++ if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
++ putc ('%', file);
++ fputs ("gs:0", file);
++ return;
++ }
++
+ if (! ix86_decompose_address (addr, &parts))
+ abort ();
+
+--- gcc/testsuite/gcc.dg/tls/opt-2.c.jj 2002-08-08 18:36:32.000000000 +0200
++++ gcc/testsuite/gcc.dg/tls/opt-2.c 2002-08-08 18:34:44.000000000 +0200
+@@ -0,0 +1,53 @@
++/* This testcase generated invalid assembly on IA-32,
++ since %gs:0 memory load was not exposed to the compiler
++ as memory load and mem to mem moves are not possible
++ on IA-32. */
++/* { dg-do link } */
++/* { dg-options "-O2 -ftls-model=initial-exec" } */
++/* { dg-options "-O2 -ftls-model=initial-exec -march=i686" { target i?86-*-* } } */
++
++__thread int thr;
++
++struct A
++{
++ unsigned int a, b, c, d, e;
++};
++
++int bar (int x, unsigned long y, void *z)
++{
++ return 0;
++}
++
++int
++foo (int x, int y, const struct A *z)
++{
++ struct A b;
++ int d;
++
++ b = *z;
++ d = bar (x, y, &b);
++ if (d == 0 && y == 0x5402)
++ {
++ int e = thr;
++ d = bar (x, 0x5401, &b);
++ if (d)
++ {
++ thr = e;
++ d = 0;
++ }
++ else if ((z->c & 0600) != (b.c & 0600)
++ || ((z->c & 060) && ((z->c & 060) != (b.c & 060))))
++ {
++ thr = 22;
++ d = -1;
++ }
++ }
++
++ return d;
++}
++
++int main (void)
++{
++ foo (1, 2, 0);
++ return 0;
++}
--- /dev/null
+2002-08-08 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/ext/typeof2.C: New test.
+ * gcc.dg/typeof-1.c: New test.
+ * gcc.dg/typeof-2.c: New test.
+
+--- gcc/testsuite/g++.dg/ext/typeof2.C.jj 2002-08-08 14:24:56.000000000 +0200
++++ gcc/testsuite/g++.dg/ext/typeof2.C 2002-08-08 14:24:39.000000000 +0200
+@@ -0,0 +1,29 @@
++// Test typeof with __asm redirection
++// { dg-do compile }
++// { dg-options "-O2" }
++
++extern "C" {
++ extern int foo1;
++ extern int foo1 __asm ("bar1");
++ int foo1 = 1;
++
++ extern int foo2 (int);
++ extern int foo2 (int) __asm ("bar2");
++ int foo2 (int x)
++ {
++ return x;
++ }
++
++ extern int foo3;
++ extern __typeof (foo3) foo3 __asm ("bar3");
++ int foo3 = 1;
++
++ extern int foo4 (int);
++ extern __typeof (foo4) foo4 __asm ("bar4");
++ int foo4 (int x)
++ {
++ return x;
++ }
++}
++
++// { dg-final { scan-assembler-not "foo" } }
+--- gcc/testsuite/gcc.dg/typeof-1.c.jj 2002-08-08 14:26:18.000000000 +0200
++++ gcc/testsuite/gcc.dg/typeof-1.c 2002-08-08 14:26:06.000000000 +0200
+@@ -0,0 +1,27 @@
++/* Test typeof with __asm redirection. */
++/* { dg-do compile } */
++/* { dg-options "-O2" } */
++
++extern int foo1;
++extern int foo1 __asm ("bar1");
++int foo1 = 1;
++
++extern int foo2 (int);
++extern int foo2 (int) __asm ("bar2");
++int foo2 (int x)
++{
++ return x;
++}
++
++extern int foo3;
++extern __typeof (foo3) foo3 __asm ("bar3");
++int foo3 = 1;
++
++extern int foo4 (int);
++extern __typeof (foo4) foo4 __asm ("bar4");
++int foo4 (int x)
++{
++ return x;
++}
++
++// { dg-final { scan-assembler-not "foo" } }
+--- gcc/testsuite/gcc.dg/typeof-2.c.jj 2002-08-08 20:42:33.000000000 +0200
++++ gcc/testsuite/gcc.dg/typeof-2.c 2002-08-08 20:47:53.000000000 +0200
+@@ -0,0 +1,29 @@
++/* Test typeof with __asm redirection. */
++/* { dg-do compile } */
++/* { dg-options "-O2" } */
++
++extern int foo1 (int x) __asm ("baz1");
++int bar1 (int x) { return x; }
++extern __typeof (bar1) foo1 __attribute ((weak, alias ("bar1")));
++
++extern int foo2 (int x) __attribute__ ((const));
++extern __typeof (foo2) foo2 __asm ("baz2");
++int bar2 (int x)
++{
++ return foo2 (x) + foo2 (x) + foo2 (x) + foo2 (x) + foo2 (x) + foo2 (x);
++}
++
++extern int foo3 (int x);
++extern __typeof (foo3) foo3 __asm ("baz3");
++int bar3 (int x)
++{
++ return foo3 (x) + foo3 (x) + foo3 (x) + foo3 (x) + foo3 (x) + foo3 (x);
++}
++
++// { dg-final { scan-assembler-not "foo1" } }
++// { dg-final { scan-assembler "baz1" } }
++// { dg-final { scan-assembler-not "foo2" } }
++// { dg-final { scan-assembler "baz2" } }
++// { dg-final { scan-assembler-not "baz2.*baz2.*baz2.*baz2.*baz2.*baz2" } }
++// { dg-final { scan-assembler-not "foo3" } }
++// { dg-final { scan-assembler "baz3.*baz3.*baz3.*baz3.*baz3.*baz3" } }
--- /dev/null
+2002-08-12 Alexandre Oliva <aoliva@redhat.com>
+
+ * c-tree.h (skip_evaluation): Move declaration...
+ * c-common.h: ... here.
+ * c-typeck.c (build_external_ref): Don't assemble_external nor
+ mark a tree as used if skip_evaluation is set.
+ * c-parse.in (typeof): New non-terminal to set skip_evaluation
+ around TYPEOF.
+ (typespec_nonreserved_nonattr): Use it.
+
+--- gcc/cp/parse.y.jj 2002-05-02 12:14:49.000000000 +0200
++++ gcc/cp/parse.y 2002-08-22 23:28:34.000000000 +0200
+@@ -1255,16 +1255,20 @@ unary_expr:
+ /* Refer to the address of a label as a pointer. */
+ | ANDAND identifier
+ { $$ = finish_label_address_expr ($2); }
+- | SIZEOF unary_expr %prec UNARY
+- { $$ = finish_sizeof ($2); }
+- | SIZEOF '(' type_id ')' %prec HYPERUNARY
++ | sizeof unary_expr %prec UNARY
++ { $$ = finish_sizeof ($2);
++ skip_evaluation--; }
++ | sizeof '(' type_id ')' %prec HYPERUNARY
+ { $$ = finish_sizeof (groktypename ($3.t));
+- check_for_new_type ("sizeof", $3); }
+- | ALIGNOF unary_expr %prec UNARY
+- { $$ = finish_alignof ($2); }
+- | ALIGNOF '(' type_id ')' %prec HYPERUNARY
+- { $$ = finish_alignof (groktypename ($3.t));
+- check_for_new_type ("alignof", $3); }
++ check_for_new_type ("sizeof", $3);
++ skip_evaluation--; }
++ | alignof unary_expr %prec UNARY
++ { $$ = finish_alignof ($2);
++ skip_evaluation--; }
++ | alignof '(' type_id ')' %prec HYPERUNARY
++ { $$ = finish_alignof (groktypename ($3.t));
++ check_for_new_type ("alignof", $3);
++ skip_evaluation--; }
+
+ /* The %prec EMPTY's here are required by the = init initializer
+ syntax extension; see below. */
+@@ -1989,6 +1993,18 @@ reserved_typespecquals:
+ { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+ ;
+
++sizeof:
++ SIZEOF { skip_evaluation++; }
++ ;
++
++alignof:
++ ALIGNOF { skip_evaluation++; }
++ ;
++
++typeof:
++ TYPEOF { skip_evaluation++; }
++ ;
++
+ /* A typespec (but not a type qualifier).
+ Once we have seen one of these in a declaration,
+ if a typedef name appears then it is being redeclared. */
+@@ -2000,12 +2016,14 @@ typespec:
+ { $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
+ | complete_type_name
+ { $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
+- | TYPEOF '(' expr ')'
++ | typeof '(' expr ')'
+ { $$.t = finish_typeof ($3);
+- $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
+- | TYPEOF '(' type_id ')'
++ $$.new_type_flag = 0; $$.lookups = NULL_TREE;
++ skip_evaluation--; }
++ | typeof '(' type_id ')'
+ { $$.t = groktypename ($3.t);
+- $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
++ $$.new_type_flag = 0; $$.lookups = NULL_TREE;
++ skip_evaluation--; }
+ | SIGOF '(' expr ')'
+ { tree type = TREE_TYPE ($3);
+
+--- gcc/cp/decl2.c.jj 2002-07-27 01:31:05.000000000 +0200
++++ gcc/cp/decl2.c 2002-08-22 23:24:11.000000000 +0200
+@@ -5179,7 +5179,8 @@ mark_used (decl)
+ TREE_USED (decl) = 1;
+ if (processing_template_decl)
+ return;
+- assemble_external (decl);
++ if (!skip_evaluation)
++ assemble_external (decl);
+
+ /* Is it a synthesized method that needs to be synthesized? */
+ if (TREE_CODE (decl) == FUNCTION_DECL
+--- gcc/c-tree.h.jj 2002-04-02 23:17:23.000000000 +0200
++++ gcc/c-tree.h 2002-08-22 23:24:34.000000000 +0200
+@@ -287,11 +287,6 @@ extern int current_function_returns_null
+
+ extern int current_function_returns_abnormally;
+
+-/* Nonzero means the expression being parsed will never be evaluated.
+- This is a count, since unevaluated expressions can nest. */
+-
+-extern int skip_evaluation;
+-
+ /* Nonzero means `$' can be in an identifier. */
+
+ extern int dollars_in_ident;
+--- gcc/c-common.h.jj 2002-04-17 15:34:36.000000000 +0200
++++ gcc/c-common.h 2002-08-22 23:24:11.000000000 +0200
+@@ -464,6 +464,11 @@ extern int warn_conversion;
+
+ extern int warn_long_long;
+
++/* Nonzero means the expression being parsed will never be evaluated.
++ This is a count, since unevaluated expressions can nest. */
++
++extern int skip_evaluation;
++
+ /* C types are partitioned into three subsets: object, function, and
+ incomplete types. */
+ #define C_TYPE_OBJECT_P(type) \
+--- gcc/c-typeck.c.jj 2002-03-23 12:02:51.000000000 +0100
++++ gcc/c-typeck.c 2002-08-22 23:24:11.000000000 +0200
+@@ -1493,7 +1493,8 @@ build_external_ref (id, fun)
+ if (TREE_TYPE (ref) == error_mark_node)
+ return error_mark_node;
+
+- assemble_external (ref);
++ if (!skip_evaluation)
++ assemble_external (ref);
+ TREE_USED (ref) = 1;
+
+ if (TREE_CODE (ref) == CONST_DECL)
+--- gcc/c-parse.in.jj 2002-04-17 15:34:46.000000000 +0200
++++ gcc/c-parse.in 2002-08-22 23:24:11.000000000 +0200
+@@ -534,6 +534,10 @@ alignof:
+ ALIGNOF { skip_evaluation++; }
+ ;
+
++typeof:
++ TYPEOF { skip_evaluation++; }
++ ;
++
+ cast_expr:
+ unary_expr
+ | '(' typename ')' cast_expr %prec UNARY
+@@ -1376,10 +1380,10 @@ ifobjc
+ | non_empty_protocolrefs
+ { $$ = get_object_reference ($1); }
+ end ifobjc
+- | TYPEOF '(' expr ')'
+- { $$ = TREE_TYPE ($3); }
+- | TYPEOF '(' typename ')'
+- { $$ = groktypename ($3); }
++ | typeof '(' expr ')'
++ { skip_evaluation--; $$ = TREE_TYPE ($3); }
++ | typeof '(' typename ')'
++ { skip_evaluation--; $$ = groktypename ($3); }
+ ;
+
+ /* typespec_nonreserved_attr does not exist. */