From: aflinta Date: Mon, 16 Sep 2002 00:01:29 +0000 (+0000) Subject: - patches from RH X-Git-Tag: STABLE~3 X-Git-Url: http://git.pld-linux.org/?a=commitdiff_plain;h=5384b7285e4366ba9056e689d09612f67e8a0b83;hp=d8e09e00e54fe4dea33d2b0c8fb71b80aebec182;p=packages%2Fgcc.git - patches from RH Changed files: gcc32-ada-link.patch -> 1.1 gcc32-attr-visibility.patch -> 1.1 gcc32-attr-visibility2.patch -> 1.1 gcc32-attr-visibility3.patch -> 1.1 gcc32-attr-visibility4.patch -> 1.1 gcc32-attr-visibility5.patch -> 1.1 gcc32-boehm-gc-libs.patch -> 1.1 gcc32-bogus-inline.patch -> 1.1 gcc32-c++-nrv-test.patch -> 1.1 gcc32-c++-pretty_function.patch -> 1.1 gcc32-c++-tail-pad.patch -> 1.1 gcc32-c++-tail-pad2.patch -> 1.1 gcc32-c++-tsubst-asm.patch -> 1.1 gcc32-cfg-eh.patch -> 1.1 gcc32-debug-pr7241.patch -> 1.1 gcc32-doc-gcov.patch -> 1.1 gcc32-duplicate-decl.patch -> 1.1 gcc32-dwarf2-pr6381.patch -> 1.1 gcc32-dwarf2-pr6436-test.patch -> 1.1 gcc32-fde-merge-compat.patch -> 1.1 gcc32-fold-const-associate.patch -> 1.1 gcc32-fold-const2.patch -> 1.1 gcc32-hard-reg-sharing.patch -> 1.1 gcc32-hard-reg-sharing2.patch -> 1.1 gcc32-i386-default-momit-leaf-frame-pointer.patch -> 1.1 gcc32-i386-memtest-test.patch -> 1.1 gcc32-i386-no-default-momit-leaf-frame-pointer.patch -> 1.1 gcc32-i386-pic-label-thunk.patch -> 1.1 gcc32-i386-pr7242.patch -> 1.1 gcc32-i386-profile-olfp.patch -> 1.1 gcc32-inline-label.patch -> 1.1 gcc32-java-no-rpath.patch -> 1.1 gcc32-locale_in_ctype_members.patch -> 1.1 gcc32-locale_in_monetary_members.patch -> 1.1 gcc32-loop-prefetch.patch -> 1.1 gcc32-pr6842.patch -> 1.1 gcc32-rh69989.patch -> 1.1 gcc32-sparc-sll1.patch -> 1.1 gcc32-test-rh65771.patch -> 1.1 gcc32-test-rotate.patch -> 1.1 gcc32-tls-dwarf2.patch -> 1.1 gcc32-tls.patch -> 1.1 gcc32-tls2.patch -> 1.1 gcc32-tls3.patch -> 1.1 gcc32-tls4.patch -> 1.1 gcc32-tls5.patch -> 1.1 gcc32-typeof-asm.patch -> 1.1 gcc32-typeof-skip-eval.patch -> 1.1 --- diff --git a/gcc32-ada-link.patch b/gcc32-ada-link.patch new file mode 100644 index 0000000..dcf5016 --- /dev/null +++ b/gcc32-ada-link.patch @@ -0,0 +1,201 @@ +--- 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 diff --git a/gcc32-attr-visibility.patch b/gcc32-attr-visibility.patch new file mode 100644 index 0000000..51536d8 --- /dev/null +++ b/gcc32-attr-visibility.patch @@ -0,0 +1,283 @@ +2002-02-26 Jakub Jelinek + + * 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) ++{ ++} diff --git a/gcc32-attr-visibility2.patch b/gcc32-attr-visibility2.patch new file mode 100644 index 0000000..a36471b --- /dev/null +++ b/gcc32-attr-visibility2.patch @@ -0,0 +1,109 @@ +2002-03-06 Jakub Jelinek + + * config/i386/i386.h (REDO_SECTION_INFO_P): Define. + +2002-03-02 Richard Henderson + + * config/i386/i386.h (ENCODE_SECTION_INFO): MODULE_LOCAL_P applies + to functions as well. + +2002-03-02 Richard Henderson + + * 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; diff --git a/gcc32-attr-visibility3.patch b/gcc32-attr-visibility3.patch new file mode 100644 index 0000000..bc66ec9 --- /dev/null +++ b/gcc32-attr-visibility3.patch @@ -0,0 +1,35 @@ +2002-07-31 Jakub Jelinek + + * 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); diff --git a/gcc32-attr-visibility4.patch b/gcc32-attr-visibility4.patch new file mode 100644 index 0000000..eccfbb9 --- /dev/null +++ b/gcc32-attr-visibility4.patch @@ -0,0 +1,16 @@ +2002-08-23 Jakub Jelinek + + * 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. */ diff --git a/gcc32-attr-visibility5.patch b/gcc32-attr-visibility5.patch new file mode 100644 index 0000000..b76b661 --- /dev/null +++ b/gcc32-attr-visibility5.patch @@ -0,0 +1,24 @@ +2002-08-28 Jakub Jelinek + + * 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) diff --git a/gcc32-boehm-gc-libs.patch b/gcc32-boehm-gc-libs.patch new file mode 100644 index 0000000..fb58e1a --- /dev/null +++ b/gcc32-boehm-gc-libs.patch @@ -0,0 +1,192 @@ +--- 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 <&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 <&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 + diff --git a/gcc32-bogus-inline.patch b/gcc32-bogus-inline.patch new file mode 100644 index 0000000..1379cb4 --- /dev/null +++ b/gcc32-bogus-inline.patch @@ -0,0 +1,96 @@ +2001-10-12 Jakub Jelinek + + * 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(); ++} diff --git a/gcc32-c++-nrv-test.patch b/gcc32-c++-nrv-test.patch new file mode 100644 index 0000000..05cb6bd --- /dev/null +++ b/gcc32-c++-nrv-test.patch @@ -0,0 +1,120 @@ +2002-07-11 Jakub Jelinek + + * g++.dg/opt/nrv5.C: New test. + +2002-07-05 Jason Merrill + + * g++.dg/opt/nrv4.C: New test. + +2002-04-09 Jason Merrill + + * 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 . ++// { 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); ++} diff --git a/gcc32-c++-pretty_function.patch b/gcc32-c++-pretty_function.patch new file mode 100644 index 0000000..be1f5fc --- /dev/null +++ b/gcc32-c++-pretty_function.patch @@ -0,0 +1,170 @@ +2002-05-24 Jakub Jelinek + + 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 int ++bar (T) ++{ ++ return (assert (foo ()), 1); ++} ++ ++template<> int ++bar (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 int ++bar (T) ++{ ++ return (assert (foo ()), 1); ++} ++ ++template<> int ++bar (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 (); ++} diff --git a/gcc32-c++-tail-pad.patch b/gcc32-c++-tail-pad.patch new file mode 100644 index 0000000..c431981 --- /dev/null +++ b/gcc32-c++-tail-pad.patch @@ -0,0 +1,281 @@ +2002-08-22 Jason Merrill + + * 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); + } + + /* 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; diff --git a/gcc32-c++-tail-pad2.patch b/gcc32-c++-tail-pad2.patch new file mode 100644 index 0000000..e95c845 --- /dev/null +++ b/gcc32-c++-tail-pad2.patch @@ -0,0 +1,145 @@ +2002-08-06 Jason Merrill + + * 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 + + * 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); diff --git a/gcc32-c++-tsubst-asm.patch b/gcc32-c++-tsubst-asm.patch new file mode 100644 index 0000000..89964dd --- /dev/null +++ b/gcc32-c++-tsubst-asm.patch @@ -0,0 +1,19 @@ +2002-05-09 Jason Merrill + + * 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 I { ++public: ++ void f() { asm ("# mov %edi, %esi" ); } ++}; ++ ++int main () { ++ I x; ++ x.f(); ++} diff --git a/gcc32-cfg-eh.patch b/gcc32-cfg-eh.patch new file mode 100644 index 0000000..4d11138 --- /dev/null +++ b/gcc32-cfg-eh.patch @@ -0,0 +1,74 @@ +2002-05-28 Richard Henderson + + * 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 + + * 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" } } diff --git a/gcc32-debug-pr7241.patch b/gcc32-debug-pr7241.patch new file mode 100644 index 0000000..dbf172f --- /dev/null +++ b/gcc32-debug-pr7241.patch @@ -0,0 +1,21 @@ +2002-07-11 Jakub Jelinek + + 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")))) + { diff --git a/gcc32-doc-gcov.patch b/gcc32-doc-gcov.patch new file mode 100644 index 0000000..d7abc9e --- /dev/null +++ b/gcc32-doc-gcov.patch @@ -0,0 +1,72 @@ +2002-08-14 Nathan Sidwell + + * 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 diff --git a/gcc32-duplicate-decl.patch b/gcc32-duplicate-decl.patch new file mode 100644 index 0000000..ef913e2 --- /dev/null +++ b/gcc32-duplicate-decl.patch @@ -0,0 +1,17 @@ +2002-01-25 Jakub Jelinek + + * 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"; diff --git a/gcc32-dwarf2-pr6381.patch b/gcc32-dwarf2-pr6381.patch new file mode 100644 index 0000000..644a492 --- /dev/null +++ b/gcc32-dwarf2-pr6381.patch @@ -0,0 +1,18 @@ +2002-05-08 Jason Merrill + + * 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() {} diff --git a/gcc32-dwarf2-pr6436-test.patch b/gcc32-dwarf2-pr6436-test.patch new file mode 100644 index 0000000..18df889 --- /dev/null +++ b/gcc32-dwarf2-pr6436-test.patch @@ -0,0 +1,24 @@ +2002-04-30 Jakub Jelinek + + * 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; ++}; diff --git a/gcc32-fde-merge-compat.patch b/gcc32-fde-merge-compat.patch new file mode 100644 index 0000000..fec3650 --- /dev/null +++ b/gcc32-fde-merge-compat.patch @@ -0,0 +1,34 @@ +2001-10-31 Jakub Jelinek + + * 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) + { diff --git a/gcc32-fold-const-associate.patch b/gcc32-fold-const-associate.patch new file mode 100644 index 0000000..90a9f2b --- /dev/null +++ b/gcc32-fold-const-associate.patch @@ -0,0 +1,58 @@ +2002-08-05 Jakub Jelinek + + * 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))); diff --git a/gcc32-fold-const2.patch b/gcc32-fold-const2.patch new file mode 100644 index 0000000..9b3f35e --- /dev/null +++ b/gcc32-fold-const2.patch @@ -0,0 +1,15 @@ +2002-05-15 Jakub Jelinek + + * 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)) + { diff --git a/gcc32-hard-reg-sharing.patch b/gcc32-hard-reg-sharing.patch new file mode 100644 index 0000000..ffa155c --- /dev/null +++ b/gcc32-hard-reg-sharing.patch @@ -0,0 +1,631 @@ +2002-06-20 Jakub Jelinek + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 *)); + +@@ -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 (); + } + + /* 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; diff --git a/gcc32-hard-reg-sharing2.patch b/gcc32-hard-reg-sharing2.patch new file mode 100644 index 0000000..24a2a68 --- /dev/null +++ b/gcc32-hard-reg-sharing2.patch @@ -0,0 +1,17 @@ +2002-06-11 Richard Henderson + + * 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); + diff --git a/gcc32-i386-default-momit-leaf-frame-pointer.patch b/gcc32-i386-default-momit-leaf-frame-pointer.patch new file mode 100644 index 0000000..fb8e24b --- /dev/null +++ b/gcc32-i386-default-momit-leaf-frame-pointer.patch @@ -0,0 +1,75 @@ +2002-05-29 Richard Henderson + + * 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 diff --git a/gcc32-i386-memtest-test.patch b/gcc32-i386-memtest-test.patch new file mode 100644 index 0000000..93cded3 --- /dev/null +++ b/gcc32-i386-memtest-test.patch @@ -0,0 +1,31 @@ +2002-05-20 Jakub Jelinek + + * 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 */ ++/* { 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); ++} diff --git a/gcc32-i386-no-default-momit-leaf-frame-pointer.patch b/gcc32-i386-no-default-momit-leaf-frame-pointer.patch new file mode 100644 index 0000000..94befa8 --- /dev/null +++ b/gcc32-i386-no-default-momit-leaf-frame-pointer.patch @@ -0,0 +1,13 @@ +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. */ diff --git a/gcc32-i386-pic-label-thunk.patch b/gcc32-i386-pic-label-thunk.patch new file mode 100644 index 0000000..e0c11aa --- /dev/null +++ b/gcc32-i386-pic-label-thunk.patch @@ -0,0 +1,91 @@ +2002-06-04 Richard Henderson + Jakub Jelinek + + * 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; + } + ++#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 diff --git a/gcc32-i386-pr7242.patch b/gcc32-i386-pr7242.patch new file mode 100644 index 0000000..ebedafe --- /dev/null +++ b/gcc32-i386-pr7242.patch @@ -0,0 +1,16 @@ +2002-07-11 Jakub Jelinek + + 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:\ diff --git a/gcc32-i386-profile-olfp.patch b/gcc32-i386-profile-olfp.patch new file mode 100644 index 0000000..7e234f8 --- /dev/null +++ b/gcc32-i386-profile-olfp.patch @@ -0,0 +1,102 @@ +2002-05-30 Richard Henderson + + * 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) + { diff --git a/gcc32-inline-label.patch b/gcc32-inline-label.patch new file mode 100644 index 0000000..f8a455f --- /dev/null +++ b/gcc32-inline-label.patch @@ -0,0 +1,55 @@ +2002-08-07 Jakub Jelinek + + * 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 (); ++} diff --git a/gcc32-java-no-rpath.patch b/gcc32-java-no-rpath.patch new file mode 100644 index 0000000..2c21dec --- /dev/null +++ b/gcc32-java-no-rpath.patch @@ -0,0 +1,93 @@ +--- 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 diff --git a/gcc32-locale_in_ctype_members.patch b/gcc32-locale_in_ctype_members.patch new file mode 100644 index 0000000..eb862df --- /dev/null +++ b/gcc32-locale_in_ctype_members.patch @@ -0,0 +1,69 @@ +--- 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:: + 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:: + 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(&__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:: + 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(__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 diff --git a/gcc32-locale_in_monetary_members.patch b/gcc32-locale_in_monetary_members.patch new file mode 100644 index 0000000..0d396dd --- /dev/null +++ b/gcc32-locale_in_monetary_members.patch @@ -0,0 +1,59 @@ +--- 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(((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(((union { const char *__s; unsigned int __w; }){ __s: __nl_langinfo_l(_NL_NUMERIC_DECIMAL_POINT_WC, __cloc)}).__w); + _M_thousands_sep = static_cast(((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 + } + } diff --git a/gcc32-loop-prefetch.patch b/gcc32-loop-prefetch.patch new file mode 100644 index 0000000..205090f --- /dev/null +++ b/gcc32-loop-prefetch.patch @@ -0,0 +1,25 @@ +Wed Jul 10 19:12:41 CEST 2002 Janis Johnson + + * 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), diff --git a/gcc32-pr6842.patch b/gcc32-pr6842.patch new file mode 100644 index 0000000..905efaa --- /dev/null +++ b/gcc32-pr6842.patch @@ -0,0 +1,48 @@ +2002-05-31 Jakub Jelinek + + 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) diff --git a/gcc32-rh69989.patch b/gcc32-rh69989.patch new file mode 100644 index 0000000..e1e9f38 --- /dev/null +++ b/gcc32-rh69989.patch @@ -0,0 +1,215 @@ +2002-07-29 Jakub Jelinek + + * gcc.dg/20020729-1.c: New test. + +2002-05-17 Richard Sandiford + + * expr.c (force_operand): Fix reversed move. + +Sat May 4 13:20:54 CEST 2002 Jan Hubicka + + * 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; ++} diff --git a/gcc32-sparc-sll1.patch b/gcc32-sparc-sll1.patch new file mode 100644 index 0000000..e8e1104 --- /dev/null +++ b/gcc32-sparc-sll1.patch @@ -0,0 +1,95 @@ +2002-05-05 Jakub Jelinek + + * 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 diff --git a/gcc32-test-rh65771.patch b/gcc32-test-rh65771.patch new file mode 100644 index 0000000..1bc801c --- /dev/null +++ b/gcc32-test-rh65771.patch @@ -0,0 +1,93 @@ +2002-06-04 Jakub Jelinek + + * 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; ++ } ++ } ++} diff --git a/gcc32-test-rotate.patch b/gcc32-test-rotate.patch new file mode 100644 index 0000000..37e5f5c --- /dev/null +++ b/gcc32-test-rotate.patch @@ -0,0 +1,323 @@ +2002-05-08 Tom Rix + + * 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 ++ ++#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 ++ ++#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 ++ ++#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); ++} diff --git a/gcc32-tls-dwarf2.patch b/gcc32-tls-dwarf2.patch new file mode 100644 index 0000000..432f196 --- /dev/null +++ b/gcc32-tls-dwarf2.patch @@ -0,0 +1,337 @@ +2002-08-21 Richard Henderson + + * 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_"; + } +@@ -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 + } + diff --git a/gcc32-tls.patch b/gcc32-tls.patch new file mode 100644 index 0000000..0f3a413 --- /dev/null +++ b/gcc32-tls.patch @@ -0,0 +1,4294 @@ +--- 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; + + 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; + + /* 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; + } + ++/* 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; ++} + ++/* 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; ++} + + /* 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; ++} ++ + + /* 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; ++} + + /* 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. + ++;; 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))])] ++ "") ++ + ;; 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; + }) + +--- 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; + ++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; + + /* 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); + } + + /* 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 struct B { ++ static __thread T t; ++}; ++ ++template ++__thread T B::t = 42; ++ ++void bar () ++{ ++ int j = B::t; ++ int k = B::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= Limits the size of inlined functions to \n")); + printf (_(" -fmessage-length= Limits diagnostics messages lengths to 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) diff --git a/gcc32-tls2.patch b/gcc32-tls2.patch new file mode 100644 index 0000000..65eea64 --- /dev/null +++ b/gcc32-tls2.patch @@ -0,0 +1,54 @@ +2002-07-30 Jakub Jelinek + + * 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 diff --git a/gcc32-tls3.patch b/gcc32-tls3.patch new file mode 100644 index 0000000..aec74c9 --- /dev/null +++ b/gcc32-tls3.patch @@ -0,0 +1,48 @@ +2002-08-06 Aldy Hernandez + + * 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; + diff --git a/gcc32-tls4.patch b/gcc32-tls4.patch new file mode 100644 index 0000000..7595e6b --- /dev/null +++ b/gcc32-tls4.patch @@ -0,0 +1,74 @@ +2002-05-22 Richard Henderson + + * 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 + + * 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; diff --git a/gcc32-tls5.patch b/gcc32-tls5.patch new file mode 100644 index 0000000..c3b5ab7 --- /dev/null +++ b/gcc32-tls5.patch @@ -0,0 +1,149 @@ +2002-08-08 Jakub Jelinek + + * 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; ++} diff --git a/gcc32-typeof-asm.patch b/gcc32-typeof-asm.patch new file mode 100644 index 0000000..ab0db75 --- /dev/null +++ b/gcc32-typeof-asm.patch @@ -0,0 +1,100 @@ +2002-08-08 Jakub Jelinek + + * 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" } } diff --git a/gcc32-typeof-skip-eval.patch b/gcc32-typeof-skip-eval.patch new file mode 100644 index 0000000..ffbe65a --- /dev/null +++ b/gcc32-typeof-skip-eval.patch @@ -0,0 +1,160 @@ +2002-08-12 Alexandre Oliva + + * 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. */