]> git.pld-linux.org Git - packages/gcc.git/blobdiff - gcc32-tls.patch
- patches from RH
[packages/gcc.git] / gcc32-tls.patch
diff --git a/gcc32-tls.patch b/gcc32-tls.patch
new file mode 100644 (file)
index 0000000..0f3a413
--- /dev/null
@@ -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;
\f
+ static int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
++static int tls_symbolic_operand_1 PARAMS ((rtx, enum tls_model));
+ static void output_pic_addr_const PARAMS ((FILE *, rtx, int));
+ static void put_condition_code PARAMS ((enum rtx_code, enum machine_mode,
+                                      int, int, FILE *));
++static const char *get_some_local_dynamic_name PARAMS ((void));
++static int get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
++static rtx maybe_get_pool_constant PARAMS ((rtx));
+ static rtx ix86_expand_int_compare PARAMS ((enum rtx_code, rtx, rtx));
+ static enum rtx_code ix86_prepare_fp_compare_args PARAMS ((enum rtx_code,
+                                                          rtx *, rtx *));
++static rtx get_thread_pointer PARAMS ((void));
+ static rtx gen_push PARAMS ((rtx));
+ static int memory_address_length PARAMS ((rtx addr));
+ static int ix86_flags_dependant PARAMS ((rtx, rtx, enum attr_type));
+@@ -820,6 +833,11 @@ static enum x86_64_reg_class merge_class
+ #undef TARGET_SCHED_REORDER
+ #define TARGET_SCHED_REORDER ix86_sched_reorder
++#ifdef HAVE_AS_TLS
++#undef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS true
++#endif
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
\f
+ /* Sometimes certain combinations of command options do not make
+@@ -1109,6 +1127,17 @@ override_options ()
+       ix86_branch_cost = i;
+     }
++  if (ix86_tls_dialect_string)
++    {
++      if (strcmp (ix86_tls_dialect_string, "gnu") == 0)
++      ix86_tls_dialect = TLS_DIALECT_GNU;
++      else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
++      ix86_tls_dialect = TLS_DIALECT_SUN;
++      else
++      error ("bad value (%s) for -mtls-dialect= switch",
++             ix86_tls_dialect_string);
++    }
++
+   /* Keep nonleaf frame pointers.  */
+   if (TARGET_OMIT_LEAF_FRAME_POINTER)
+     flag_omit_frame_pointer = 1;
+@@ -3007,6 +3036,70 @@ local_symbolic_operand (op, mode)
+   return 0;
+ }
++/* Test for various thread-local symbols.  See ix86_encode_section_info. */
++
++int
++tls_symbolic_operand (op, mode)
++     register rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  const char *symbol_str;
++
++  if (GET_CODE (op) != SYMBOL_REF)
++    return 0;
++  symbol_str = XSTR (op, 0);
++
++  if (symbol_str[0] != '%')
++    return 0;
++  return strchr (tls_model_chars, symbol_str[1]) - tls_model_chars;
++}
++
++static int
++tls_symbolic_operand_1 (op, kind)
++     rtx op;
++     enum tls_model kind;
++{
++  const char *symbol_str;
++
++  if (GET_CODE (op) != SYMBOL_REF)
++    return 0;
++  symbol_str = XSTR (op, 0);
++
++  return symbol_str[0] == '%' && symbol_str[1] == tls_model_chars[kind];
++}
++
++int
++global_dynamic_symbolic_operand (op, mode)
++     register rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  return tls_symbolic_operand_1 (op, TLS_MODEL_GLOBAL_DYNAMIC);
++}
++
++int
++local_dynamic_symbolic_operand (op, mode)
++     register rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_DYNAMIC);
++}
++
++int
++initial_exec_symbolic_operand (op, mode)
++     register rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  return tls_symbolic_operand_1 (op, TLS_MODEL_INITIAL_EXEC);
++}
++
++int
++local_exec_symbolic_operand (op, mode)
++     register rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  return tls_symbolic_operand_1 (op, TLS_MODEL_LOCAL_EXEC);
++}
++
+ /* Test for a valid operand for a call instruction.  Don't allow the
+    arg pointer register or virtual regs since they may decay into
+    reg + const, which the patterns can't handle.  */
+@@ -3858,7 +3951,7 @@ ix86_asm_file_end (file)
+ {
+   rtx xops[2];
+-  if (! TARGET_DEEP_BRANCH_PREDICTION || pic_label_name[0] == 0)
++  if (pic_label_name[0] == 0)
+     return;
+   /* The trick here is to create a linkonce section containing the
+@@ -3896,17 +3989,33 @@ ix86_asm_file_end (file)
+   output_asm_insn ("ret", xops);
+ }
+-void
+-load_pic_register ()
++/* Emit code for the SET_GOT patterns.  */
++
++const char *
++output_set_got (dest)
++     rtx dest;
+ {
+-  rtx gotsym, pclab;
++  rtx xops[3];
+-  if (TARGET_64BIT)
+-    abort ();
++  xops[0] = dest;
++  xops[1] = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
++
++  if (! TARGET_DEEP_BRANCH_PREDICTION || !flag_pic)
++    {
++      xops[2] = gen_rtx_LABEL_REF (Pmode, gen_label_rtx ());
++
++      if (!flag_pic)
++      output_asm_insn ("mov{l}\t{%2, %0|%0, %2}", xops);
++      else
++      output_asm_insn ("call\t%a2", xops);
+-  gotsym = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
++      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
++                               CODE_LABEL_NUMBER (XEXP (xops[2], 0)));
+-  if (TARGET_DEEP_BRANCH_PREDICTION)
++      if (flag_pic)
++      output_asm_insn ("pop{l}\t%0", xops);
++    }
++  else
+     {
+       if (! pic_label_name[0])
+       {
+@@ -3915,16 +4024,17 @@ load_pic_register ()
+         else
+           ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", 0);
+       }
+-      pclab = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, pic_label_name));
+-    }
++      xops[2] = gen_rtx_SYMBOL_REF (Pmode, pic_label_name);
++      xops[2] = gen_rtx_MEM (QImode, xops[2]);
++      output_asm_insn ("call\t%X2", xops);
++    }
++  
++  if (!flag_pic || TARGET_DEEP_BRANCH_PREDICTION)
++    output_asm_insn ("add{l}\t{%1, %0|%0, %1}", xops);
+   else
+-    {
+-      pclab = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+-    }
+-
+-  emit_insn (gen_prologue_get_pc (pic_offset_table_rtx, pclab));
+-
+-  emit_insn (gen_prologue_set_got (pic_offset_table_rtx, gotsym, pclab));
++    output_asm_insn ("add{l}\t{%1+[.-%a2], %0|%0, %a1+(.-%a2)}", xops);
++  
++  return "";
+ }
+ /* Generate an "push" pattern for input ARG.  */
+@@ -4253,7 +4363,15 @@ ix86_expand_prologue ()
+ #endif
+   if (pic_reg_used)
+-    load_pic_register ();
++    {
++      insn = emit_insn (gen_set_got (pic_offset_table_rtx));
++
++      /* ??? The current_function_uses_pic_offset_table flag is woefully
++       inaccurate, as it isn't updated as code gets deleted.  Allow the
++       thing to be removed.  A better solution would be to actually get
++       proper liveness for ebx, as then we won't save/restore it too.  */
++      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, NULL);
++    }
+   /* If we are profiling, make sure no instructions are scheduled before
+      the call to mcount.  However, if -fpic, the above call will have
+@@ -4694,6 +4812,114 @@ ix86_find_base_term (x)
+   return term;
+ }
\f
++/* Determine if a given RTX is a valid constant.  We already know this
++   satisfies CONSTANT_P.  */
++
++bool
++legitimate_constant_p (x)
++     rtx x;
++{
++  rtx inner;
++
++  switch (GET_CODE (x))
++    {
++    case SYMBOL_REF:
++      /* TLS symbols are not constant.  */
++      if (tls_symbolic_operand (x, Pmode))
++      return false;
++      break;
++
++    case CONST:
++      inner = XEXP (x, 0);
++
++      /* Offsets of TLS symbols are never valid.
++       Discourage CSE from creating them.  */
++      if (GET_CODE (inner) == PLUS
++        && tls_symbolic_operand (XEXP (inner, 0), Pmode))
++      return false;
++
++      /* Only some unspecs are valid as "constants".  */
++      if (GET_CODE (inner) == UNSPEC)
++      switch (XINT (inner, 1))
++        {
++        case UNSPEC_TPOFF:
++          return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
++        case UNSPEC_TP:
++          return true;
++        default:
++          return false;
++        }
++      break;
++
++    default:
++      break;
++    }
++
++  /* Otherwise we handle everything else in the move patterns.  */
++  return true;
++}
++
++/* Determine if a given RTX is a valid constant address.  */
++
++bool
++constant_address_p (x)
++     rtx x;
++{
++  switch (GET_CODE (x))
++    {
++    case LABEL_REF:
++    case CONST_INT:
++      return true;
++
++    case CONST_DOUBLE:
++      return TARGET_64BIT;
++
++    case CONST:
++    case SYMBOL_REF:
++      return !flag_pic && legitimate_constant_p (x);
++
++    default:
++      return false;
++    }
++}
++
++/* Nonzero if the constant value X is a legitimate general operand
++   when generating PIC code.  It is given that flag_pic is on and 
++   that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
++
++bool
++legitimate_pic_operand_p (x)
++     rtx x;
++{
++  rtx inner;
++
++  switch (GET_CODE (x))
++    {
++    case CONST:
++      inner = XEXP (x, 0);
++
++      /* Only some unspecs are valid as "constants".  */
++      if (GET_CODE (inner) == UNSPEC)
++      switch (XINT (inner, 1))
++        {
++        case UNSPEC_TPOFF:
++          return local_exec_symbolic_operand (XVECEXP (inner, 0, 0), Pmode);
++        case UNSPEC_TP:
++          return true;
++        default:
++          return false;
++        }
++      /* FALLTHRU */
++
++    case SYMBOL_REF:
++    case LABEL_REF:
++      return legitimate_pic_address_disp_p (x);
++
++    default:
++      return true;
++    }
++}
++
+ /* Determine if a given CONST RTX is a valid memory displacement
+    in PIC mode.  */
+@@ -4701,6 +4927,8 @@ int
+ legitimate_pic_address_disp_p (disp)
+      register rtx disp;
+ {
++  bool saw_plus;
++
+   /* In 64bit mode we can allow direct addresses of symbols and labels
+      when they are not dynamic symbols.  */
+   if (TARGET_64BIT)
+@@ -4737,25 +4965,39 @@ legitimate_pic_address_disp_p (disp)
+       return 1;
+     }
++  saw_plus = false;
+   if (GET_CODE (disp) == PLUS)
+     {
+       if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
+       return 0;
+       disp = XEXP (disp, 0);
++      saw_plus = true;
+     }
+   if (GET_CODE (disp) != UNSPEC
+       || XVECLEN (disp, 0) != 1)
+     return 0;
+-  /* Must be @GOT or @GOTOFF.  */
+   switch (XINT (disp, 1))
+     {
+-    case 6: /* @GOT */
++    case UNSPEC_GOT:
++      if (saw_plus)
++      return false;
+       return GET_CODE (XVECEXP (disp, 0, 0)) == SYMBOL_REF;
+-
+-    case 7: /* @GOTOFF */
++    case UNSPEC_GOTOFF:
+       return local_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++    case UNSPEC_GOTTPOFF:
++      if (saw_plus)
++      return false;
++      return initial_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++    case UNSPEC_NTPOFF:
++      if (saw_plus)
++      return false;
++      return local_exec_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
++    case UNSPEC_DTPOFF:
++      if (saw_plus)
++      return false;
++      return local_dynamic_symbolic_operand (XVECEXP (disp, 0, 0), Pmode);
+     }
+     
+   return 0;
+@@ -4882,12 +5124,6 @@ legitimate_address_p (mode, addr, strict
+     {
+       reason_rtx = disp;
+-      if (!CONSTANT_ADDRESS_P (disp))
+-      {
+-        reason = "displacement is not constant";
+-        goto report_error;
+-      }
+-
+       if (TARGET_64BIT)
+       {
+         if (!x86_64_sign_extended_value (disp))
+@@ -4905,8 +5141,30 @@ legitimate_address_p (mode, addr, strict
+           }
+       }
+-      if (flag_pic && SYMBOLIC_CONST (disp))
++      if (GET_CODE (disp) == CONST
++        && GET_CODE (XEXP (disp, 0)) == UNSPEC)
++      switch (XINT (XEXP (disp, 0), 1))
++        {
++        case UNSPEC_GOT:
++        case UNSPEC_GOTOFF:
++        case UNSPEC_GOTPCREL:
++          if (!flag_pic)
++            abort ();
++          goto is_legitimate_pic;
++
++        case UNSPEC_GOTTPOFF:
++        case UNSPEC_NTPOFF:
++        case UNSPEC_DTPOFF:
++          break;
++
++        default:
++          reason = "invalid address unspec";
++          goto report_error;
++        }
++
++      else if (flag_pic && SYMBOLIC_CONST (disp))
+       {
++      is_legitimate_pic:
+         if (TARGET_64BIT && (index || base))
+           {
+             reason = "non-constant pic memory reference";
+@@ -4949,6 +5207,11 @@ legitimate_address_p (mode, addr, strict
+             goto report_error;
+           }
+       }
++      else if (!CONSTANT_ADDRESS_P (disp))
++      {
++        reason = "displacement is not constant";
++        goto report_error;
++      }
+     }
+   /* Everything looks valid.  */
+@@ -5129,7 +5392,102 @@ legitimize_pic_address (orig, reg)
+     }
+   return new;
+ }
++
++void
++ix86_encode_section_info (decl)
++     tree decl;
++{
++  bool local_p;
++  rtx rtl, symbol;
++
++  rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
++  if (GET_CODE (rtl) != MEM)
++    return;
++  symbol = XEXP (rtl, 0);
++  if (GET_CODE (symbol) != SYMBOL_REF)
++    return;
++
++  local_p = !DECL_P (decl) || !TREE_PUBLIC (decl) || MODULE_LOCAL_P (decl);
++
++  /* For basic x86, if using PIC, mark a SYMBOL_REF for a non-global
++     symbol so that we may access it directly in the GOT.  */
++
++  if (flag_pic)
++    SYMBOL_REF_FLAG (symbol) = local_p;
++
++  /* For ELF, encode thread-local data with %[GLil] for "global dynamic",
++     "local dynamic", "initial exec" or "local exec" TLS models
++     respectively.  */
++
++  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++    {
++      const char *symbol_str;
++      char *newstr;
++      size_t len;
++      enum tls_model kind;
++
++      if (!flag_pic)
++      {
++        if (local_p)
++          kind = TLS_MODEL_LOCAL_EXEC;
++        else
++          kind = TLS_MODEL_INITIAL_EXEC;
++      }
++      /* Local dynamic is inefficient when we're not combining the
++       parts of the address.  */
++      else if (optimize && local_p)
++      kind = TLS_MODEL_LOCAL_DYNAMIC;
++      else
++      kind = TLS_MODEL_GLOBAL_DYNAMIC;
++      if (kind < flag_tls_default)
++      kind = flag_tls_default;
++
++      symbol_str = XSTR (symbol, 0);
++
++      if (symbol_str[0] == '%')
++      {
++        if (symbol_str[1] == tls_model_chars[kind])
++          return;
++        symbol_str += 2;
++      }
++      len = strlen (symbol_str) + 1;
++      newstr = alloca (len + 2);
++
++      newstr[0] = '%';
++      newstr[1] = tls_model_chars[kind];
++      memcpy (newstr + 2, symbol_str, len);
++
++      XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1);
++    }
++}
++
++/* Undo the above when printing symbol names.  */
++
++const char *
++ix86_strip_name_encoding (str)
++     const char *str;
++{
++  if (str[0] == '%')
++    str += 2;
++  if (str [0] == '*')
++    str += 1;
++  return str;
++}
\f
++/* Load the thread pointer into a register.  */
++
++static rtx
++get_thread_pointer ()
++{
++  rtx tp;
++
++  tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
++  tp = gen_rtx_CONST (Pmode, tp);
++  tp = force_reg (Pmode, tp);
++
++  return tp;
++}
++
+ /* Try machine-dependent ways of modifying an illegitimate address
+    to be legitimate.  If we find one, return the new, valid address.
+    This macro is used in only one place: `memory_address' in explow.c.
+@@ -5167,6 +5525,84 @@ legitimize_address (x, oldx, mode)
+       debug_rtx (x);
+     }
++  log = tls_symbolic_operand (x, mode);
++  if (log)
++    {
++      rtx dest, base, off, pic;
++
++      switch (log)
++        {
++        case TLS_MODEL_GLOBAL_DYNAMIC:
++        dest = gen_reg_rtx (Pmode);
++          emit_insn (gen_tls_global_dynamic (dest, x));
++        break;
++
++        case TLS_MODEL_LOCAL_DYNAMIC:
++        base = gen_reg_rtx (Pmode);
++        emit_insn (gen_tls_local_dynamic_base (base));
++
++        off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF);
++        off = gen_rtx_CONST (Pmode, off);
++
++        return gen_rtx_PLUS (Pmode, base, off);
++
++        case TLS_MODEL_INITIAL_EXEC:
++        if (flag_pic)
++          {
++            current_function_uses_pic_offset_table = 1;
++            pic = pic_offset_table_rtx;
++          }
++        else
++          {
++            pic = gen_reg_rtx (Pmode);
++            emit_insn (gen_set_got (pic));
++          }
++
++        base = get_thread_pointer ();
++
++        off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_GOTTPOFF);
++        off = gen_rtx_CONST (Pmode, off);
++        off = gen_rtx_PLUS (Pmode, pic, off);
++        off = gen_rtx_MEM (Pmode, off);
++        RTX_UNCHANGING_P (off) = 1;
++        set_mem_alias_set (off, ix86_GOT_alias_set ());
++
++        /* Damn Sun for specifing a set of dynamic relocations without
++           considering the two-operand nature of the architecture!
++           We'd be much better off with a "GOTNTPOFF" relocation that
++           already contained the negated constant.  */
++        /* ??? Using negl and reg+reg addressing appears to be a lose
++           size-wise.  The negl is two bytes, just like the extra movl
++           incurred by the two-operand subl, but reg+reg addressing
++           uses the two-byte modrm form, unlike plain reg.  */
++
++        dest = gen_reg_rtx (Pmode);
++        emit_insn (gen_subsi3 (dest, base, off));
++        break;
++
++        case TLS_MODEL_LOCAL_EXEC:
++        base = get_thread_pointer ();
++
++        off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x),
++                              TARGET_GNU_TLS ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
++        off = gen_rtx_CONST (Pmode, off);
++
++        if (TARGET_GNU_TLS)
++          return gen_rtx_PLUS (Pmode, base, off);
++        else
++          {
++            dest = gen_reg_rtx (Pmode);
++            emit_insn (gen_subsi3 (dest, base, off));
++          }
++        break;
++
++      default:
++        abort ();
++        }
++
++      return dest;
++    }
++
+   if (flag_pic && SYMBOLIC_CONST (x))
+     return legitimize_pic_address (x, 0);
+@@ -5410,18 +5846,30 @@ output_pic_addr_const (file, x, code)
+        output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+        switch (XINT (x, 1))
+       {
+-      case 6:
++      case UNSPEC_GOT:
+         fputs ("@GOT", file);
+         break;
+-      case 7:
++      case UNSPEC_GOTOFF:
+         fputs ("@GOTOFF", file);
+         break;
+-      case 8:
++      case UNSPEC_PLT:
+         fputs ("@PLT", file);
+         break;
+-      case 15:
++      case UNSPEC_GOTPCREL:
+         fputs ("@GOTPCREL(%RIP)", file);
+         break;
++      case UNSPEC_GOTTPOFF:
++        fputs ("@GOTTPOFF", file);
++        break;
++      case UNSPEC_TPOFF:
++        fputs ("@TPOFF", file);
++        break;
++      case UNSPEC_NTPOFF:
++        fputs ("@NTPOFF", file);
++        break;
++      case UNSPEC_DTPOFF:
++        fputs ("@DTPOFF", file);
++        break;
+       default:
+         output_operand_lossage ("invalid UNSPEC as operand");
+         break;
+@@ -5710,6 +6158,43 @@ print_reg (x, code, file)
+     }
+ }
++/* Locate some local-dynamic symbol still in use by this function
++   so that we can print its name in some tls_local_dynamic_base
++   pattern.  */
++
++static const char *
++get_some_local_dynamic_name ()
++{
++  rtx insn;
++
++  if (cfun->machine->some_ld_name)
++    return cfun->machine->some_ld_name;
++
++  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
++    if (INSN_P (insn)
++      && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
++      return cfun->machine->some_ld_name;
++
++  abort ();
++}
++
++static int
++get_some_local_dynamic_name_1 (px, data)
++     rtx *px;
++     void *data ATTRIBUTE_UNUSED;
++{
++  rtx x = *px;
++
++  if (GET_CODE (x) == SYMBOL_REF
++      && local_dynamic_symbolic_operand (x, Pmode))
++    {
++      cfun->machine->some_ld_name = XSTR (x, 0);
++      return 1;
++    }
++
++  return 0;
++}
++
+ /* Meaning of CODE:
+    L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
+    C -- print opcode suffix for set/cmov insn.
+@@ -5734,6 +6219,7 @@ print_reg (x, code, file)
+    D -- print condition for SSE cmp instruction.
+    P -- if PIC, print an @PLT suffix.
+    X -- don't print any sort of PIC '@' suffix for a symbol.
++   & -- print some in-use local-dynamic symbol name.
+  */
+ void
+@@ -5751,6 +6237,10 @@ print_operand (file, x, code)
+           putc ('*', file);
+         return;
++      case '&':
++        assemble_name (file, get_some_local_dynamic_name ());
++        return;
++
+       case 'A':
+         if (ASSEMBLER_DIALECT == ASM_ATT)
+           putc ('*', file);
+@@ -6078,6 +6568,18 @@ print_operand (file, x, code)
+       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
+       fprintf (file, "%s", dstr);
+     }
++
++  else if (GET_CODE (x) == CONST
++         && GET_CODE (XEXP (x, 0)) == UNSPEC
++         && XINT (XEXP (x, 0), 1) == UNSPEC_TP)
++    {
++      if (ASSEMBLER_DIALECT == ASM_INTEL)
++      fputs ("DWORD PTR ", file);
++      if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
++      putc ('%', file);
++      fputs ("gs:0", file);
++    }
++
+   else
+     {
+       if (code != 'P')
+@@ -6226,6 +6728,43 @@ print_operand_address (file, addr)
+       }
+     }
+ }
++
++bool
++output_addr_const_extra (file, x)
++     FILE *file;
++     rtx x;
++{
++  rtx op;
++
++  if (GET_CODE (x) != UNSPEC)
++    return false;
++
++  op = XVECEXP (x, 0, 0);
++  switch (XINT (x, 1))
++    {
++    case UNSPEC_GOTTPOFF:
++      output_addr_const (file, op);
++      fputs ("@GOTTPOFF", file);
++      break;
++    case UNSPEC_TPOFF:
++      output_addr_const (file, op);
++      fputs ("@TPOFF", file);
++      break;
++    case UNSPEC_NTPOFF:
++      output_addr_const (file, op);
++      fputs ("@NTPOFF", file);
++      break;
++    case UNSPEC_DTPOFF:
++      output_addr_const (file, op);
++      fputs ("@DTPOFF", file);
++      break;
++
++    default:
++      return false;
++    }
++
++  return true;
++}
\f
+ /* Split one or more DImode RTL references into pairs of SImode
+    references.  The RTL can be REG, offsettable MEM, integer constant, or
+@@ -6763,51 +7302,117 @@ ix86_expand_clear (dest)
+   emit_insn (tmp);
+ }
++/* X is an unchanging MEM.  If it is a constant pool reference, return
++   the constant pool rtx, else NULL.  */
++
++static rtx
++maybe_get_pool_constant (x)
++     rtx x;
++{
++  x = XEXP (x, 0);
++
++  if (flag_pic)
++    {
++      if (GET_CODE (x) != PLUS)
++      return NULL_RTX;
++      if (XEXP (x, 0) != pic_offset_table_rtx)
++      return NULL_RTX;
++      x = XEXP (x, 1);
++      if (GET_CODE (x) != CONST)
++      return NULL_RTX;
++      x = XEXP (x, 0);
++      if (GET_CODE (x) != UNSPEC)
++      return NULL_RTX;
++      if (XINT (x, 1) != UNSPEC_GOTOFF)
++      return NULL_RTX;
++      x = XVECEXP (x, 0, 0);
++    }
++
++  if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
++    return get_pool_constant (x);
++
++  return NULL_RTX;
++}
++
+ void
+ ix86_expand_move (mode, operands)
+      enum machine_mode mode;
+      rtx operands[];
+ {
+   int strict = (reload_in_progress || reload_completed);
+-  rtx insn;
++  rtx insn, op0, op1, tmp;
++
++  op0 = operands[0];
++  op1 = operands[1];
+-  if (flag_pic && mode == Pmode && symbolic_operand (operands[1], Pmode))
++  /* ??? We have a slight problem.  We need to say that tls symbols are
++     not legitimate constants so that reload does not helpfully reload
++     these constants from a REG_EQUIV, which we cannot handle.  (Recall
++     that general- and local-dynamic address resolution requires a
++     function call.)
++
++     However, if we say that tls symbols are not legitimate constants,
++     then emit_move_insn helpfully drop them into the constant pool.
++
++     It is far easier to work around emit_move_insn than reload.  Recognize
++     the MEM that we would have created and extract the symbol_ref.  */
++
++  if (mode == Pmode
++      && GET_CODE (op1) == MEM
++      && RTX_UNCHANGING_P (op1))
+     {
+-      /* Emit insns to move operands[1] into operands[0].  */
++      tmp = maybe_get_pool_constant (op1);
++      /* Note that we only care about symbolic constants here, which
++       unlike CONST_INT will always have a proper mode.  */
++      if (tmp && GET_MODE (tmp) == Pmode)
++      op1 = tmp;
++    }
+-      if (GET_CODE (operands[0]) == MEM)
+-      operands[1] = force_reg (Pmode, operands[1]);
++  if (tls_symbolic_operand (op1, Pmode))
++    {
++      op1 = legitimize_address (op1, op1, VOIDmode);
++      if (GET_CODE (op0) == MEM)
++      {
++        tmp = gen_reg_rtx (mode);
++        emit_insn (gen_rtx_SET (VOIDmode, tmp, op1));
++        op1 = tmp;
++      }
++    }
++  else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
++    {
++      if (GET_CODE (op0) == MEM)
++      op1 = force_reg (Pmode, op1);
+       else
+       {
+-        rtx temp = operands[0];
++        rtx temp = op0;
+         if (GET_CODE (temp) != REG)
+           temp = gen_reg_rtx (Pmode);
+-        temp = legitimize_pic_address (operands[1], temp);
+-        if (temp == operands[0])
++        temp = legitimize_pic_address (op1, temp);
++        if (temp == op0)
+           return;
+-        operands[1] = temp;
++        op1 = temp;
+       }
+     }
+   else
+     {
+-      if (GET_CODE (operands[0]) == MEM
++      if (GET_CODE (op0) == MEM
+         && (PUSH_ROUNDING (GET_MODE_SIZE (mode)) != GET_MODE_SIZE (mode)
+-            || !push_operand (operands[0], mode))
+-        && GET_CODE (operands[1]) == MEM)
+-      operands[1] = force_reg (mode, operands[1]);
+-
+-      if (push_operand (operands[0], mode)
+-        && ! general_no_elim_operand (operands[1], mode))
+-      operands[1] = copy_to_mode_reg (mode, operands[1]);
++            || !push_operand (op0, mode))
++        && GET_CODE (op1) == MEM)
++      op1 = force_reg (mode, op1);
++
++      if (push_operand (op0, mode)
++        && ! general_no_elim_operand (op1, mode))
++      op1 = copy_to_mode_reg (mode, op1);
+       /* Force large constants in 64bit compilation into register
+        to get them CSEed.  */
+       if (TARGET_64BIT && mode == DImode
+-        && immediate_operand (operands[1], mode)
+-        && !x86_64_zero_extended_value (operands[1])
+-        && !register_operand (operands[0], mode)
++        && immediate_operand (op1, mode)
++        && !x86_64_zero_extended_value (op1)
++        && !register_operand (op0, mode)
+         && optimize && !reload_completed && !reload_in_progress)
+-      operands[1] = copy_to_mode_reg (mode, operands[1]);
++      op1 = copy_to_mode_reg (mode, op1);
+       if (FLOAT_MODE_P (mode))
+       {
+@@ -6817,13 +7422,13 @@ ix86_expand_move (mode, operands)
+         if (strict)
+           ;
+-        else if (GET_CODE (operands[1]) == CONST_DOUBLE
+-                 && register_operand (operands[0], mode))
+-          operands[1] = validize_mem (force_const_mem (mode, operands[1]));
++        else if (GET_CODE (op1) == CONST_DOUBLE
++                 && register_operand (op0, mode))
++          op1 = validize_mem (force_const_mem (mode, op1));
+       }
+     }
+-  insn = gen_rtx_SET (VOIDmode, operands[0], operands[1]);
++  insn = gen_rtx_SET (VOIDmode, op0, op1);
+   emit_insn (insn);
+ }
+@@ -8588,13 +9193,14 @@ ix86_split_to_parts (operand, parts, mod
+   if (size < 2 || size > 3)
+     abort ();
+-  /* Optimize constant pool reference to immediates.  This is used by fp moves,
+-     that force all constants to memory to allow combining.  */
+-
+-  if (GET_CODE (operand) == MEM
+-      && GET_CODE (XEXP (operand, 0)) == SYMBOL_REF
+-      && CONSTANT_POOL_ADDRESS_P (XEXP (operand, 0)))
+-    operand = get_pool_constant (XEXP (operand, 0));
++  /* Optimize constant pool reference to immediates.  This is used by fp
++     moves, that force all constants to memory to allow combining.  */
++  if (GET_CODE (operand) == MEM && RTX_UNCHANGING_P (operand))
++    {
++      rtx tmp = maybe_get_pool_constant (operand);
++      if (tmp)
++      operand = tmp;
++    }
+   if (GET_CODE (operand) == MEM && !offsettable_memref_p (operand))
+     {
+@@ -9790,6 +10396,55 @@ ix86_expand_strlensi_unroll_1 (out, alig
+   emit_label (end_0_label);
+ }
++
++void
++ix86_expand_call (retval, fnaddr, callarg1, callarg2, pop)
++     rtx retval, fnaddr, callarg1, callarg2, pop;
++{
++  rtx use = NULL, call;
++
++  if (pop == const0_rtx)
++    pop = NULL;
++  if (TARGET_64BIT && pop)
++    abort ();
++
++  /* Static functions and indirect calls don't need the pic register.  */
++  if (! TARGET_64BIT && flag_pic
++      && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
++      && ! SYMBOL_REF_FLAG (XEXP (fnaddr, 0)))
++    {
++      current_function_uses_pic_offset_table = 1;
++      use_reg (&use, pic_offset_table_rtx);
++    }
++
++  if (TARGET_64BIT && INTVAL (callarg2) >= 0)
++    {
++      rtx al = gen_rtx_REG (QImode, 0);
++      emit_move_insn (al, callarg2);
++      use_reg (&use, al);
++    }
++
++  if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
++    {
++      fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
++      fnaddr = gen_rtx_MEM (QImode, fnaddr);
++    }
++
++  call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
++  if (retval)
++    call = gen_rtx_SET (VOIDmode, retval, call);
++  if (pop)
++    {
++      pop = gen_rtx_PLUS (Pmode, stack_pointer_rtx, pop);
++      pop = gen_rtx_SET (VOIDmode, stack_pointer_rtx, pop);
++      call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, call, pop));
++    }
++
++  call = emit_call_insn (call);
++  if (use)
++    CALL_INSN_FUNCTION_USAGE (call) = use;
++}
++  
\f
+ /* Clear stack slot assignments remembered from previous functions.
+    This is called from INIT_EXPANDERS once before RTL is emitted for each
+@@ -9849,6 +10504,24 @@ assign_386_stack_local (mode, n)
+   return ix86_stack_locals[(int) mode][n];
+ }
++
++/* Construct the SYMBOL_REF for the tls_get_addr function.  */
++
++rtx
++ix86_tls_get_addr ()
++{
++  static rtx symbol;
++
++  if (!symbol)
++    {
++      symbol = gen_rtx_SYMBOL_REF (Pmode, (TARGET_GNU_TLS
++                                         ? "___tls_get_addr"
++                                         : "__tls_get_addr"));
++      ggc_add_rtx_root (&symbol, 1);
++    }
++
++  return symbol;
++}
\f
+ /* Calculate the length of the memory address in the instruction
+    encoding.  Does not include the one-byte modrm, opcode, or prefix.  */
+--- gcc/config/i386/i386-protos.h.jj   Wed Jun 19 15:18:02 2002
++++ gcc/config/i386/i386-protos.h      Wed Jun 19 19:33:52 2002
+@@ -28,7 +28,6 @@ extern int ix86_frame_pointer_required P
+ extern void ix86_setup_frame_addresses PARAMS ((void));
+ extern void ix86_asm_file_end PARAMS ((FILE *));
+-extern void load_pic_register PARAMS ((void));
+ extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
+ extern void ix86_expand_prologue PARAMS ((void));
+ extern void ix86_expand_epilogue PARAMS ((int));
+@@ -36,6 +35,9 @@ extern void ix86_expand_epilogue PARAMS 
+ extern void ix86_output_addr_vec_elt PARAMS ((FILE *, int));
+ extern void ix86_output_addr_diff_elt PARAMS ((FILE *, int, int));
++extern void ix86_encode_section_info PARAMS ((tree));
++extern const char *ix86_strip_name_encoding PARAMS ((const char *));
++
+ #ifdef RTX_CODE
+ extern int ix86_aligned_p PARAMS ((rtx));
+@@ -51,6 +53,11 @@ extern int x86_64_immediate_operand PARA
+ extern int x86_64_zext_immediate_operand PARAMS ((rtx, enum machine_mode));
+ extern int const_int_1_operand PARAMS ((rtx, enum machine_mode));
+ extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int tls_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int global_dynamic_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int local_dynamic_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int initial_exec_symbolic_operand PARAMS ((rtx, enum machine_mode));
++extern int local_exec_symbolic_operand PARAMS ((rtx, enum machine_mode));
+ extern int pic_symbolic_operand PARAMS ((rtx, enum machine_mode));
+ extern int call_insn_operand PARAMS ((rtx, enum machine_mode));
+ extern int constant_call_address_operand PARAMS ((rtx, enum machine_mode));
+@@ -84,6 +91,9 @@ extern int ix86_expand_movstr PARAMS ((r
+ extern int ix86_expand_clrstr PARAMS ((rtx, rtx, rtx));
+ extern int ix86_expand_strlen PARAMS ((rtx, rtx, rtx, rtx));
++extern bool legitimate_constant_p PARAMS ((rtx));
++extern bool constant_address_p PARAMS ((rtx));
++extern bool legitimate_pic_operand_p PARAMS ((rtx));
+ extern int legitimate_pic_address_disp_p PARAMS ((rtx));
+ extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
+ extern rtx legitimize_pic_address PARAMS ((rtx, rtx));
+@@ -92,10 +102,12 @@ extern rtx legitimize_address PARAMS ((r
+ extern void print_reg PARAMS ((rtx, int, FILE*));
+ extern void print_operand PARAMS ((FILE*, rtx, int));
+ extern void print_operand_address PARAMS ((FILE*, rtx));
++extern bool output_addr_const_extra PARAMS ((FILE*, rtx));
+ extern void split_di PARAMS ((rtx[], int, rtx[], rtx[]));
+ extern void split_ti PARAMS ((rtx[], int, rtx[], rtx[]));
++extern const char *output_set_got PARAMS ((rtx));
+ extern const char *output_387_binary_op PARAMS ((rtx, rtx*));
+ extern const char *output_fix_trunc PARAMS ((rtx, rtx*));
+ extern const char *output_fp_compare PARAMS ((rtx, rtx*, int, int));
+@@ -121,6 +133,7 @@ extern void ix86_expand_branch PARAMS ((
+ extern int ix86_expand_setcc PARAMS ((enum rtx_code, rtx));
+ extern int ix86_expand_int_movcc PARAMS ((rtx[]));
+ extern int ix86_expand_fp_movcc PARAMS ((rtx[]));
++extern void ix86_expand_call PARAMS ((rtx, rtx, rtx, rtx, rtx));
+ extern void x86_initialize_trampoline PARAMS ((rtx, rtx, rtx));
+ extern rtx ix86_zero_extend_to_Pmode PARAMS ((rtx));
+ extern void ix86_split_long_move PARAMS ((rtx[]));
+@@ -181,6 +194,8 @@ extern rtx ix86_expand_builtin PARAMS ((
+ #endif
++extern rtx ix86_tls_get_addr PARAMS ((void));
++
+ #ifdef TREE_CODE
+ extern int ix86_return_pops_args PARAMS ((tree, tree, int));
+ extern tree ix86_build_va_list PARAMS ((void));
+--- gcc/config/i386/i386.h.jj  Wed Jun 19 19:33:51 2002
++++ gcc/config/i386/i386.h     Wed Jun 19 20:20:56 2002
+@@ -282,6 +282,9 @@ extern int x86_prefetch_sse;
+ #define TARGET_RED_ZONE (!(target_flags & MASK_NO_RED_ZONE))
++#define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
++#define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN)
++
+ /* WARNING: Do not mark empty strings for translation, as calling
+             gettext on an empty string does NOT return an empty
+             string. */
+@@ -451,6 +454,8 @@ extern int ix86_arch;
+     "" /* Undocumented. */ },                                 \
+   { "asm=", &ix86_asm_string,                                 \
+     N_("Use given assembler dialect") },                      \
++  { "tls-dialect=", &ix86_tls_dialect_string,                 \
++    N_("Use given thread-local storage dialect") },           \
+   SUBTARGET_OPTIONS                                           \
+ }
+@@ -1934,15 +1939,12 @@ do {                                                                   \
+ #define MAX_REGS_PER_ADDRESS 2
+-#define CONSTANT_ADDRESS_P(X)                                 \
+-  (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF    \
+-   || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST      \
+-   || GET_CODE (X) == CONST_DOUBLE)
++#define CONSTANT_ADDRESS_P(X)  constant_address_p (X)
+ /* Nonzero if the constant value X is a legitimate general operand.
+    It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+-#define LEGITIMATE_CONSTANT_P(X) 1
++#define LEGITIMATE_CONSTANT_P(X)  legitimate_constant_p (X)
+ #ifdef REG_OK_STRICT
+ #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)                               \
+@@ -2005,9 +2007,7 @@ do {                                                                     \
+    when generating PIC code.  It is given that flag_pic is on and 
+    that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+-#define LEGITIMATE_PIC_OPERAND_P(X)           \
+-  (! SYMBOLIC_CONST (X)                               \
+-   || legitimate_pic_address_disp_p (X))
++#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X)
+ #define SYMBOLIC_CONST(X)     \
+   (GET_CODE (X) == SYMBOL_REF                                         \
+@@ -2251,33 +2251,23 @@ enum ix86_builtins
+    On i386, if using PIC, mark a SYMBOL_REF for a non-global symbol
+    so that we may access it directly in the GOT.  */
+-#define ENCODE_SECTION_INFO(DECL)                             \
+-do {                                                          \
+-    if (flag_pic)                                             \
+-      {                                                               \
+-      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'    \
+-                 ? TREE_CST_RTL (DECL) : DECL_RTL (DECL));    \
+-                                                              \
+-      if (GET_CODE (rtl) == MEM)                              \
+-        {                                                     \
+-          if (TARGET_DEBUG_ADDR                               \
+-              && TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd')   \
+-            {                                                 \
+-              fprintf (stderr, "Encode %s, public = %d\n",    \
+-                       IDENTIFIER_POINTER (DECL_NAME (DECL)), \
+-                       TREE_PUBLIC (DECL));                   \
+-            }                                                 \
+-                                                              \
+-          SYMBOL_REF_FLAG (XEXP (rtl, 0))                     \
+-            = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd'      \
+-               || ! TREE_PUBLIC (DECL)                        \
+-               || MODULE_LOCAL_P (DECL));                     \
+-        }                                                     \
+-      }                                                               \
+-} while (0)
+-
++#define ENCODE_SECTION_INFO(DECL)  ix86_encode_section_info(DECL)
+ #define REDO_SECTION_INFO_P(DECL) 1
++#define STRIP_NAME_ENCODING(VAR,STR)  ((VAR) = ix86_strip_name_encoding (STR))
++
++#define ASM_OUTPUT_LABELREF(FILE,NAME)                \
++  do {                                                \
++    const char *xname = (NAME);                       \
++    if (xname[0] == '%')                      \
++      xname += 2;                             \
++    if (xname[0] == '*')                      \
++      xname += 1;                             \
++    else                                      \
++      fputs (user_label_prefix, FILE);                \
++    fputs (xname, FILE);                      \
++  } while (0)
++
+ /* The `FINALIZE_PIC' macro serves as a hook to emit these special
+    codes once the function is being compiled into assembly code, but
+    not before.  (It is not done before, because in the case of
+@@ -2923,7 +2913,7 @@ extern int const svr4_dbx_register_map[F
+    print_operand function.  */
+ #define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+-  ((CODE) == '*' || (CODE) == '+')
++  ((CODE) == '*' || (CODE) == '+' || (CODE) == '&')
+ /* Print the name of a register based on its machine mode and number.
+    If CODE is 'w', pretend the mode is HImode.
+@@ -2942,6 +2932,12 @@ extern int const svr4_dbx_register_map[F
+ #define PRINT_OPERAND_ADDRESS(FILE, ADDR)  \
+   print_operand_address ((FILE), (ADDR))
++#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL)        \
++do {                                          \
++  if (! output_addr_const_extra (FILE, (X)))  \
++    goto FAIL;                                        \
++} while (0);
++
+ /* Print the name of a register for based on its machine mode and number.
+    This macro is used to print debugging output.
+    This macro is different from PRINT_REG in that it may be used in
+@@ -3071,7 +3067,12 @@ extern int const svr4_dbx_register_map[F
+   {"memory_displacement_operand", {MEM}},                             \
+   {"cmpsi_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,      \
+                    LABEL_REF, SUBREG, REG, MEM, AND}},                \
+-  {"long_memory_operand", {MEM}},
++  {"long_memory_operand", {MEM}},                                     \
++  {"tls_symbolic_operand", {SYMBOL_REF}},                             \
++  {"global_dynamic_symbolic_operand", {SYMBOL_REF}},                  \
++  {"local_dynamic_symbolic_operand", {SYMBOL_REF}},                   \
++  {"initial_exec_symbolic_operand", {SYMBOL_REF}},                    \
++  {"local_exec_symbolic_operand", {SYMBOL_REF}},
+ /* A list of predicates that do special things with modes, and so
+    should not elicit warnings for VOIDmode match_operand.  */
+@@ -3112,6 +3113,16 @@ enum asm_dialect {
+ };
+ extern const char *ix86_asm_string;
+ extern enum asm_dialect ix86_asm_dialect;
++
++enum tls_dialect
++{
++  TLS_DIALECT_GNU,
++  TLS_DIALECT_SUN
++};
++
++extern enum tls_dialect ix86_tls_dialect;
++extern const char *ix86_tls_dialect_string;
++  
+ /* Value of -mcmodel specified by user.  */
+ extern const char *ix86_cmodel_string;
+ extern enum cmodel ix86_cmodel;
+--- gcc/config/i386/i386.md.jj Tue Jun  4 20:28:36 2002
++++ gcc/config/i386/i386.md    Wed Jun 19 19:33:52 2002
+@@ -49,55 +49,59 @@
+ ;; 'k' Likewise, print the SImode name of the register.
+ ;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
+ ;; 'y' Print "st(0)" instead of "st" as a register.
+-;;
++
+ ;; UNSPEC usage:
+-;; 0  This is a `scas' operation.  The mode of the UNSPEC is always SImode.
+-;;    operand 0 is the memory address to scan.
+-;;    operand 1 is a register containing the value to scan for.  The mode
+-;;       of the scas opcode will be the same as the mode of this operand.
+-;;    operand 2 is the known alignment of operand 0.
+-;; 1  This is a `sin' operation.  The mode of the UNSPEC is MODE_FLOAT.
+-;;    operand 0 is the argument for `sin'.
+-;; 2  This is a `cos' operation.  The mode of the UNSPEC is MODE_FLOAT.
+-;;    operand 0 is the argument for `cos'.
+-;; 3  This is part of a `stack probe' operation.  The mode of the UNSPEC is 
+-;;    always SImode.  operand 0 is the size of the stack allocation.
+-;; 4  This is the source of a fake SET of the frame pointer which is used to
+-;;    prevent insns referencing it being scheduled across the initial
+-;;    decrement of the stack pointer.
+-;; 5  This is a `bsf' operation.
+-;; 6  This is the @GOT offset of a PIC address.
+-;; 7  This is the @GOTOFF offset of a PIC address.
+-;; 8  This is a reference to a symbol's @PLT address.
+-;; 9  This is an `fnstsw' operation.
+-;; 10 This is a `sahf' operation.
+-;; 11 This is a `fstcw' operation
+-;; 12 This is behaviour of add when setting carry flag.
+-;; 13 This is a `eh_return' placeholder.
+-
+-;; For SSE/MMX support:
+-;; 30 This is `fix', guaranteed to be truncating.
+-;; 31 This is a `emms' operation.
+-;; 32 This is a `maskmov' operation.
+-;; 33 This is a `movmsk' operation.
+-;; 34 This is a `non-temporal' move.
+-;; 36 This is used to distinguish COMISS from UCOMISS.
+-;; 37 This is a `ldmxcsr' operation.
+-;; 38 This is a forced `movaps' instruction (rather than whatever movti does)
+-;; 39 This is a forced `movups' instruction (rather than whatever movti does)
+-;; 40 This is a `stmxcsr' operation.
+-;; 41 This is a `shuffle' operation.
+-;; 42 This is a `rcp' operation.
+-;; 43 This is a `rsqsrt' operation.
+-;; 44 This is a `sfence' operation.
+-;; 45 This is a noop to prevent excessive combiner cleverness.
+-;; 46 This is a `femms' operation.
+-;; 49 This is a 'pavgusb' operation.
+-;; 50 This is a `pfrcp' operation.
+-;; 51 This is a `pfrcpit1' operation.
+-;; 52 This is a `pfrcpit2' operation.
+-;; 53 This is a `pfrsqrt' operation.
+-;; 54 This is a `pfrsqrit1' operation.
++;; ??? Note that the 3.1 branch, unlike mainline, has not had all
++;; of the uses of UNSPEC replaced with their symbolic constants.
++;; Thus you cannot change these arbitrarily without pain.
++
++(define_constants
++  [(UNSPEC_SCAS                       0)
++   (UNSPEC_SIN                        1)
++   (UNSPEC_COS                        2)
++   (UNSPEC_STACK_PROBE                3)
++   (UNSPEC_STACK_ALLOC                4)
++   (UNSPEC_BSF                        5)
++   (UNSPEC_GOT                        6)
++   (UNSPEC_GOTOFF             7)
++   (UNSPEC_PLT                        8)
++   (UNSPEC_FNSTSW             9)
++   (UNSPEC_SAHF                       10)
++   (UNSPEC_FSTCW              11)
++   (UNSPEC_FLDCW              12)
++   (UNSPEC_ADD_CARRY          12)
++   (UNSPEC_EH_RETURN          13)
++   (UNSPEC_GOTPCREL           15)
++   (UNSPEC_SET_GOT            16)
++
++   ; For TLS support:
++   (UNSPEC_GOTTPOFF             20)
++   (UNSPEC_TPOFF                21)
++   (UNSPEC_NTPOFF               22)
++   (UNSPEC_DTPOFF               23)
++   (UNSPEC_TP                   24)
++   (UNSPEC_TLS_GD               25)
++   (UNSPEC_TLS_LD_BASE          26)
++
++   ; For SSE/MMX support:
++   (UNSPEC_FIX                  30)
++   (UNSPEC_MASKMOV              32)
++   (UNSPEC_MOVMSK               33)
++   (UNSPEC_MOVNT                34)
++   (UNSPEC_MOVA                 38)
++   (UNSPEC_MOVU                 39)
++   (UNSPEC_SHUFFLE              41)
++   (UNSPEC_RCP                  42)
++   (UNSPEC_RSQRT                43)
++   (UNSPEC_SFENCE               44)
++   (UNSPEC_NOP                  45)     ; prevents combiner cleverness
++   (UNSPEC_PAVGUSB              49)
++   (UNSPEC_PFRCP                50)
++   (UNSPEC_PFRCPIT1             51)
++   (UNSPEC_PFRCPIT2             52)
++   (UNSPEC_PFRSQRT              53)
++   (UNSPEC_PFRSQIT1             54)
++  ])
+ ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
+ ;; from i386.c.
+@@ -1759,7 +1763,7 @@
+       return "lea{l}\t{%1, %0|%0, %1}";
+     default:
+-      if (flag_pic && SYMBOLIC_CONST (operands[1]))
++      if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1]))
+       abort();
+       return "mov{l}\t{%1, %0|%0, %1}";
+     }
+@@ -2525,7 +2529,7 @@
+     case TYPE_LEA:
+       return "lea{q}\t{%a1, %0|%0, %a1}";
+     default:
+-      if (flag_pic && SYMBOLIC_CONST (operands[1]))
++      if (flag_pic && !LEGITIMATE_PIC_OPERAND_P (operands[1]))
+       abort ();
+       if (get_attr_mode (insn) == MODE_SI)
+       return "mov{l}\t{%k1, %k0|%k0, %k1}";
+@@ -13474,21 +13478,8 @@
+                           (match_operand:SI 3 "" "")))])]
+   "!TARGET_64BIT"
+ {
+-  if (operands[3] == const0_rtx)
+-    {
+-      emit_insn (gen_call (operands[0], operands[1], constm1_rtx));
+-      DONE;
+-    }
+-  /* Static functions and indirect calls don't need
+-     current_function_uses_pic_offset_table.  */
+-  if (flag_pic
+-      && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+-      && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+-    current_function_uses_pic_offset_table = 1;
+-  if (! call_insn_operand (XEXP (operands[0], 0), Pmode))
+-    XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+-  if (TARGET_64BIT)
+-    abort();
++  ix86_expand_call (NULL, operands[0], operands[1], operands[2], operands[3]);
++  DONE;
+ })
+ (define_insn "*call_pop_0"
+@@ -13530,37 +13521,12 @@
+   [(call (match_operand:QI 0 "" "")
+        (match_operand 1 "" ""))
+    (use (match_operand 2 "" ""))]
+-  ;; Operand 1 not used on the i386.
+   ""
+ {
+-  rtx insn;
+-  /* Static functions and indirect calls don't need
+-     current_function_uses_pic_offset_table.  */
+-  if (flag_pic
+-      && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF
+-      && ! SYMBOL_REF_FLAG (XEXP (operands[0], 0)))
+-    current_function_uses_pic_offset_table = 1;
+-
+-  if (! call_insn_operand (XEXP (operands[0], 0), Pmode))
+-    XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+-  if (TARGET_64BIT && INTVAL (operands[2]) >= 0)
+-    {
+-      rtx reg = gen_rtx_REG (QImode, 0);
+-      emit_move_insn (reg, operands[2]);
+-      insn = emit_call_insn (gen_call_exp (operands[0], operands[1]));
+-      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
+-      DONE;
+-    }
+-   insn = emit_call_insn (gen_call_exp (operands[0], operands[1]));
+-   DONE;
++  ix86_expand_call (NULL, operands[0], operands[1], operands[2], NULL);
++  DONE;
+ })
+-(define_expand "call_exp"
+-  [(call (match_operand:QI 0 "" "")
+-       (match_operand 1 "" ""))]
+-  ""
+-  "")
+-
+ (define_insn "*call_0"
+   [(call (mem:QI (match_operand 0 "constant_call_address_operand" ""))
+        (match_operand 1 "" ""))]
+@@ -13612,7 +13578,6 @@
+   [(set_attr "type" "call")])
+ ;; Call subroutine, returning value in operand 0
+-;; (which must be a hard register).
+ (define_expand "call_value_pop"
+   [(parallel [(set (match_operand 0 "" "")
+@@ -13623,20 +13588,9 @@
+                           (match_operand:SI 4 "" "")))])]
+   "!TARGET_64BIT"
+ {
+-  if (operands[4] == const0_rtx)
+-    {
+-      emit_insn (gen_call_value (operands[0], operands[1], operands[2],
+-                               constm1_rtx));
+-      DONE;
+-    }
+-  /* Static functions and indirect calls don't need
+-     current_function_uses_pic_offset_table.  */
+-  if (flag_pic
+-      && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+-      && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+-    current_function_uses_pic_offset_table = 1;
+-  if (! call_insn_operand (XEXP (operands[1], 0), Pmode))
+-    XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
++  ix86_expand_call (operands[0], operands[1], operands[2],
++                  operands[3], operands[4]);
++  DONE;
+ })
+ (define_expand "call_value"
+@@ -13647,36 +13601,10 @@
+   ;; Operand 2 not used on the i386.
+   ""
+ {
+-  rtx insn;
+-  /* Static functions and indirect calls don't need
+-     current_function_uses_pic_offset_table.  */
+-  if (flag_pic
+-      && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
+-      && ! SYMBOL_REF_FLAG (XEXP (operands[1], 0)))
+-    current_function_uses_pic_offset_table = 1;
+-  if (! call_insn_operand (XEXP (operands[1], 0), Pmode))
+-    XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
+-  if (TARGET_64BIT && INTVAL (operands[3]) >= 0)
+-    {
+-      rtx reg = gen_rtx_REG (QImode, 0);
+-      emit_move_insn (reg, operands[3]);
+-      insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1],
+-                                               operands[2]));
+-      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
+-      DONE;
+-    }
+-  insn = emit_call_insn (gen_call_value_exp (operands[0], operands[1],
+-                                           operands[2]));
++  ix86_expand_call (operands[0], operands[1], operands[2], operands[3], NULL);
+   DONE;
+ })
+-(define_expand "call_value_exp"
+-  [(set (match_operand 0 "" "")
+-      (call (match_operand:QI 1 "" "")
+-            (match_operand:SI 2 "" "")))]
+-  ""
+-  "")
+-
+ ;; Call subroutine returning any type.
+ (define_expand "untyped_call"
+@@ -13693,12 +13621,10 @@
+      simply pretend the untyped call returns a complex long double
+      value.  */
+-  emit_call_insn (TARGET_FLOAT_RETURNS_IN_80387
+-                  ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG),
+-                                  operands[0], const0_rtx,
+-                                  GEN_INT (SSE_REGPARM_MAX - 1))
+-                  : gen_call (operands[0], const0_rtx,
+-                            GEN_INT (SSE_REGPARM_MAX - 1)));
++  ix86_expand_call ((TARGET_FLOAT_RETURNS_IN_80387
++                   ? gen_rtx_REG (XCmode, FIRST_FLOAT_REG) : NULL),
++                  operands[0], const0_rtx, GEN_INT (SSE_REGPARM_MAX - 1),
++                  NULL);
+   for (i = 0; i < XVECLEN (operands[2], 0); i++)
+     {
+@@ -13781,45 +13707,39 @@
+   ""
+   "ix86_expand_prologue (); DONE;")
+-(define_insn "prologue_set_got"
++(define_expand "set_got"
++  [(parallel [(set (match_operand:SI 0 "register_operand" "")
++                 (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++            (clobber (reg:CC 17))])]
++  "!TARGET_64BIT"
++  "")
++
++(define_insn "*set_got_nopic"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+-      (unspec_volatile:SI
+-       [(plus:SI (match_dup 0)
+-                 (plus:SI (match_operand:SI 1 "symbolic_operand" "")
+-                          (minus:SI (pc) (match_operand 2 "" ""))))] 1))
++      (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
+    (clobber (reg:CC 17))]
+-  "!TARGET_64BIT"
+-{
+-  if (GET_CODE (operands[2]) == LABEL_REF)
+-     operands[2] = XEXP (operands[2], 0);
+-  if (TARGET_DEEP_BRANCH_PREDICTION) 
+-    return "add{l}\t{%1, %0|%0, %1}";
+-  else  
+-    return "add{l}\t{%1+[.-%X2], %0|%0, %a1+(.-%X2)}";
+-}
+-  [(set_attr "type" "alu")
+-   ; Since this insn may have two constant operands, we must set the
+-   ; length manually.
+-   (set_attr "length_immediate" "4")
+-   (set_attr "mode" "SI")])
++  "!TARGET_64BIT && !flag_pic"
++  { return output_set_got (operands[0]); }
++  [(set_attr "type" "multi")
++   (set_attr "length" "11")])
++  
++(define_insn "*set_got_deep"
++  [(set (match_operand:SI 0 "register_operand" "=b")
++      (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++   (clobber (reg:CC 17))]
++  "!TARGET_64BIT && TARGET_DEEP_BRANCH_PREDICTION"
++  { return output_set_got (operands[0]); }
++  [(set_attr "type" "multi")
++   (set_attr "length" "11")])
+-(define_insn "prologue_get_pc"
++(define_insn "*set_got_nodeep"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+-    (unspec_volatile:SI [(plus:SI (pc) (match_operand 1 "" ""))] 2))]
++      (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
++   (clobber (reg:CC 17))]
+   "!TARGET_64BIT"
+-{
+-  if (GET_CODE (operands[1]) == LABEL_REF)
+-    operands[1] = XEXP (operands[1], 0);
+-  output_asm_insn ("call\t%X1", operands);
+-  if (! TARGET_DEEP_BRANCH_PREDICTION)
+-    {
+-      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+-                               CODE_LABEL_NUMBER (operands[1]));
+-      return "pop{l}\t%0";
+-    }
+-  RET;
+-}
+-  [(set_attr "type" "multi")])
++  { return output_set_got (operands[0]); }
++  [(set_attr "type" "multi")
++   (set_attr "length" "12")])
+ (define_expand "epilogue"
+   [(const_int 1)]
+@@ -13996,6 +13916,127 @@
+ ;; ffshi2 is not useful -- 4 word prefix ops are needed, which is larger
+ ;; and slower than the two-byte movzx insn needed to do the work in SImode.
\f
++;; Thread-local storage patterns for ELF.
++;;
++;; Note that these code sequences must appear exactly as shown
++;; in order to allow linker relaxation.
++
++(define_insn "*tls_global_dynamic_gnu"
++  [(set (match_operand:SI 0 "register_operand" "=a")
++      (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++                  (match_operand:SI 2 "tls_symbolic_operand" "")
++                  (match_operand:SI 3 "call_insn_operand" "")]
++                  UNSPEC_TLS_GD))
++   (clobber (match_scratch:SI 4 "=d"))
++   (clobber (match_scratch:SI 5 "=c"))
++   (clobber (reg:CC 17))]
++  "TARGET_GNU_TLS"
++  "lea{l}\t{%a2@TLSGD(,%1,1), %0|%0, %a2@TLSGD[%1*1]}\;call\t%P3"
++  [(set_attr "type" "multi")
++   (set_attr "length" "12")])
++
++(define_insn "*tls_global_dynamic_sun"
++  [(set (match_operand:SI 0 "register_operand" "=a")
++      (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++                  (match_operand:SI 2 "tls_symbolic_operand" "")
++                  (match_operand:SI 3 "call_insn_operand" "")]
++                  UNSPEC_TLS_GD))
++   (clobber (match_scratch:SI 4 "=d"))
++   (clobber (match_scratch:SI 5 "=c"))
++   (clobber (reg:CC 17))]
++  "TARGET_SUN_TLS"
++  "lea{l}\t{%a2@DTLNDX(%1), %4|%4, %a2@DTLNDX[%1]}
++      push{l}\t%4\;call\t%a2@TLSPLT\;pop{l}\t%4\;nop"
++  [(set_attr "type" "multi")
++   (set_attr "length" "14")])
++
++(define_expand "tls_global_dynamic"
++  [(parallel [(set (match_operand:SI 0 "register_operand" "")
++                 (unspec:SI
++                  [(match_dup 2)
++                   (match_operand:SI 1 "tls_symbolic_operand" "")
++                   (match_dup 3)]
++                  UNSPEC_TLS_GD))
++            (clobber (match_scratch:SI 4 ""))
++            (clobber (match_scratch:SI 5 ""))
++            (clobber (reg:CC 17))])]
++  ""
++{
++  if (!flag_pic)
++    abort ();
++  current_function_uses_pic_offset_table = 1;
++  operands[2] = pic_offset_table_rtx;
++  operands[3] = ix86_tls_get_addr ();
++})
++
++(define_insn "*tls_local_dynamic_base_gnu"
++  [(set (match_operand:SI 0 "register_operand" "=a")
++      (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++                    (match_operand:SI 2 "call_insn_operand" "")]
++                 UNSPEC_TLS_LD_BASE))
++   (clobber (match_scratch:SI 3 "=d"))
++   (clobber (match_scratch:SI 4 "=c"))
++   (clobber (reg:CC 17))]
++  "TARGET_GNU_TLS"
++  "lea{l}\t{%&@TLSLDM(%1), %0|%0, %&@TLSLDM[%1]}\;call\t%P2"
++  [(set_attr "type" "multi")
++   (set_attr "length" "11")])
++
++(define_insn "*tls_local_dynamic_base_sun"
++  [(set (match_operand:SI 0 "register_operand" "=a")
++      (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++                    (match_operand:SI 2 "call_insn_operand" "")]
++                 UNSPEC_TLS_LD_BASE))
++   (clobber (match_scratch:SI 3 "=d"))
++   (clobber (match_scratch:SI 4 "=c"))
++   (clobber (reg:CC 17))]
++  "TARGET_SUN_TLS"
++  "lea{l}\t{%&@TMDNX(%1), %3|%3, %&@TMDNX[%1]}
++      push{l}\t%3\;call\t%&@TLSPLT\;pop{l}\t%3"
++  [(set_attr "type" "multi")
++   (set_attr "length" "13")])
++
++(define_expand "tls_local_dynamic_base"
++  [(parallel [(set (match_operand:SI 0 "register_operand" "")
++                 (unspec:SI [(match_dup 1) (match_dup 2)]
++                            UNSPEC_TLS_LD_BASE))
++            (clobber (match_scratch:SI 3 ""))
++            (clobber (match_scratch:SI 4 ""))
++            (clobber (reg:CC 17))])]
++  ""
++{
++  if (!flag_pic)
++    abort ();
++  current_function_uses_pic_offset_table = 1;
++  operands[1] = pic_offset_table_rtx;
++  operands[2] = ix86_tls_get_addr ();
++})
++
++;; Local dynamic of a single variable is a lose.  Show combine how
++;; to convert that back to global dynamic.
++
++(define_insn_and_split "*tls_local_dynamic_once"
++  [(set (match_operand:SI 0 "register_operand" "=a")
++      (plus:SI (unspec:SI [(match_operand:SI 1 "register_operand" "b")
++                           (match_operand:SI 2 "call_insn_operand" "")]
++                          UNSPEC_TLS_LD_BASE)
++               (const:SI (unspec:SI
++                          [(match_operand:SI 3 "tls_symbolic_operand" "")]
++                          UNSPEC_DTPOFF))))
++   (clobber (match_scratch:SI 4 "=d"))
++   (clobber (match_scratch:SI 5 "=c"))
++   (clobber (reg:CC 17))]
++  ""
++  "#"
++  ""
++  [(parallel [(set (match_dup 0)
++                 (unspec:SI [(match_dup 1) (match_dup 3) (match_dup 2)]
++                            UNSPEC_TLS_GD))
++            (clobber (match_dup 4))
++            (clobber (match_dup 5))
++            (clobber (reg:CC 17))])]
++  "")
++\f
+ ;; These patterns match the binary 387 instructions for addM3, subM3,
+ ;; mulM3 and divM3.  There are three patterns for each of DFmode and
+ ;; SFmode.  The first is the normal insn, the second the same insn but
+@@ -16835,7 +16876,7 @@
+   [(label_ref (match_operand 0 "" ""))]
+   "!TARGET_64BIT && flag_pic"
+ {
+-  load_pic_register ();
++  emit_insn (gen_set_got (pic_offset_table_rtx));
+   DONE;
+ })
\f
+--- gcc/config/ia64/ia64-protos.h.jj   Tue Apr 23 20:28:20 2002
++++ gcc/config/ia64/ia64-protos.h      Wed Jun 19 19:33:52 2002
+@@ -31,6 +31,7 @@ extern int call_operand PARAMS((rtx, enu
+ extern int sdata_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int got_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int symbolic_operand PARAMS((rtx, enum machine_mode));
++extern int tls_symbolic_operand PARAMS((rtx, enum machine_mode));
+ extern int function_operand PARAMS((rtx, enum machine_mode));
+ extern int setjmp_operand PARAMS((rtx, enum machine_mode));
+ extern int move_operand PARAMS((rtx, enum machine_mode));
+@@ -67,6 +68,7 @@ extern int general_tfmode_operand PARAMS
+ extern int destination_tfmode_operand PARAMS((rtx, enum machine_mode));
+ extern int tfreg_or_fp01_operand PARAMS((rtx, enum machine_mode));
++extern rtx ia64_expand_move PARAMS ((rtx, rtx));
+ extern int ia64_move_ok PARAMS((rtx, rtx));
+ extern int ia64_depz_field_mask PARAMS((rtx, rtx));
+ extern rtx ia64_gp_save_reg PARAMS((int));
+--- gcc/config/ia64/ia64.c.jj  Wed Jun 19 22:36:54 2002
++++ gcc/config/ia64/ia64.c     Wed Jun 19 22:46:07 2002
+@@ -95,6 +95,13 @@ static const char * const ia64_output_re
+ /* String used with the -mfixed-range= option.  */
+ const char *ia64_fixed_range_string;
++/* Determines whether we use adds, addl, or movl to generate our
++   TLS immediate offsets.  */
++int ia64_tls_size = 22;
++
++/* String used with the -mtls-size= option.  */
++const char *ia64_tls_size_string;
++
+ /* Determines whether we run our final scheduling pass or not.  We always
+    avoid the normal second scheduling pass.  */
+ static int ia64_flag_schedule_insns2;
+@@ -104,6 +111,8 @@ static int ia64_flag_schedule_insns2;
+ unsigned int ia64_section_threshold;
\f
++static rtx gen_tls_get_addr PARAMS ((void));
++static rtx gen_thread_pointer PARAMS ((void));
+ static int find_gr_spill PARAMS ((int));
+ static int next_scratch_gr_reg PARAMS ((void));
+ static void mark_reg_gr_used_mask PARAMS ((rtx, void *));
+@@ -214,6 +223,11 @@ static const struct attribute_spec ia64_
+ #undef TARGET_SCHED_CYCLE_DISPLAY
+ #define TARGET_SCHED_CYCLE_DISPLAY ia64_cycle_display
++#ifdef HAVE_AS_TLS
++#undef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS true
++#endif
++
+ struct gcc_target targetm = TARGET_INITIALIZER;
\f
+ /* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
+@@ -250,7 +264,10 @@ sdata_symbolic_operand (op, mode)
+       if (CONSTANT_POOL_ADDRESS_P (op))
+       return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
+       else
+-        return XSTR (op, 0)[0] == SDATA_NAME_FLAG_CHAR;
++      {
++        const char *str = XSTR (op, 0);
++          return (str[0] == ENCODE_SECTION_INFO_CHAR && str[1] == 's');
++      }
+     default:
+       break;
+@@ -324,6 +341,35 @@ symbolic_operand (op, mode)
+   return 0;
+ }
++/* Return tls_model if OP refers to a TLS symbol.  */
++
++int
++tls_symbolic_operand (op, mode)
++     rtx op;
++     enum machine_mode mode ATTRIBUTE_UNUSED;
++{
++  const char *str;
++
++  if (GET_CODE (op) != SYMBOL_REF)
++    return 0;
++  str = XSTR (op, 0);
++  if (str[0] != ENCODE_SECTION_INFO_CHAR)
++    return 0;
++  switch (str[1])
++    {
++    case 'G':
++      return TLS_MODEL_GLOBAL_DYNAMIC;
++    case 'L':
++      return TLS_MODEL_LOCAL_DYNAMIC;
++    case 'i':
++      return TLS_MODEL_INITIAL_EXEC;
++    case 'l':
++      return TLS_MODEL_LOCAL_EXEC;
++    }
++  return 0;
++}
++
++
+ /* Return 1 if OP refers to a function.  */
+ int
+@@ -922,6 +968,9 @@ ia64_expand_load_address (dest, src, scr
+   else
+     temp = dest;
++  if (tls_symbolic_operand (src, Pmode))
++    abort ();
++
+   if (TARGET_AUTO_PIC)
+     emit_insn (gen_load_gprel64 (temp, src));
+   else if (GET_CODE (src) == SYMBOL_REF && SYMBOL_REF_FLAG (src))
+@@ -964,6 +1013,185 @@ ia64_expand_load_address (dest, src, scr
+     emit_move_insn (dest, temp);
+ }
++static rtx
++gen_tls_get_addr ()
++{
++  static rtx tga;
++  if (!tga)
++    {
++      tga = init_one_libfunc ("__tls_get_addr");
++      ggc_add_rtx_root (&tga, 1);
++    }
++  return tga;
++}
++
++static rtx
++gen_thread_pointer ()
++{
++  static rtx tp;
++  if (!tp)
++    {
++      tp = gen_rtx_REG (Pmode, 13);
++      RTX_UNCHANGING_P (tp) = 1;
++      ggc_add_rtx_root (&tp, 1);
++    }
++  return tp;
++}
++
++rtx
++ia64_expand_move (op0, op1)
++     rtx op0, op1;
++{
++  enum machine_mode mode = GET_MODE (op0);
++
++  if (!reload_in_progress && !reload_completed && !ia64_move_ok (op0, op1))
++    op1 = force_reg (mode, op1);
++
++  if (mode == Pmode)
++    {
++      enum tls_model tls_kind;
++      if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
++      {
++        rtx tga_op1, tga_op2, tga_ret, tga_eqv, tmp, insns;
++
++        switch (tls_kind)
++          {
++          case TLS_MODEL_GLOBAL_DYNAMIC:
++            start_sequence ();
++
++            tga_op1 = gen_reg_rtx (Pmode);
++            emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1));
++            tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
++            RTX_UNCHANGING_P (tga_op1) = 1;
++
++            tga_op2 = gen_reg_rtx (Pmode);
++            emit_insn (gen_load_ltoff_dtprel (tga_op2, op1));
++            tga_op2 = gen_rtx_MEM (Pmode, tga_op2);
++            RTX_UNCHANGING_P (tga_op2) = 1;
++            
++            tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX,
++                                               LCT_CONST, Pmode, 2, tga_op1,
++                                               Pmode, tga_op2, Pmode);
++
++            insns = get_insns ();
++            end_sequence ();
++
++            emit_libcall_block (insns, op0, tga_ret, op1);
++            return NULL_RTX;
++
++          case TLS_MODEL_LOCAL_DYNAMIC:
++            /* ??? This isn't the completely proper way to do local-dynamic
++               If the call to __tls_get_addr is used only by a single symbol,
++               then we should (somehow) move the dtprel to the second arg
++               to avoid the extra add.  */
++            start_sequence ();
++
++            tga_op1 = gen_reg_rtx (Pmode);
++            emit_insn (gen_load_ltoff_dtpmod (tga_op1, op1));
++            tga_op1 = gen_rtx_MEM (Pmode, tga_op1);
++            RTX_UNCHANGING_P (tga_op1) = 1;
++
++            tga_op2 = const0_rtx;
++
++            tga_ret = emit_library_call_value (gen_tls_get_addr (), NULL_RTX,
++                                               LCT_CONST, Pmode, 2, tga_op1,
++                                               Pmode, tga_op2, Pmode);
++
++            insns = get_insns ();
++            end_sequence ();
++
++            tga_eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
++                                      UNSPEC_LD_BASE);
++            tmp = gen_reg_rtx (Pmode);
++            emit_libcall_block (insns, tmp, tga_ret, tga_eqv);
++
++            if (register_operand (op0, Pmode))
++              tga_ret = op0;
++            else
++              tga_ret = gen_reg_rtx (Pmode);
++            if (TARGET_TLS64)
++              {
++                emit_insn (gen_load_dtprel (tga_ret, op1));
++                emit_insn (gen_adddi3 (tga_ret, tmp, tga_ret));
++              }
++            else
++              emit_insn (gen_add_dtprel (tga_ret, tmp, op1));
++            if (tga_ret == op0)
++              return NULL_RTX;
++            op1 = tga_ret;
++            break;
++
++          case TLS_MODEL_INITIAL_EXEC:
++            tmp = gen_reg_rtx (Pmode);
++            emit_insn (gen_load_ltoff_tprel (tmp, op1));
++            tmp = gen_rtx_MEM (Pmode, tmp);
++            RTX_UNCHANGING_P (tmp) = 1;
++            tmp = force_reg (Pmode, tmp);
++
++            if (register_operand (op0, Pmode))
++              op1 = op0;
++            else
++              op1 = gen_reg_rtx (Pmode);
++            emit_insn (gen_adddi3 (op1, tmp, gen_thread_pointer ()));
++            if (op1 == op0)
++              return NULL_RTX;
++            break;
++
++          case TLS_MODEL_LOCAL_EXEC:
++            if (register_operand (op0, Pmode))
++              tmp = op0;
++            else
++              tmp = gen_reg_rtx (Pmode);
++            if (TARGET_TLS64)
++              {
++                emit_insn (gen_load_tprel (tmp, op1));
++                emit_insn (gen_adddi3 (tmp, gen_thread_pointer (), tmp));
++              }
++            else
++              emit_insn (gen_add_tprel (tmp, gen_thread_pointer (), op1));
++            if (tmp == op0)
++              return NULL_RTX;
++            op1 = tmp;
++            break;
++
++          default:
++            abort ();
++          }
++      }
++      else if (!TARGET_NO_PIC && symbolic_operand (op1, DImode))
++      {
++        /* Before optimization starts, delay committing to any particular
++           type of PIC address load.  If this function gets deferred, we
++           may acquire information that changes the value of the
++           sdata_symbolic_operand predicate.
++
++           But don't delay for function pointers.  Loading a function address
++           actually loads the address of the descriptor not the function.
++           If we represent these as SYMBOL_REFs, then they get cse'd with
++           calls, and we end up with calls to the descriptor address instead
++           of calls to the function address.  Functions are not candidates
++           for sdata anyways.
++
++           Don't delay for LABEL_REF because the splitter loses REG_LABEL
++           notes.  Don't delay for pool addresses on general principals;
++           they'll never become non-local behind our back.  */
++
++        if (rtx_equal_function_value_matters
++            && GET_CODE (op1) != LABEL_REF
++            && ! (GET_CODE (op1) == SYMBOL_REF
++                  && (SYMBOL_REF_FLAG (op1)
++                      || CONSTANT_POOL_ADDRESS_P (op1)
++                      || STRING_POOL_ADDRESS_P (op1))))
++          emit_insn (gen_movdi_symbolic (op0, op1));
++        else
++          ia64_expand_load_address (op0, op1, NULL_RTX);
++        return NULL_RTX;
++      }
++    }
++
++  return op1;
++}
++
+ rtx
+ ia64_gp_save_reg (setjmp_p)
+      int setjmp_p;
+@@ -3944,6 +4172,16 @@ ia64_override_options ()
+   if (ia64_fixed_range_string)
+     fix_range (ia64_fixed_range_string);
++  if (ia64_tls_size_string)
++    {
++      char *end;
++      unsigned long tmp = strtoul (ia64_tls_size_string, &end, 10);
++      if (*end || (tmp != 14 && tmp != 22 && tmp != 64))
++      error ("bad value (%s) for -mtls-size= switch", ia64_tls_size_string);
++      else
++      ia64_tls_size = tmp;
++    }
++
+   ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload;
+   flag_schedule_insns_after_reload = 0;
+@@ -4607,6 +4845,13 @@ rtx_needs_barrier (x, flags, pred)
+         need_barrier |= rtx_needs_barrier (XVECEXP (x, 0, 2), flags, pred);
+         break;
++      case UNSPEC_LTOFF_DTPMOD:
++      case UNSPEC_LTOFF_DTPREL:
++      case UNSPEC_DTPREL:
++      case UNSPEC_LTOFF_TPREL:
++      case UNSPEC_TPREL:
++          break;
++
+       default:
+         abort ();
+       }
+@@ -6872,6 +7117,9 @@ ia64_encode_section_info (decl)
+      tree decl;
+ {
+   const char *symbol_str;
++  bool is_local, is_small;
++  rtx symbol;
++  char encoding = 0;
+   if (TREE_CODE (decl) == FUNCTION_DECL)
+     {
+@@ -6885,75 +7133,111 @@ ia64_encode_section_info (decl)
+       || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
+     return;
+     
+-  symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
++  symbol = XEXP (DECL_RTL (decl), 0);
++  symbol_str = XSTR (symbol, 0);
++
++  /* A non-decl is an entry in the constant pool.  */
++  if (!DECL_P (decl))
++    is_local = true;
++  /* Static variables are always local.  */
++  else if (! TREE_PUBLIC (decl))
++    is_local = true;
++  /* A variable is local if the user tells us so.  */
++  else if (MODULE_LOCAL_P (decl))
++    is_local = true;
++  /* Otherwise, variables defined outside this object may not be local.  */
++  else if (DECL_EXTERNAL (decl))
++    is_local = false;
++  /* Linkonce and weak data are never local.  */
++  else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
++    is_local = false;
++  /* If PIC, then assume that any global name can be overridden by
++     symbols resolved from other modules.  */
++  else if (flag_pic)
++    is_local = false;
++  /* Uninitialized COMMON variable may be unified with symbols
++     resolved from other modules.  */
++  else if (DECL_COMMON (decl)
++         && (DECL_INITIAL (decl) == NULL
++             || DECL_INITIAL (decl) == error_mark_node))
++    is_local = false;
++  /* Otherwise we're left with initialized (or non-common) global data
++     which is of necessity defined locally.  */
++  else
++    is_local = true;
+-  /* We assume that -fpic is used only to create a shared library (dso).
+-     With -fpic, no global data can ever be sdata.
+-     Without -fpic, global common uninitialized data can never be sdata, since
+-     it can unify with a real definition in a dso.  */
+-  /* ??? Actually, we can put globals in sdata, as long as we don't use gprel
+-     to access them.  The linker may then be able to do linker relaxation to
+-     optimize references to them.  Currently sdata implies use of gprel.  */
+-  /* We need the DECL_EXTERNAL check for C++.  static class data members get
+-     both TREE_STATIC and DECL_EXTERNAL set, to indicate that they are
+-     statically allocated, but the space is allocated somewhere else.  Such
+-     decls can not be own data.  */
+-  if (! TARGET_NO_SDATA
+-      && ((TREE_STATIC (decl) && ! DECL_EXTERNAL (decl)
+-         && ! (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+-         && ! (TREE_PUBLIC (decl)
+-               && (flag_pic
+-                   || (DECL_COMMON (decl)
+-                       && (DECL_INITIAL (decl) == 0
+-                           || DECL_INITIAL (decl) == error_mark_node)))))
+-        || MODULE_LOCAL_P (decl))
+-      /* Either the variable must be declared without a section attribute,
+-       or the section must be sdata or sbss.  */
+-      && (DECL_SECTION_NAME (decl) == 0
+-        || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+-                     ".sdata")
+-        || ! strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+-                     ".sbss")))
++  is_small = false;
++  if (TARGET_NO_SDATA)
++    ;
++  else if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
++    {
++      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
++      if (strcmp (section, ".sdata") == 0
++        || strcmp (section, ".sbss") == 0)
++      is_small = true;
++    }
++  else
+     {
+       HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+-      /* If the variable has already been defined in the output file, then it
+-       is too late to put it in sdata if it wasn't put there in the first
+-       place.  The test is here rather than above, because if it is already
+-       in sdata, then it can stay there.  */
+-
+-      if (TREE_ASM_WRITTEN (decl))
+-      ;
+-
+-      /* If this is an incomplete type with size 0, then we can't put it in
+-       sdata because it might be too big when completed.
+-       Objects bigger than threshold should have SDATA_NAME_FLAG_CHAR
+-       added if they are in .sdata or .sbss explicitely.  */
+-      else if (((size > 0
+-               && size <= (HOST_WIDE_INT) ia64_section_threshold)
+-              || DECL_SECTION_NAME (decl))
+-             && symbol_str[0] != SDATA_NAME_FLAG_CHAR)
+-      {
+-        size_t len = strlen (symbol_str);
+-        char *newstr = alloca (len + 1);
+-        const char *string;
++      /* If this is an incomplete type with size 0, then we can't put it
++       in sdata because it might be too big when completed.  */
++      if (size > 0 && size <= ia64_section_threshold)
++      is_small = true;
++    }
+-        *newstr = SDATA_NAME_FLAG_CHAR;
+-        memcpy (newstr + 1, symbol_str, len + 1);
+-        
+-        string = ggc_alloc_string (newstr, len + 1);
+-        XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
++  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++    {
++      enum tls_model kind;
++      if (!flag_pic)
++      {
++        if (is_local)
++          kind = TLS_MODEL_LOCAL_EXEC;
++        else
++          kind = TLS_MODEL_INITIAL_EXEC;
+       }
+-    }
+-  /* This decl is marked as being in small data/bss but it shouldn't
+-     be; one likely explanation for this is that the decl has been
+-     moved into a different section from the one it was in when
+-     ENCODE_SECTION_INFO was first called.  Remove the '@'.  */
+-  else if (symbol_str[0] == SDATA_NAME_FLAG_CHAR)
++      else if (is_local)
++      kind = TLS_MODEL_LOCAL_DYNAMIC;
++      else
++      kind = TLS_MODEL_GLOBAL_DYNAMIC;
++      if (kind < flag_tls_default)
++      kind = flag_tls_default;
++
++      encoding = " GLil"[kind];
++    }
++  /* Determine if DECL will wind up in .sdata/.sbss.  */
++  else if (is_local && is_small)
++    encoding = 's';
++  
++  /* Finally, encode this into the symbol string.  */
++  if (encoding)
+     {
+-      XSTR (XEXP (DECL_RTL (decl), 0), 0)
+-      = ggc_strdup (symbol_str + 1);
++      char *newstr;
++      size_t len;
++  
++      if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
++      {
++        if (encoding == symbol_str[1])
++          return;
++        /* ??? Sdata became thread or thread becaome not thread.  Lose.  */
++        abort ();
++      }
++
++      len = strlen (symbol_str);
++      newstr = alloca (len + 3);
++      newstr[0] = ENCODE_SECTION_INFO_CHAR;
++      newstr[1] = encoding;
++      memcpy (newstr + 2, symbol_str, len + 1);
++
++      XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2);
+     }
++  
++  /* This decl is marked as being in small data/bss but it shouldn't be;
++     one likely explanation for this is that the decl has been moved into
++     a different section from the one it was in when encode_section_info
++     was first called.  Remove the encoding.  */
++  else if (symbol_str[0] == ENCODE_SECTION_INFO_CHAR)
++    XSTR (symbol, 0) = ggc_strdup (symbol_str + 2);
+ }
\f
+ /* Output assembly directives for prologue regions.  */
+--- gcc/config/ia64/ia64.h.jj  Tue Apr 23 20:28:21 2002
++++ gcc/config/ia64/ia64.h     Wed Jun 19 19:33:52 2002
+@@ -109,6 +109,11 @@ extern int target_flags;
+ #define TARGET_DWARF2_ASM     (target_flags & MASK_DWARF2_ASM)
++extern int ia64_tls_size;
++#define TARGET_TLS14          (ia64_tls_size == 14)
++#define TARGET_TLS22          (ia64_tls_size == 22)
++#define TARGET_TLS64          (ia64_tls_size == 64)
++
+ /* This macro defines names of command options to set and clear bits in
+    `target_flags'.  Its definition is an initializer with a subgrouping for
+    each command option.  */
+@@ -177,10 +182,13 @@ extern int target_flags;
+    subgrouping for each command option.  */
+ extern const char *ia64_fixed_range_string;
++extern const char *ia64_tls_size_string;
+ #define TARGET_OPTIONS \
+ {                                                                     \
+   { "fixed-range=",   &ia64_fixed_range_string,                       \
+       N_("Specify range of registers to make fixed")},                        \
++  { "tls-size=",      &ia64_tls_size_string,                          \
++      N_("Specify bit size of immediate TLS offsets")},                       \
+ }
+ /* Sometimes certain combinations of command options do not make sense on a
+@@ -1801,7 +1809,7 @@ do {                                                                     \
+     && (DECL_ONE_ONLY (DECL) || DECL_WEAK (DECL) || DECL_COMMON (DECL)        \
+       || DECL_SECTION_NAME (DECL) != 0))
+-#define SDATA_NAME_FLAG_CHAR '@'
++#define ENCODE_SECTION_INFO_CHAR '@'
+ #define IA64_DEFAULT_GVALUE 8
+@@ -1811,8 +1819,8 @@ do {                                                                     \
+ #define STRIP_NAME_ENCODING(VAR, SYMBOL_NAME) \
+ do {                                          \
+   (VAR) = (SYMBOL_NAME);                      \
+-  if ((VAR)[0] == SDATA_NAME_FLAG_CHAR)               \
+-    (VAR)++;                                  \
++  if ((VAR)[0] == ENCODE_SECTION_INFO_CHAR)   \
++    (VAR) += 2;                                       \
+   if ((VAR)[0] == '*')                                \
+     (VAR)++;                                  \
+ } while (0)
+--- gcc/config/ia64/ia64.md.jj Tue Apr 23 20:28:21 2002
++++ gcc/config/ia64/ia64.md    Wed Jun 19 19:33:52 2002
+@@ -68,7 +68,19 @@
+ ;;    23      cycle display
+ ;;      24      addp4
+ ;;    25      prologue_use
+-;;
++
++;; More unspec:
++
++(define_constants
++  [; Relocations
++   (UNSPEC_LTOFF_DTPMOD               14)
++   (UNSPEC_LTOFF_DTPREL               15)
++   (UNSPEC_DTPREL             16)
++   (UNSPEC_LTOFF_TPREL                17)
++   (UNSPEC_TPREL              18)
++   (UNSPEC_LD_BASE            26)
++  ])
++
+ ;; unspec_volatile:
+ ;;    0       alloc
+ ;;    1       blockage
+@@ -272,12 +284,12 @@
+   [(set (match_operand:QI 0 "general_operand" "")
+       (match_operand:QI 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (QImode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn "*movqi_internal"
+   [(set (match_operand:QI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
+@@ -297,12 +309,12 @@
+   [(set (match_operand:HI 0 "general_operand" "")
+       (match_operand:HI 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (HImode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn "*movhi_internal"
+   [(set (match_operand:HI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
+@@ -322,12 +334,12 @@
+   [(set (match_operand:SI 0 "general_operand" "")
+       (match_operand:SI 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (SImode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn "*movsi_internal"
+   [(set (match_operand:SI 0 "destination_operand" "=r,r,r,r, m, r,*f,*f, r,*d")
+@@ -351,32 +363,12 @@
+   [(set (match_operand:DI 0 "general_operand" "")
+       (match_operand:DI 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (DImode, operands[1]);
+-  if (! TARGET_NO_PIC && symbolic_operand (operands[1], DImode))
+-    {
+-      /* Before optimization starts, delay committing to any particular
+-       type of PIC address load.  If this function gets deferred, we
+-       may acquire information that changes the value of the
+-       sdata_symbolic_operand predicate.  */
+-      /* But don't delay for function pointers.  Loading a function address
+-       actually loads the address of the descriptor not the function.
+-       If we represent these as SYMBOL_REFs, then they get cse'd with
+-       calls, and we end up with calls to the descriptor address instead of
+-       calls to the function address.  Functions are not candidates for
+-       sdata anyways.  */
+-      if (rtx_equal_function_value_matters
+-        && ! (GET_CODE (operands[1]) == SYMBOL_REF
+-              && SYMBOL_REF_FLAG (operands[1])))
+-      emit_insn (gen_movdi_symbolic (operands[0], operands[1], gen_reg_rtx (DImode)));
+-      else
+-        ia64_expand_load_address (operands[0], operands[1], NULL_RTX);
+-      DONE;
+-    }
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ ;; This is used during early compilation to delay the decision on
+ ;; how to refer to a variable as long as possible.  This is especially
+@@ -384,19 +376,22 @@
+ ;; deferred functions, since we may acquire additional information
+ ;; on the variables used in the meantime.
+-;; ??? This causes us to lose REG_LABEL notes, because the insn splitter
+-;; does not attempt to preserve any REG_NOTES on the input instruction.
+-
+ (define_insn_and_split "movdi_symbolic"
+   [(set (match_operand:DI 0 "register_operand" "=r")
+       (match_operand:DI 1 "symbolic_operand" "s"))
+-   (clobber (match_operand:DI  2 "register_operand" "+r"))
++   (clobber (match_scratch:DI 2 "=r"))
+    (use (reg:DI 1))]
+   ""
+   "* abort ();"
+-  ""
++  "!no_new_pseudos || reload_completed"
+   [(const_int 0)]
+-  "ia64_expand_load_address (operands[0], operands[1], operands[2]); DONE;")
++{
++  rtx scratch = operands[2];
++  if (!reload_completed)
++    gen_reg_rtx (Pmode);
++  ia64_expand_load_address (operands[0], operands[1], scratch); 
++  DONE;
++})
+ (define_insn "*movdi_internal"
+   [(set (match_operand:DI 0 "destination_operand"
+@@ -510,6 +505,131 @@
+   "addl %0 = @ltoff(%1), gp"
+   [(set_attr "itanium_class" "ialu")])
++(define_insn "load_ltoff_dtpmod"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (reg:DI 1)
++               (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                          UNSPEC_LTOFF_DTPMOD)))]
++  ""
++  "addl %0 = @ltoff(@dtpmod(%1)), gp"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_insn "load_ltoff_dtprel"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (reg:DI 1)
++               (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                          UNSPEC_LTOFF_DTPREL)))]
++  ""
++  "addl %0 = @ltoff(@dtprel(%1)), gp"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_expand "load_dtprel"
++  [(set (match_operand:DI 0 "register_operand" "")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_DTPREL))]
++  ""
++  "")
++
++(define_insn "*load_dtprel64"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_DTPREL))]
++  "TARGET_TLS64"
++  "movl %0 = @dtprel(%1)"
++  [(set_attr "itanium_class" "long_i")])
++
++(define_insn "*load_dtprel22"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_DTPREL))]
++  ""
++  "addl %0 = @dtprel(%1), r0"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_expand "add_dtprel"
++  [(set (match_operand:DI 0 "register_operand" "")
++      (plus:DI (match_operand:DI 1 "register_operand" "")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_DTPREL)))]
++  "!TARGET_TLS64"
++  "")
++
++(define_insn "*add_dtprel14"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (match_operand:DI 1 "register_operand" "r")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_DTPREL)))]
++  "TARGET_TLS14"
++  "adds %0 = @dtprel(%2), %1"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_insn "*add_dtprel22"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (match_operand:DI 1 "register_operand" "a")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_DTPREL)))]
++  "TARGET_TLS22"
++  "addl %0 = @dtprel(%2), %1"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_insn "load_ltoff_tprel"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (reg:DI 1)
++               (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                          UNSPEC_LTOFF_TPREL)))]
++  ""
++  "addl %0 = @ltoff(@tprel(%1)), gp"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_expand "load_tprel"
++  [(set (match_operand:DI 0 "register_operand" "")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_TPREL))]
++  ""
++  "")
++
++(define_insn "*load_tprel64"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_TPREL))]
++  "TARGET_TLS64"
++  "movl %0 = @tprel(%1)"
++  [(set_attr "itanium_class" "long_i")])
++
++(define_insn "*load_tprel22"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
++                 UNSPEC_TPREL))]
++  ""
++  "addl %0 = @tprel(%1), r0"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_expand "add_tprel"
++  [(set (match_operand:DI 0 "register_operand" "")
++      (plus:DI (match_operand:DI 1 "register_operand" "")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_TPREL)))]
++  "!TARGET_TLS64"
++  "")
++
++(define_insn "*add_tprel14"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (match_operand:DI 1 "register_operand" "r")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_TPREL)))]
++  "TARGET_TLS14"
++  "adds %0 = @tprel(%2), %1"
++  [(set_attr "itanium_class" "ialu")])
++
++(define_insn "*add_tprel22"
++  [(set (match_operand:DI 0 "register_operand" "=r")
++      (plus:DI (match_operand:DI 1 "register_operand" "a")
++               (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
++                          UNSPEC_TPREL)))]
++  "TARGET_TLS22"
++  "addl %0 = @tprel(%2), %1"
++  [(set_attr "itanium_class" "ialu")])
++
+ ;; With no offsettable memory references, we've got to have a scratch
+ ;; around to play with the second word.
+ (define_expand "movti"
+@@ -517,12 +637,12 @@
+                  (match_operand:TI 1 "general_operand" ""))
+             (clobber (match_scratch:DI 2 ""))])]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (TImode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn_and_split "*movti_internal"
+   [(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
+@@ -639,12 +759,12 @@
+   [(set (match_operand:SF 0 "general_operand" "")
+       (match_operand:SF 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (SFmode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn "*movsf_internal"
+   [(set (match_operand:SF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
+@@ -665,12 +785,12 @@
+   [(set (match_operand:DF 0 "general_operand" "")
+       (match_operand:DF 1 "general_operand" ""))]
+   ""
+-  "
+ {
+-  if (! reload_in_progress && ! reload_completed
+-      && ! ia64_move_ok (operands[0], operands[1]))
+-    operands[1] = force_reg (DFmode, operands[1]);
+-}")
++  rtx op1 = ia64_expand_move (operands[0], operands[1]);
++  if (!op1)
++    DONE;
++  operands[1] = op1;
++})
+ (define_insn "*movdf_internal"
+   [(set (match_operand:DF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
+--- gcc/config/ia64/sysv4.h.jj Mon Jun  3 17:24:18 2002
++++ gcc/config/ia64/sysv4.h    Wed Jun 19 19:33:52 2002
+@@ -42,8 +42,7 @@ extern int size_directive_output;
+ #undef ASM_OUTPUT_ALIGNED_LOCAL
+ #define ASM_OUTPUT_ALIGNED_DECL_LOCAL(FILE, DECL, NAME, SIZE, ALIGN) \
+ do {                                                                  \
+-  if ((DECL)                                                          \
+-      && XSTR (XEXP (DECL_RTL (DECL), 0), 0)[0] == SDATA_NAME_FLAG_CHAR) \
++  if ((DECL) && sdata_symbolic_operand (XEXP (DECL_RTL (DECL), 0), Pmode)) \
+     sbss_section ();                                                  \
+   else                                                                        \
+     bss_section ();                                                   \
+@@ -62,8 +61,8 @@ do {                                                                 \
+ #define ASM_OUTPUT_LABELREF(STREAM, NAME)     \
+ do {                                          \
+   const char *name_ = NAME;                   \
+-  if (*name_ == SDATA_NAME_FLAG_CHAR)         \
+-    name_++;                                  \
++  if (*name_ == ENCODE_SECTION_INFO_CHAR)     \
++    name_ += 2;                                       \
+   if (*name_ == '*')                          \
+     name_++;                                  \
+   else                                                \
+@@ -149,9 +148,11 @@ do {                                                                      \
+       0       .text
+       1       .rodata
+       2       .data
+-      3       .sdata
+-      4       .bss
++      3       .bss
++      4       .sdata
+       5       .sbss
++      6       .tdata
++      7       .tbss
+ */
+ #define DO_SELECT_SECTION(SECNUM, DECL, RELOC)                                \
+   do                                                                  \
+@@ -167,9 +168,10 @@ do {                                                                      \
+       }                                                               \
+       else if (TREE_CODE (DECL) == VAR_DECL)                          \
+       {                                                               \
+-        if (XSTR (XEXP (DECL_RTL (DECL), 0), 0)[0]                    \
+-            == SDATA_NAME_FLAG_CHAR)                                  \
+-          SECNUM = 3;                                                 \
++        if (DECL_THREAD_LOCAL (DECL))                                 \
++          SECNUM = 6;                                                 \
++        else if (sdata_symbolic_operand (XEXP (DECL_RTL (DECL), 0), Pmode))\
++          SECNUM = 4;                                                 \
+         /* ??? We need the extra RELOC check, because the default     \
+            is to only check RELOC if flag_pic is set, and we don't    \
+            set flag_pic (yet?).  */                                   \
+@@ -184,13 +186,18 @@ do {                                                                     \
+           SECNUM = 0x201;                                             \
+         else                                                          \
+           SECNUM = 0x301;                                             \
++                                                                      \
++        if (SECNUM >= 2                                               \
++            && (!DECL_INITIAL (DECL)                                  \
++                || DECL_INITIAL (DECL) == error_mark_node))           \
++          SECNUM++;                                                   \
+       }                                                               \
+       /* This could be a CONSTRUCTOR containing ADDR_EXPR of a VAR_DECL, \
+        in which case we can't put it in a shared library rodata.  */  \
+       else if (flag_pic && (RELOC))                                   \
+-      SECNUM = 3;                                                     \
+-      else                                                            \
+       SECNUM = 2;                                                     \
++      else                                                            \
++      SECNUM = 1;                                                     \
+     }                                                                 \
+   while (0)
+@@ -206,8 +213,8 @@ do {                                                                       \
+       text_section,                                                   \
+       const_section,                                                  \
+       data_section,                                                   \
+-      sdata_section,                                                  \
+       bss_section,                                                    \
++      sdata_section,                                                  \
+       sbss_section                                                    \
+       };                                                              \
+                                                                       \
+@@ -217,6 +224,12 @@ do {                                                                      \
+                                                                       \
+       switch (sec)                                                    \
+       {                                                               \
++      case 6:                                                         \
++        named_section (NULL_TREE, ".tdata", RELOC);                   \
++        break;                                                        \
++      case 7:                                                         \
++        named_section (NULL_TREE, ".tbss", RELOC);                    \
++        break;                                                        \
+       case 0x101:                                                     \
+         mergeable_string_section (DECL, ALIGN, 0);                    \
+         break;                                                        \
+@@ -244,9 +257,11 @@ do {                                                                      \
+       { ".text.",   ".gnu.linkonce.t." },                             \
+       { ".rodata.", ".gnu.linkonce.r." },                             \
+       { ".data.",   ".gnu.linkonce.d." },                             \
+-      { ".sdata.",  ".gnu.linkonce.s." },                             \
+       { ".bss.",    ".gnu.linkonce.b." },                             \
+-      { ".sbss.",   ".gnu.linkonce.sb." }                             \
++      { ".sdata.",  ".gnu.linkonce.s." },                             \
++      { ".sbss.",   ".gnu.linkonce.sb." },                            \
++      { ".tdata.",  ".gnu.linkonce.td." },                            \
++      { ".tbss.",   ".gnu.linkonce.tb." }                             \
+       };                                                              \
+                                                                       \
+       int nlen, plen, sec;                                            \
+--- gcc/config/elfos.h.jj      Tue Dec 18 01:30:48 2001
++++ gcc/config/elfos.h Wed Jun 19 19:33:52 2002
+@@ -288,24 +288,28 @@ const_section ()                                         \
+       const char *name;                                               \
+       char *string;                                           \
+       const char *prefix;                                     \
+-      static const char *const prefixes[4][2] =                       \
++      static const char *const prefixes[][2] =                        \
+       {                                                               \
+       { ".text.",   ".gnu.linkonce.t." },                     \
+       { ".rodata.", ".gnu.linkonce.r." },                     \
+       { ".data.",   ".gnu.linkonce.d." },                     \
+-      { ".bss.",    ".gnu.linkonce.b." }                      \
++      { ".bss.",    ".gnu.linkonce.b." },                     \
++      { ".tdata",   ".gnu.linkonce.td." },                    \
++      { ".tbss",    ".gnu.linkonce.tb." },                    \
+       };                                                      \
+                                                                       \
+       if (TREE_CODE (DECL) == FUNCTION_DECL)                  \
+       sec = 0;                                                \
+       else if (DECL_INITIAL (DECL) == 0                               \
+              || DECL_INITIAL (DECL) == error_mark_node)       \
+-        sec =  3;                                             \
++        sec = 3;                                              \
+       else if (DECL_READONLY_SECTION (DECL, RELOC))           \
+       sec = 1;                                                \
+       else                                                    \
+       sec = 2;                                                \
+-                                                                      \
++      if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl)) \
++      sec = (sec == 3 ? 5 : 4);                               \
++                                                              \
+       name   = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL));       \
+       /* Strip off any encoding in name.  */                  \
+       STRIP_NAME_ENCODING (name, name);                               \
+@@ -367,10 +371,18 @@ const_section ()                                         \
+     }                                                         \
+   else if (TREE_CODE (DECL) == VAR_DECL)                      \
+     {                                                         \
+-      if (!TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL)   \
+-        || !DECL_INITIAL (DECL)                               \
+-        || (DECL_INITIAL (DECL) != error_mark_node            \
+-            && !TREE_CONSTANT (DECL_INITIAL (DECL))))         \
++      if (DECL_THREAD_LOCAL (DECL))                           \
++      {                                                       \
++        if (!DECL_INITIAL (DECL)                              \
++            || DECL_INITIAL (DECL) == error_mark_node)        \
++          named_section (NULL_TREE, ".tbss", RELOC);          \
++        else                                                  \
++          named_section (NULL_TREE, ".tdata", RELOC);         \
++      }                                                       \
++      else if (!TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
++             || !DECL_INITIAL (DECL)                          \
++             || (DECL_INITIAL (DECL) != error_mark_node       \
++                 && !TREE_CONSTANT (DECL_INITIAL (DECL))))    \
+       {                                                       \
+         if (flag_pic && ((RELOC) & 2))                        \
+           named_section (NULL_TREE, ".data.rel", RELOC);      \
+--- gcc/fixinc/fixincl.x.jj    Thu May  2 12:15:15 2002
++++ gcc/fixinc/fixincl.x       Wed Jun 19 19:33:52 2002
+@@ -5,7 +5,7 @@
+  * files which are fixed to work correctly with ANSI C and placed in a
+  * directory that GNU C will search.
+  *
+- * This file contains 142 fixup descriptions.
++ * This file contains 143 fixup descriptions.
+  *
+  * See README for more information.
+  *
+@@ -4568,6 +4568,41 @@ static const char* apzSysz_Stdlib_For_Su
+ /* * * * * * * * * * * * * * * * * * * * * * * * * *
+  *
++ *  Description of Thread_Keyword fix
++ */
++tSCC zThread_KeywordName[] =
++     "thread_keyword";
++
++/*
++ *  File name selection pattern
++ */
++tSCC zThread_KeywordList[] =
++  "|pthread.h|bits/sigthread.h|";
++/*
++ *  Machine/OS name selection pattern
++ */
++#define apzThread_KeywordMachs (const char**)NULL
++
++/*
++ *  content selection pattern - do fix if pattern found
++ */
++tSCC zThread_KeywordSelect0[] =
++       " __thread([,)])";
++
++#define    THREAD_KEYWORD_TEST_CT  1
++static tTestDesc aThread_KeywordTests[] = {
++  { TT_EGREP,    zThread_KeywordSelect0, (regex_t*)NULL }, };
++
++/*
++ *  Fix Command Arguments for Thread_Keyword
++ */
++static const char* apzThread_KeywordPatch[] = {
++    "format",
++    " __thr%1",
++    (char*)NULL };
++
++/* * * * * * * * * * * * * * * * * * * * * * * * * *
++ *
+  *  Description of Tinfo_Cplusplus fix
+  */
+ tSCC zTinfo_CplusplusName[] =
+@@ -5581,9 +5616,9 @@ static const char* apzX11_SprintfPatch[]
+  *
+  *  List of all fixes
+  */
+-#define REGEX_COUNT          151
++#define REGEX_COUNT          152
+ #define MACH_LIST_SIZE_LIMIT 279
+-#define FIX_COUNT            142
++#define FIX_COUNT            143
+ /*
+  *  Enumerate the fixes
+@@ -5705,6 +5740,7 @@ typedef enum {
+     SVR4_PROFIL_FIXIDX,
+     SYSV68_STRING_FIXIDX,
+     SYSZ_STDLIB_FOR_SUN_FIXIDX,
++    THREAD_KEYWORD_FIXIDX,
+     TINFO_CPLUSPLUS_FIXIDX,
+     ULTRIX_ATEXIT_PARAM_FIXIDX,
+     ULTRIX_ATOF_PARAM_FIXIDX,
+@@ -6314,6 +6350,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
+      SYSZ_STDLIB_FOR_SUN_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+      aSysz_Stdlib_For_SunTests,   apzSysz_Stdlib_For_SunPatch, 0 },
++  {  zThread_KeywordName,    zThread_KeywordList,
++     apzThread_KeywordMachs,
++     THREAD_KEYWORD_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
++     aThread_KeywordTests,   apzThread_KeywordPatch, 0 },
++
+   {  zTinfo_CplusplusName,    zTinfo_CplusplusList,
+      apzTinfo_CplusplusMachs,
+      TINFO_CPLUSPLUS_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+--- gcc/fixinc/inclhack.def.jj Thu May  2 12:15:17 2002
++++ gcc/fixinc/inclhack.def    Wed Jun 19 19:33:52 2002
+@@ -1,4 +1,3 @@
+-
+ /* -*- Mode: C -*-  */
+ autogen definitions fixincl;
+@@ -2886,6 +2885,24 @@ fix = {
+ };
++/*
++ * __thread is now a keyword.
++ */
++fix = {
++    hackname  = thread_keyword;
++    files     = "pthread.h";
++    files     = "bits/sigthread.h";
++    select    = " __thread([,)])";
++    c_fix     = format;
++    c_fix_arg = " __thr%1";
++
++    test_text =
++        "extern int pthread_create (pthread_t *__restrict __thread,\n"
++        "extern int pthread_kill (pthread_t __thread, int __signo);\n"
++        "extern int pthread_cancel (pthread_t __thread);";
++};
++
++
+ /*
+  *  if the #if says _cplusplus, not the double underscore __cplusplus
+  *  that it should be
+--- gcc/testsuite/g++.dg/dg.exp.jj     Thu Feb 14 13:26:12 2002
++++ gcc/testsuite/g++.dg/dg.exp        Wed Jun 19 19:33:52 2002
+@@ -28,10 +28,12 @@ if ![info exists DEFAULT_CXXFLAGS] then 
+ # Initialize `dg'.
+ dg-init
+-# Gather a list of all tests, excluding those in special/; those are handled
+-# well, specially.
+-set all [lsort [find $srcdir/$subdir *.C]]
+-set tests [prune [prune $all $srcdir/$subdir/special/*] $srcdir/$subdir/debug/*]
++# Gather a list of all tests, with the exception of those in directories
++# that are handled specially.
++set tests [lsort [find $srcdir/$subdir *.C]]
++set tests [prune $tests $srcdir/$subdir/debug/*]
++set tests [prune $tests $srcdir/$subdir/special/*]
++set tests [prune $tests $srcdir/$subdir/tls/*]
+ # Main loop.
+ dg-runtest $tests "" $DEFAULT_CXXFLAGS
+--- gcc/testsuite/g++.dg/tls/diag-1.C.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/diag-1.C  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,30 @@
++/* Valid __thread specifiers.  */
++
++__thread int g1;
++extern __thread int g2;
++static __thread int g3;
++
++void foo()
++{
++  extern __thread int l1;
++  static __thread int l2;
++}
++
++struct A {
++  static __thread int i;
++};
++
++__thread int A::i = 42;
++
++template <typename T> struct B {
++  static __thread T t;
++};
++
++template <typename T>
++__thread T B<T>::t = 42;
++
++void bar ()
++{
++  int j = B<int>::t;
++  int k = B<const int>::t;
++}
+--- gcc/testsuite/g++.dg/tls/diag-2.C.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/diag-2.C  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,25 @@
++/* Invalid __thread specifiers.  */
++
++__thread extern int g1;               /* { dg-error "`__thread' before `extern'" } */
++__thread static int g2;               /* { dg-error "`__thread' before `static'" } */
++__thread __thread int g3;     /* { dg-error "duplicate `__thread'" } */
++typedef __thread int g4;      /* { dg-error "multiple storage classes" } */
++
++void foo()
++{
++  __thread int l1;            /* { dg-error "implicitly auto and declared `__thread'" } */
++  auto __thread int l2;               /* { dg-error "multiple storage classes" } */
++  __thread extern int l3;     /* { dg-error "`__thread' before `extern'" } */
++  register __thread int l4;   /* { dg-error "multiple storage classes" } */
++}
++
++__thread void f1 ();          /* { dg-error "invalid for function" } */
++extern __thread void f2 ();   /* { dg-error "invalid for function" } */
++static __thread void f3 ();   /* { dg-error "invalid for function" } */
++__thread void f4 () { }               /* { dg-error "invalid for function" } */
++
++void bar(__thread int p1);    /* { dg-error "(invalid in parameter)|(specified for parameter)" } */
++
++struct A {
++  __thread int i;             /* { dg-error "specified for field" } */
++};
+--- gcc/testsuite/g++.dg/tls/init-1.C.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/init-1.C  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,13 @@
++/* Valid initializations.  */
++
++__thread int i = 42;
++
++static int j;
++__thread int *p = &j;
++
++/* Note that this is valid in C++ (unlike C) as a run-time initialization.  */
++int *q = &i;
++
++/* Valid because "const int k" is an integral constant expression in C++.  */
++__thread const int k = 42;
++__thread const int l = k;
+--- gcc/testsuite/g++.dg/tls/init-2.C.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/init-2.C  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,13 @@
++/* Invalid initializations.  */
++
++extern __thread int i;
++__thread int *p = &i; /* { dg-error "run-time initialization" } */
++
++extern int f();
++__thread int j = f(); /* { dg-error "run-time initialization" } */
++
++struct S
++{
++  S();
++};
++__thread S s;         /* { dg-error "run-time initialization" } */
+--- gcc/testsuite/g++.dg/tls/tls.exp.jj        Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/tls.exp   Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,44 @@
++#   Copyright (C) 2002 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++# 
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++# 
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
++
++# GCC testsuite that uses the `dg.exp' driver.
++
++# Load support procs.
++load_lib g++-dg.exp
++
++# Test for thread-local data supported by the platform.  If it
++# isn't, everything will fail with the "not supported" message.
++
++set comp_output [g++_target_compile \
++              "$srcdir/$subdir/trivial.C" "trivial.S" assembly ""]
++if { [string match "*not supported*" $comp_output] } {
++  return 0
++}
++
++# If a testcase doesn't have special options, use these.
++global DEFAULT_CXXFLAGS
++if ![info exists DEFAULT_CXXFLAGS] then {
++    set DEFAULT_CXXFLAGS " -ansi -pedantic-errors -Wno-long-long"
++}
++
++# Initialize `dg'.
++dg-init
++
++# Main loop.
++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
++
++# All done.
++dg-finish
+--- gcc/testsuite/g++.dg/tls/trivial.C.jj      Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/g++.dg/tls/trivial.C Wed Jun 19 19:33:52 2002
+@@ -0,0 +1 @@
++__thread int i;
+--- gcc/testsuite/gcc.dg/tls/diag-1.c.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/diag-1.c  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,11 @@
++/* Valid __thread specifiers.  */
++
++__thread int g1;
++extern __thread int g2;
++static __thread int g3;
++
++void foo()
++{
++  extern __thread int l1;
++  static __thread int l2;
++}
+--- gcc/testsuite/gcc.dg/tls/diag-2.c.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/diag-2.c  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,21 @@
++/* Invalid __thread specifiers.  */
++
++__thread extern int g1;               /* { dg-error "`__thread' before `extern'" } */
++__thread static int g2;               /* { dg-error "`__thread' before `static'" } */
++__thread __thread int g3;     /* { dg-error "duplicate `__thread'" } */
++typedef __thread int g4;      /* { dg-error "multiple storage classes" } */
++
++void foo()
++{
++  __thread int l1;            /* { dg-error "implicitly auto and declared `__thread'" } */
++  auto __thread int l2;               /* { dg-error "multiple storage classes" } */
++  __thread extern int l3;     /* { dg-error "`__thread' before `extern'" } */
++  register __thread int l4;   /* { dg-error "multiple storage classes" } */
++}
++
++__thread void f1 ();          /* { dg-error "invalid storage class for function" } */
++extern __thread void f2 ();   /* { dg-error "invalid storage class for function" } */
++static __thread void f3 ();   /* { dg-error "invalid storage class for function" } */
++__thread void f4 () { }               /* { dg-error "function definition declared `__thread'" } */
++
++void bar(__thread int p1);    /* { dg-error "storage class specified for parameter" } */
+--- gcc/testsuite/gcc.dg/tls/init-1.c.jj       Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/init-1.c  Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,4 @@
++/* Invalid initializations.  */
++
++extern __thread int i;
++int *p = &i;  /* { dg-error "initializer element is not constant" } */
+--- gcc/testsuite/gcc.dg/tls/tls.exp.jj        Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/tls.exp   Wed Jun 19 19:33:52 2002
+@@ -0,0 +1,45 @@
++#   Copyright (C) 2002 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2 of the License, or
++# (at your option) any later version.
++# 
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU General Public License for more details.
++# 
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
++
++# GCC testsuite that uses the `dg.exp' driver.
++
++# Load support procs.
++load_lib gcc-dg.exp
++
++# Test for thread-local data supported by the platform.  If it
++# isn't, everything will fail with the "not supported" message.
++
++set comp_output [gcc_target_compile \
++              "$srcdir/$subdir/trivial.c" "trivial.S" assembly ""]
++if { [string match "*not supported*" $comp_output] } {
++  return 0
++}
++
++# If a testcase doesn't have special options, use these.
++global DEFAULT_CFLAGS
++if ![info exists DEFAULT_CFLAGS] then {
++    set DEFAULT_CFLAGS " -ansi -pedantic-errors"
++}
++
++# Initialize `dg'.
++dg-init
++
++# Main loop.
++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \
++        "" $DEFAULT_CFLAGS
++
++# All done.
++dg-finish
+--- gcc/testsuite/gcc.dg/tls/trivial.c.jj      Wed Jun 19 19:33:52 2002
++++ gcc/testsuite/gcc.dg/tls/trivial.c Wed Jun 19 19:33:52 2002
+@@ -0,0 +1 @@
++__thread int i;
+--- gcc/c-common.h.jj  Wed Apr 17 15:34:36 2002
++++ gcc/c-common.h     Wed Jun 19 19:33:52 2002
+@@ -58,7 +58,7 @@ enum rid
+   RID_VOLATILE, RID_SIGNED,  RID_AUTO,  RID_RESTRICT,
+   /* C extensions */
+-  RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX,
++  RID_BOUNDED, RID_UNBOUNDED, RID_COMPLEX, RID_THREAD,
+   /* C++ */
+   RID_FRIEND, RID_VIRTUAL, RID_EXPLICIT, RID_EXPORT, RID_MUTABLE,
+--- gcc/c-decl.c.jj    Wed Jun 19 19:33:50 2002
++++ gcc/c-decl.c       Wed Jun 19 19:33:52 2002
+@@ -3571,9 +3571,19 @@ start_decl (declarator, declspecs, initi
+   /* ANSI specifies that a tentative definition which is not merged with
+      a non-tentative definition behaves exactly like a definition with an
+      initializer equal to zero.  (Section 3.7.2)
+-     -fno-common gives strict ANSI behavior.  Usually you don't want it.
+-     This matters only for variables with external linkage.  */
+-  if (! flag_no_common || ! TREE_PUBLIC (decl))
++
++     -fno-common gives strict ANSI behavior, though this tends to break
++     a large body of code that grew up without this rule.
++
++     Thread-local variables are never common, since there's no entrenched
++     body of code to break, and it allows more efficient variable references
++     in the presense of dynamic linking.  */
++
++  if (TREE_CODE (decl) == VAR_DECL
++      && !initialized
++      && TREE_PUBLIC (decl)
++      && !DECL_THREAD_LOCAL (decl)
++      && !flag_no_common)
+     DECL_COMMON (decl) = 1;
+   /* Set attributes here so if duplicate decl, will have proper attributes.  */
+@@ -4172,7 +4182,7 @@ grokdeclarator (declarator, declspecs, d
+         enum rid i = C_RID_CODE (id);
+         if ((int) i <= (int) RID_LAST_MODIFIER)
+           {
+-            if (i == RID_LONG && (specbits & (1 << (int) i)))
++            if (i == RID_LONG && (specbits & (1 << (int) RID_LONG)))
+               {
+                 if (longlong)
+                   error ("`long long long' is too long for GCC");
+@@ -4186,6 +4196,19 @@ grokdeclarator (declarator, declspecs, d
+               }
+             else if (specbits & (1 << (int) i))
+               pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
++
++            /* Diagnose "__thread extern".  Recall that this list
++               is in the reverse order seen in the text.  */
++            if (i == RID_THREAD
++                && (specbits & (1 << (int) RID_EXTERN
++                                | 1 << (int) RID_STATIC)))
++              {
++                if (specbits & 1 << (int) RID_EXTERN)
++                  error ("`__thread' before `extern'");
++                else
++                  error ("`__thread' before `static'");
++              }
++
+             specbits |= 1 << (int) i;
+             goto found;
+           }
+@@ -4438,6 +4461,12 @@ grokdeclarator (declarator, declspecs, d
+     if (specbits & 1 << (int) RID_REGISTER) nclasses++;
+     if (specbits & 1 << (int) RID_TYPEDEF) nclasses++;
++    /* "static __thread" and "extern __thread" are allowed.  */
++    if ((specbits & (1 << (int) RID_THREAD
++                   | 1 << (int) RID_STATIC
++                   | 1 << (int) RID_EXTERN)) == (1 << (int) RID_THREAD))
++      nclasses++;
++
+     /* Warn about storage classes that are invalid for certain
+        kinds of declarations (parameters, typenames, etc.).  */
+@@ -4447,7 +4476,8 @@ grokdeclarator (declarator, declspecs, d
+            && (specbits
+                & ((1 << (int) RID_REGISTER)
+                   | (1 << (int) RID_AUTO)
+-                  | (1 << (int) RID_TYPEDEF))))
++                  | (1 << (int) RID_TYPEDEF)
++                  | (1 << (int) RID_THREAD))))
+       {
+       if (specbits & 1 << (int) RID_AUTO
+           && (pedantic || current_binding_level == global_binding_level))
+@@ -4456,8 +4486,10 @@ grokdeclarator (declarator, declspecs, d
+         error ("function definition declared `register'");
+       if (specbits & 1 << (int) RID_TYPEDEF)
+         error ("function definition declared `typedef'");
++      if (specbits & 1 << (int) RID_THREAD)
++        error ("function definition declared `__thread'");
+       specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+-                    | (1 << (int) RID_AUTO));
++                    | (1 << (int) RID_AUTO) | (1 << (int) RID_THREAD));
+       }
+     else if (decl_context != NORMAL && nclasses > 0)
+       {
+@@ -4480,7 +4512,7 @@ grokdeclarator (declarator, declspecs, d
+             }
+           specbits &= ~((1 << (int) RID_TYPEDEF) | (1 << (int) RID_REGISTER)
+                         | (1 << (int) RID_AUTO) | (1 << (int) RID_STATIC)
+-                        | (1 << (int) RID_EXTERN));
++                        | (1 << (int) RID_EXTERN) | (1 << (int) RID_THREAD));
+         }
+       }
+     else if (specbits & 1 << (int) RID_EXTERN && initialized && ! funcdef_flag)
+@@ -4491,12 +4523,25 @@ grokdeclarator (declarator, declspecs, d
+       else
+         error ("`%s' has both `extern' and initializer", name);
+       }
+-    else if (specbits & 1 << (int) RID_EXTERN && funcdef_flag
+-           && current_binding_level != global_binding_level)
+-      error ("nested function `%s' declared `extern'", name);
+-    else if (current_binding_level == global_binding_level
+-           && specbits & (1 << (int) RID_AUTO))
+-      error ("top-level declaration of `%s' specifies `auto'", name);
++    else if (current_binding_level == global_binding_level)
++      {
++      if (specbits & 1 << (int) RID_AUTO)
++        error ("top-level declaration of `%s' specifies `auto'", name);
++      }
++    else
++      {
++      if (specbits & 1 << (int) RID_EXTERN && funcdef_flag)
++        error ("nested function `%s' declared `extern'", name);
++      else if ((specbits & (1 << (int) RID_THREAD
++                             | 1 << (int) RID_EXTERN
++                             | 1 << (int) RID_STATIC))
++               == (1 << (int) RID_THREAD))
++        {
++          error ("function-scope `%s' implicitly auto and declared `__thread'",
++                 name);
++          specbits &= ~(1 << (int) RID_THREAD);
++        }
++      }
+   }
+   /* Now figure out the structure of the declarator proper.
+@@ -5095,6 +5140,8 @@ grokdeclarator (declarator, declspecs, d
+         pedwarn ("invalid storage class for function `%s'", name);
+       if (specbits & (1 << (int) RID_REGISTER))
+         error ("invalid storage class for function `%s'", name);
++      if (specbits & (1 << (int) RID_THREAD))
++        error ("invalid storage class for function `%s'", name);
+       /* Function declaration not at top level.
+          Storage classes other than `extern' are not allowed
+          and `extern' makes no difference.  */
+@@ -5187,22 +5234,32 @@ grokdeclarator (declarator, declspecs, d
+         pedwarn_with_decl (decl, "variable `%s' declared `inline'");
+       DECL_EXTERNAL (decl) = extern_ref;
++
+       /* At top level, the presence of a `static' or `register' storage
+          class specifier, or the absence of all storage class specifiers
+          makes this declaration a definition (perhaps tentative).  Also,
+          the absence of both `static' and `register' makes it public.  */
+       if (current_binding_level == global_binding_level)
+         {
+-          TREE_PUBLIC (decl)
+-            = !(specbits
+-                & ((1 << (int) RID_STATIC) | (1 << (int) RID_REGISTER)));
+-          TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
++          TREE_PUBLIC (decl) = !(specbits & ((1 << (int) RID_STATIC)
++                                             | (1 << (int) RID_REGISTER)));
++          TREE_STATIC (decl) = !extern_ref;
+         }
+       /* Not at top level, only `static' makes a static definition.  */
+       else
+         {
+           TREE_STATIC (decl) = (specbits & (1 << (int) RID_STATIC)) != 0;
+-          TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
++          TREE_PUBLIC (decl) = extern_ref;
++        }
++
++      if (specbits & 1 << (int) RID_THREAD)
++        {
++          if (targetm.have_tls)
++            DECL_THREAD_LOCAL (decl) = 1;
++          else
++            /* A mere warning is sure to result in improper semantics
++               at runtime.  Don't bother to allow this to compile.  */
++            error ("thread-local storage not supported for this target");
+         }
+       }
+--- gcc/c-parse.in.jj  Wed Apr 17 15:34:46 2002
++++ gcc/c-parse.in     Wed Jun 19 19:33:52 2002
+@@ -3329,6 +3329,7 @@ static const struct resword reswords[] =
+   { "__restrict__",   RID_RESTRICT,   0 },
+   { "__signed",               RID_SIGNED,     0 },
+   { "__signed__",     RID_SIGNED,     0 },
++  { "__thread",               RID_THREAD,     0 },
+   { "__typeof",               RID_TYPEOF,     0 },
+   { "__typeof__",     RID_TYPEOF,     0 },
+   { "__unbounded",    RID_UNBOUNDED,  0 },
+@@ -3424,6 +3425,7 @@ static const short rid_to_yy[RID_MAX] =
+   /* RID_BOUNDED */   TYPE_QUAL,
+   /* RID_UNBOUNDED */ TYPE_QUAL,
+   /* RID_COMPLEX */   TYPESPEC,
++  /* RID_THREAD */    SCSPEC,
+   /* C++ */
+   /* RID_FRIEND */    0,
+--- gcc/config.in.jj   Sat Jun  8 00:38:25 2002
++++ gcc/config.in      Wed Jun 19 19:33:52 2002
+@@ -523,6 +523,9 @@
+ /* Define if your assembler supports marking sections with SHF_MERGE flag. */
+ #undef HAVE_GAS_SHF_MERGE
++/* Define if your assembler supports thread-local storage. */
++#undef HAVE_AS_TLS
++
+ /* Define if your assembler supports explicit relocations. */
+ #undef HAVE_AS_EXPLICIT_RELOCS
+--- gcc/flags.h.jj     Sat Mar 23 12:02:51 2002
++++ gcc/flags.h        Wed Jun 19 19:33:52 2002
+@@ -450,11 +450,22 @@ extern int flag_pretend_float;
+ extern int flag_pedantic_errors;
+-/* Nonzero means generate position-independent code.
+-   This is not fully implemented yet.  */
++/* Nonzero means generate position-independent code.  1 vs 2 for a 
++   target-dependent "small" or "large" mode.  */
+ extern int flag_pic;
++/* Set to the default thread-local storage (tls) model to use.  */
++
++enum tls_model {
++  TLS_MODEL_GLOBAL_DYNAMIC = 1,
++  TLS_MODEL_LOCAL_DYNAMIC,
++  TLS_MODEL_INITIAL_EXEC,
++  TLS_MODEL_LOCAL_EXEC
++};
++
++extern enum tls_model flag_tls_default;
++
+ /* Nonzero means generate extra code for exception handling and enable
+    exception handling.  */
+--- gcc/configure.in.jj        Sat Jun  8 00:38:27 2002
++++ gcc/configure.in   Wed Jun 19 19:33:52 2002
+@@ -1715,6 +1715,72 @@ if test x"$gcc_cv_as_shf_merge" = xyes; 
+ fi
+ AC_MSG_RESULT($gcc_cv_as_shf_merge)
++AC_MSG_CHECKING(assembler thread-local storage support)
++gcc_cv_as_tls=no
++conftest_s=
++tls_first_major=
++tls_first_minor=
++case "$target" in
++changequote(,)dnl
++  i[34567]86-*-*)
++changequote([,])dnl
++    conftest_s='
++      .section ".tdata","awT",@progbits
++foo:  .long   25
++      .text
++      movl    %gs:0, %eax
++      leal    foo@TLSGD(,%ebx,1), %eax
++      leal    foo@TLSLDM(%ebx), %eax
++      leal    foo@DTPOFF(%eax), %edx
++      movl    foo@GOTTPOFF(%ebx), %eax
++      subl    foo@GOTTPOFF(%ebx), %eax
++      movl    $foo@TPOFF, %eax
++      subl    $foo@TPOFF, %eax
++      leal    foo@NTPOFF(%ecx), %eax'
++      tls_first_major=2
++      tls_first_minor=13
++      ;;
++  ia64-*-*)
++    conftest_s='
++      .section ".tdata","awT",@progbits
++foo:  data8   25
++      .text
++      addl    r16 = @ltoff(@dtpmod(foo#)), gp
++      addl    r17 = @ltoff(@dtprel(foo#)), gp
++      addl    r18 = @ltoff(@tprel(foo#)), gp
++      addl    r19 = @dtprel(foo#), gp
++      adds    r21 = @dtprel(foo#), r13
++      movl    r23 = @dtprel(foo#)
++      addl    r20 = @tprel(foo#), gp
++      adds    r22 = @tprel(foo#), r13
++      movl    r24 = @tprel(foo#)'
++      tls_first_major=2
++      tls_first_minor=13
++      ;;
++esac
++if test -z "$tls_first_major"; then
++  :
++elif test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
++then
++  if test "$gcc_cv_gas_major_version" -eq "$tls_first_major" \
++        -a "$gcc_cv_gas_minor_version" -ge "$tls_first_minor" \
++        -o "$gcc_cv_gas_major_version" -gt "$tls_first_major"; then
++    gcc_cv_as_tls=yes
++  fi
++elif test x$gcc_cv_as != x; then
++  echo "$conftest_s" > conftest.s
++  if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
++  then
++    gcc_cv_as_tls=yes
++  fi
++  rm -f conftest.s conftest.o
++fi
++if test "$gcc_cv_as_tls" = yes; then
++  AC_DEFINE(HAVE_AS_TLS, 1,
++          [Define if your assembler supports thread-local storage.])
++fi
++AC_MSG_RESULT($gcc_cv_as_tls)
++
+ case "$target" in
+   # All TARGET_ABI_OSF targets.
+   alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*)
+--- gcc/configure.jj   Sat Jun  8 00:38:27 2002
++++ gcc/configure      Wed Jun 19 22:28:09 2002
+@@ -7391,6 +7391,73 @@ EOF
+ fi
+ echo "$ac_t""$gcc_cv_as_shf_merge" 1>&6
++echo $ac_n "checking assembler thread-local storage support""... $ac_c" 1>&6
++echo "configure:7399: checking assembler thread-local storage support" >&5
++gcc_cv_as_tls=no
++conftest_s=
++tls_first_major=
++tls_first_minor=
++case "$target" in
++  i[34567]86-*-*)
++    conftest_s='
++      .section ".tdata","awT",@progbits
++foo:  .long   25
++      .text
++      movl    %gs:0, %eax
++      leal    foo@TLSGD(,%ebx,1), %eax
++      leal    foo@TLSLDM(%ebx), %eax
++      leal    foo@DTPOFF(%eax), %edx
++      movl    foo@GOTTPOFF(%ebx), %eax
++      subl    foo@GOTTPOFF(%ebx), %eax
++      movl    $foo@TPOFF, %eax
++      subl    $foo@TPOFF, %eax
++      leal    foo@NTPOFF(%ecx), %eax'
++      tls_first_major=2
++      tls_first_minor=13
++      ;;
++  ia64-*-*)
++    conftest_s='
++      .section ".tdata","awT",@progbits
++foo:  data8   25
++      .text
++      addl    r16 = @ltoff(@dtpmod(foo#)), gp
++      addl    r17 = @ltoff(@dtprel(foo#)), gp
++      addl    r18 = @ltoff(@tprel(foo#)), gp
++      addl    r19 = @dtprel(foo#), gp
++      adds    r21 = @dtprel(foo#), r13
++      movl    r23 = @dtprel(foo#)
++      addl    r20 = @tprel(foo#), gp
++      adds    r22 = @tprel(foo#), r13
++      movl    r24 = @tprel(foo#)'
++      tls_first_major=2
++      tls_first_minor=13
++      ;;
++esac
++if test -z "$tls_first_major"; then
++  :
++elif test x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x
++then
++  if test "$gcc_cv_gas_major_version" -eq "$tls_first_major" \
++        -a "$gcc_cv_gas_minor_version" -ge "$tls_first_minor" \
++        -o "$gcc_cv_gas_major_version" -gt "$tls_first_major"; then
++    gcc_cv_as_tls=yes
++  fi
++elif test x$gcc_cv_as != x; then
++  echo "$conftest_s" > conftest.s
++  if $gcc_cv_as --fatal-warnings -o conftest.o conftest.s > /dev/null 2>&1
++  then
++    gcc_cv_as_tls=yes
++  fi
++  rm -f conftest.s conftest.o
++fi
++if test "$gcc_cv_as_tls" = yes; then
++  cat >> confdefs.h <<\EOF
++#define HAVE_AS_TLS 1
++EOF
++
++fi
++echo "$ac_t""$gcc_cv_as_tls" 1>&6
++
+ case "$target" in
+   # All TARGET_ABI_OSF targets.
+   alpha*-*-osf* | alpha*-*-linux* | alpha*-*-*bsd*)
+--- gcc/output.h.jj    Wed Jun 19 19:33:50 2002
++++ gcc/output.h       Wed Jun 19 19:33:52 2002
+@@ -514,7 +514,8 @@ extern void no_asm_to_stream PARAMS ((FI
+ #define SECTION_STRINGS  0x10000      /* contains zero terminated strings without
+                                          embedded zeros */
+ #define SECTION_OVERRIDE 0x20000      /* allow override of default flags */
+-#define SECTION_MACH_DEP 0x40000      /* subsequent bits reserved for target */
++#define SECTION_TLS    0x40000        /* contains thread-local storage */
++#define SECTION_MACH_DEP 0x80000      /* subsequent bits reserved for target */
+ extern unsigned int get_named_section_flags PARAMS ((const char *));
+ extern bool set_named_section_flags   PARAMS ((const char *, unsigned int));
+--- gcc/print-tree.c.jj        Mon Mar 18 23:19:57 2002
++++ gcc/print-tree.c   Wed Jun 19 19:33:52 2002
+@@ -363,6 +363,8 @@ print_node (file, prefix, node, indent)
+       if (TREE_CODE (node) == VAR_DECL && DECL_IN_TEXT_SECTION (node))
+       fputs (" in-text-section", file);
++      if (TREE_CODE (node) == VAR_DECL && DECL_THREAD_LOCAL (node))
++      fputs (" thread-local", file);
+       if (TREE_CODE (node) == PARM_DECL && DECL_TRANSPARENT_UNION (node))
+       fputs (" transparent-union", file);
+--- gcc/target-def.h.jj        Tue Feb 12 16:19:14 2002
++++ gcc/target-def.h   Wed Jun 19 19:33:52 2002
+@@ -98,6 +98,10 @@ Foundation, 59 Temple Place - Suite 330,
+ #define TARGET_HAVE_NAMED_SECTIONS false
+ #endif
++#ifndef TARGET_HAVE_TLS
++#define TARGET_HAVE_TLS false
++#endif
++
+ #ifndef TARGET_ASM_EXCEPTION_SECTION
+ #define TARGET_ASM_EXCEPTION_SECTION default_exception_section
+ #endif
+@@ -194,9 +198,10 @@ Foundation, 59 Temple Place - Suite 330,
+   TARGET_INIT_BUILTINS,                               \
+   TARGET_EXPAND_BUILTIN,                      \
+   TARGET_SECTION_TYPE_FLAGS,                  \
++  TARGET_CANNOT_MODIFY_JUMPS_P,                       \
+   TARGET_HAVE_NAMED_SECTIONS,                 \
+   TARGET_HAVE_CTORS_DTORS,                    \
+-  TARGET_CANNOT_MODIFY_JUMPS_P                        \
++  TARGET_HAVE_TLS                             \
+ }
+ #include "hooks.h"
+--- gcc/target.h.jj    Tue Feb 12 16:19:14 2002
++++ gcc/target.h       Wed Jun 19 19:33:52 2002
+@@ -178,6 +178,10 @@ struct gcc_target
+   /* ??? Should be merged with SELECT_SECTION and UNIQUE_SECTION.  */
+   unsigned int (* section_type_flags) PARAMS ((tree, const char *, int));
++  /* True if new jumps cannot be created, to replace existing ones or
++     not, at the current point in the compilation.  */
++  bool (* cannot_modify_jumps_p) PARAMS ((void));
++
+   /* True if arbitrary sections are supported.  */
+   bool have_named_sections;
+@@ -185,9 +189,8 @@ struct gcc_target
+      false if we're using collect2 for the job.  */
+   bool have_ctors_dtors;
+-  /* True if new jumps cannot be created, to replace existing ones or
+-     not, at the current point in the compilation.  */
+-  bool (* cannot_modify_jumps_p) PARAMS ((void));
++  /* True if thread-local storage is supported.  */
++  bool have_tls;
+ };
+ extern struct gcc_target targetm;
+--- gcc/toplev.c.jj    Thu May 30 11:08:44 2002
++++ gcc/toplev.c       Wed Jun 19 19:33:52 2002
+@@ -682,12 +682,15 @@ int flag_shared_data;
+ int flag_delayed_branch;
+ /* Nonzero if we are compiling pure (sharable) code.
+-   Value is 1 if we are doing reasonable (i.e. simple
+-   offset into offset table) pic.  Value is 2 if we can
+-   only perform register offsets.  */
++   Value is 1 if we are doing "small" pic; value is 2 if we're doing
++   "large" pic.  */
+ int flag_pic;
++/* Set to the default thread-local storage (tls) model to use.  */
++
++enum tls_model flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
++
+ /* Nonzero means generate extra code for exception handling and enable
+    exception handling.  */
+@@ -3609,6 +3612,7 @@ display_help ()
+   printf (_("  -finline-limit=<number> Limits the size of inlined functions to <number>\n"));
+   printf (_("  -fmessage-length=<number> Limits diagnostics messages lengths to <number> characters per line.  0 suppresses line-wrapping\n"));
+   printf (_("  -fdiagnostics-show-location=[once | every-line] Indicates how often source location information should be emitted, as prefix, at the beginning of diagnostics when line-wrapping\n"));
++  printf (_("  -ftls-model=[global-dynamic | local-dynamic | initial-exec | local-exec] Indicates the default thread-local storage code generation model\n"));
+   for (i = ARRAY_SIZE (f_options); i--;)
+     {
+@@ -3887,6 +3891,19 @@ decode_f_option (arg)
+                                MAX_INLINE_INSNS);
+       set_param_value ("max-inline-insns", val);
+     }
++  else if ((option_value = skip_leading_substring (arg, "tls-model=")))
++    {
++      if (strcmp (option_value, "global-dynamic") == 0)
++      flag_tls_default = TLS_MODEL_GLOBAL_DYNAMIC;
++      else if (strcmp (option_value, "local-dynamic") == 0)
++      flag_tls_default = TLS_MODEL_LOCAL_DYNAMIC;
++      else if (strcmp (option_value, "initial-exec") == 0)
++      flag_tls_default = TLS_MODEL_INITIAL_EXEC;
++      else if (strcmp (option_value, "local-exec") == 0)
++      flag_tls_default = TLS_MODEL_LOCAL_EXEC;
++      else
++      warning ("`%s': unknown tls-model option", arg - 2);
++    }
+ #ifdef INSN_SCHEDULING
+   else if ((option_value = skip_leading_substring (arg, "sched-verbose=")))
+     fix_sched_param ("verbose", option_value);
+--- gcc/tree.c.jj      Sun Apr 28 23:20:20 2002
++++ gcc/tree.c Wed Jun 19 19:33:52 2002
+@@ -1510,12 +1510,13 @@ staticp (arg)
+     case FUNCTION_DECL:
+       /* Nested functions aren't static, since taking their address
+        involves a trampoline.  */
+-      return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+-      && ! DECL_NON_ADDR_CONST_P (arg);
++      return ((decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
++            && ! DECL_NON_ADDR_CONST_P (arg));
+     case VAR_DECL:
+-      return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+-      && ! DECL_NON_ADDR_CONST_P (arg);
++      return ((TREE_STATIC (arg) || DECL_EXTERNAL (arg))
++            && ! DECL_THREAD_LOCAL (arg)
++            && ! DECL_NON_ADDR_CONST_P (arg));
+     case CONSTRUCTOR:
+       return TREE_STATIC (arg);
+--- gcc/tree.h.jj      Wed Jun 19 19:33:50 2002
++++ gcc/tree.h Wed Jun 19 19:33:52 2002
+@@ -1614,6 +1614,10 @@ struct tree_type
+ /* In a FUNCTION_DECL, nonzero if the function cannot be inlined.  */
+ #define DECL_UNINLINABLE(NODE) (FUNCTION_DECL_CHECK (NODE)->decl.uninlinable)
++/* In a VAR_DECL, nonzero if the data should be allocated from 
++   thread-local storage.  */
++#define DECL_THREAD_LOCAL(NODE) (VAR_DECL_CHECK (NODE)->decl.thread_local_flag)
++
+ /* In a FUNCTION_DECL, the saved representation of the body of the
+    entire function.  Usually a COMPOUND_STMT, but in C++ this may also
+    be a RETURN_INIT, CTOR_INITIALIZER, or TRY_BLOCK.  */
+@@ -1792,7 +1796,8 @@ struct tree_decl
+   unsigned non_addressable : 1;
+   unsigned user_align : 1;
+   unsigned uninlinable : 1;
+-  /* Three unused bits.  */
++  unsigned thread_local_flag : 1;
++  /* Two unused bits.  */
+   unsigned lang_flag_0 : 1;
+   unsigned lang_flag_1 : 1;
+--- gcc/varasm.c.jj    Wed Jun 19 19:33:51 2002
++++ gcc/varasm.c       Wed Jun 19 19:33:52 2002
+@@ -1599,14 +1599,24 @@ assemble_variable (decl, top_level, at_e
+   /* Handle uninitialized definitions.  */
+-  if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+-      /* If the target can't output uninitialized but not common global data
+-       in .bss, then we have to use .data.  */
+-#if ! defined ASM_EMIT_BSS
+-      && DECL_COMMON (decl)
++  /* If the decl has been given an explicit section name, then it
++     isn't common, and shouldn't be handled as such.  */
++  if (DECL_SECTION_NAME (decl) || dont_output_data)
++    ;
++  /* We don't implement common thread-local data at present.  */
++  else if (DECL_THREAD_LOCAL (decl))
++    {
++      if (DECL_COMMON (decl))
++      sorry ("thread-local COMMON data not implemented");
++    }
++#ifndef ASM_EMIT_BSS
++  /* If the target can't output uninitialized but not common global data
++     in .bss, then we have to use .data.  */
++  else if (!DECL_COMMON (decl))
++    ;
+ #endif
+-      && DECL_SECTION_NAME (decl) == NULL_TREE
+-      && ! dont_output_data)
++  else if (DECL_INITIAL (decl) == 0
++         || DECL_INITIAL (decl) == error_mark_node)
+     {
+       unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+       unsigned HOST_WIDE_INT rounded = size;
+@@ -5324,14 +5334,22 @@ default_section_type_flags (decl, name, 
+   if (decl && DECL_ONE_ONLY (decl))
+     flags |= SECTION_LINKONCE;
++  if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
++    flags |= SECTION_TLS | SECTION_WRITE;
++
+   if (strcmp (name, ".bss") == 0
+       || strncmp (name, ".bss.", 5) == 0
+       || strncmp (name, ".gnu.linkonce.b.", 16) == 0
+       || strcmp (name, ".sbss") == 0
+       || strncmp (name, ".sbss.", 6) == 0
+-      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
++      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0
++      || strcmp (name, ".tbss") == 0)
+     flags |= SECTION_BSS;
++  if (strcmp (name, ".tdata") == 0
++      || strcmp (name, ".tbss") == 0)
++    flags |= SECTION_TLS;
++
+   return flags;
+ }
+@@ -5374,6 +5392,8 @@ default_elf_asm_named_section (name, fla
+     *f++ = 'M';
+   if (flags & SECTION_STRINGS)
+     *f++ = 'S';
++  if (flags & SECTION_TLS)
++    *f++ = 'T';
+   *f = '\0';
+   if (flags & SECTION_BSS)
This page took 0.179532 seconds and 4 git commands to generate.