]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Introduce TLS descriptors for i386 and x86_64.
authorAlexandre Oliva <aoliva@redhat.com>
Thu, 19 Jan 2006 00:40:16 +0000 (00:40 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Thu, 19 Jan 2006 00:40:16 +0000 (00:40 +0000)
* config/i386/i386.h (TARGET_GNU2_TLS): New macro.
(TARGET_ANY_GNU_TLS): New macro.
(enum tls_dialect): Added TLS_DIALECT_GNU2.
(struct machine_function): Add tls_descriptor_call_expanded_p.
(ix86_tls_descriptor_calls_expande_in_cfun): New macro.
(ix86_current_function_calls_tls_descriptor): Likewise.
* config/i386/i386.c (ix86_tls_dialect): Fix typo in comment.
(override_options): Introduce gnu2 tls dialect.
(ix86_frame_pointer_required): Functions containing TLSCALLs are
not leaves.
(ix86_select_alt_pic_regnum, ix86_compute_frame_layout):
Likewise.
(legitimize_tls_address): Adjust logic for GNU2 TLS.
(ix86_init_machine_status): Initialize new field.
(ix86_tls_get_addr): Use TARGET_ANY_GNU_TLS.
(ix86_tls_module_base): New.
* config/i386/i386-protos.h (ix86_tls_module_base): Declare it.
* config/i386/i386.md (UNSPEC_TLSDESC): New constant.
(tls_global_dynamic_32, tls_global_dynamic_64): Handle GNU2 TLS.
(tls_local_dynamic_base_32, tls_local_dynamic_base_64): Likewise.
(tls_dynamic_gnu2_32, *tls_dynamic_lea_32): New patterns.
(*tls_dynamic_call_32, *tls_dynamic_gnu2_combine_32): Likewise.
(tls_dynamic_gnu2_64, *tls_dynamic_lea_64): Likewise.
(*tls_dynamic_call_64, *tls_dynamic_gnu2_combine_64): Likewise.
* config/i386/predicates.md (tls_modbase_operand): New.
(tp_or_register_operand): New.

From-SVN: r109934

gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/predicates.md

index 642a89154ce6d5bfb37ccb182259cb4075b7a205..9511cdba0412356cd359a738c73a27b19272afcd 100644 (file)
@@ -1,3 +1,33 @@
+2006-01-18  Alexandre Oliva  <aoliva@redhat.com>
+
+       Introduce TLS descriptors for i386 and x86_64.
+       * config/i386/i386.h (TARGET_GNU2_TLS): New macro.
+       (TARGET_ANY_GNU_TLS): New macro.
+       (enum tls_dialect): Added TLS_DIALECT_GNU2.
+       (struct machine_function): Add tls_descriptor_call_expanded_p.
+       (ix86_tls_descriptor_calls_expande_in_cfun): New macro.
+       (ix86_current_function_calls_tls_descriptor): Likewise.
+       * config/i386/i386.c (ix86_tls_dialect): Fix typo in comment.
+       (override_options): Introduce gnu2 tls dialect.
+       (ix86_frame_pointer_required): Functions containing TLSCALLs are
+       not leaves.
+       (ix86_select_alt_pic_regnum, ix86_compute_frame_layout):
+       Likewise.
+       (legitimize_tls_address): Adjust logic for GNU2 TLS.
+       (ix86_init_machine_status): Initialize new field.
+       (ix86_tls_get_addr): Use TARGET_ANY_GNU_TLS.
+       (ix86_tls_module_base): New.
+       * config/i386/i386-protos.h (ix86_tls_module_base): Declare it.
+       * config/i386/i386.md (UNSPEC_TLSDESC): New constant.
+       (tls_global_dynamic_32, tls_global_dynamic_64): Handle GNU2 TLS.
+       (tls_local_dynamic_base_32, tls_local_dynamic_base_64): Likewise.
+       (tls_dynamic_gnu2_32, *tls_dynamic_lea_32): New patterns.
+       (*tls_dynamic_call_32, *tls_dynamic_gnu2_combine_32): Likewise.
+       (tls_dynamic_gnu2_64, *tls_dynamic_lea_64): Likewise.
+       (*tls_dynamic_call_64, *tls_dynamic_gnu2_combine_64): Likewise.
+       * config/i386/predicates.md (tls_modbase_operand): New.
+       (tp_or_register_operand): New.
+
 2006-01-18  Daniel Berlin  <dberlin@dberlin.org>
 
        * ipa-reference.c (check_operand):  Allow FUNCTION_DECL.
index 188c9677b77d713cef11e6fc8df21f89b8758a71..ed9d4f3d62e74cde6254b63b65926712a7543eb6 100644 (file)
@@ -1,6 +1,7 @@
 /* Definitions of target machine for GCC for IA-32.
    Copyright (C) 1988, 1992, 1994, 1995, 1996, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -179,6 +180,7 @@ extern int x86_field_alignment (tree, int);
 #endif
 
 extern rtx ix86_tls_get_addr (void);
+extern rtx ix86_tls_module_base (void);
 
 extern void ix86_expand_vector_init (bool, rtx, rtx);
 extern void ix86_expand_vector_set (bool, rtx, rtx, int);
index f4838de8d4b2755c7c3cefe03915ad279e742654..e45d2a266bd53ad029ea056e0e37c7fa7932f6d5 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on IA-32.
    Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -876,7 +876,7 @@ struct ix86_frame
 enum cmodel ix86_cmodel;
 /* Asm dialect.  */
 enum asm_dialect ix86_asm_dialect = ASM_ATT;
-/* TLS dialext.  */
+/* TLS dialects.  */
 enum tls_dialect ix86_tls_dialect = TLS_DIALECT_GNU;
 
 /* Which unit we are generating floating point math for.  */
@@ -1626,6 +1626,8 @@ override_options (void)
     {
       if (strcmp (ix86_tls_dialect_string, "gnu") == 0)
        ix86_tls_dialect = TLS_DIALECT_GNU;
+      else if (strcmp (ix86_tls_dialect_string, "gnu2") == 0)
+       ix86_tls_dialect = TLS_DIALECT_GNU2;
       else if (strcmp (ix86_tls_dialect_string, "sun") == 0)
        ix86_tls_dialect = TLS_DIALECT_SUN;
       else
@@ -4415,7 +4417,8 @@ ix86_frame_pointer_required (void)
      the frame pointer by default.  Turn it back on now if we've not
      got a leaf function.  */
   if (TARGET_OMIT_LEAF_FRAME_POINTER
-      && (!current_function_is_leaf))
+      && (!current_function_is_leaf
+         || ix86_current_function_calls_tls_descriptor))
     return 1;
 
   if (current_function_profile)
@@ -4597,7 +4600,8 @@ gen_push (rtx arg)
 static unsigned int
 ix86_select_alt_pic_regnum (void)
 {
-  if (current_function_is_leaf && !current_function_profile)
+  if (current_function_is_leaf && !current_function_profile
+      && !ix86_current_function_calls_tls_descriptor)
     {
       int i;
       for (i = 2; i >= 0; --i)
@@ -4788,7 +4792,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
      expander assumes that last current_function_outgoing_args_size
      of stack frame are unused.  */
   if (ACCUMULATE_OUTGOING_ARGS
-      && (!current_function_is_leaf || current_function_calls_alloca))
+      && (!current_function_is_leaf || current_function_calls_alloca
+         || ix86_current_function_calls_tls_descriptor))
     {
       offset += current_function_outgoing_args_size;
       frame->outgoing_arguments_size = current_function_outgoing_args_size;
@@ -4798,7 +4803,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
 
   /* Align stack boundary.  Only needed if we're calling another function
      or using alloca.  */
-  if (!current_function_is_leaf || current_function_calls_alloca)
+  if (!current_function_is_leaf || current_function_calls_alloca
+      || ix86_current_function_calls_tls_descriptor)
     frame->padding2 = ((offset + preferred_alignment - 1)
                       & -preferred_alignment) - offset;
   else
@@ -4819,7 +4825,8 @@ ix86_compute_frame_layout (struct ix86_frame *frame)
     frame->save_regs_using_mov = false;
 
   if (TARGET_RED_ZONE && current_function_sp_is_unchanging
-      && current_function_is_leaf)
+      && current_function_is_leaf
+      && !ix86_current_function_calls_tls_descriptor)
     {
       frame->red_zone_size = frame->to_allocate;
       if (frame->save_regs_using_mov)
@@ -6351,14 +6358,16 @@ get_thread_pointer (int to_reg)
 static rtx
 legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
 {
-  rtx dest, base, off, pic;
+  rtx dest, base, off, pic, tp;
   int type;
 
   switch (model)
     {
     case TLS_MODEL_GLOBAL_DYNAMIC:
       dest = gen_reg_rtx (Pmode);
-      if (TARGET_64BIT)
+      tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0;
+
+      if (TARGET_64BIT && ! TARGET_GNU2_TLS)
        {
          rtx rax = gen_rtx_REG (Pmode, 0), insns;
 
@@ -6369,13 +6378,24 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
 
          emit_libcall_block (insns, dest, rax, x);
        }
+      else if (TARGET_64BIT && TARGET_GNU2_TLS)
+       emit_insn (gen_tls_global_dynamic_64 (dest, x));
       else
        emit_insn (gen_tls_global_dynamic_32 (dest, x));
+
+      if (TARGET_GNU2_TLS)
+       {
+         dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, dest));
+
+         set_unique_reg_note (get_last_insn (), REG_EQUIV, x);
+       }
       break;
 
     case TLS_MODEL_LOCAL_DYNAMIC:
       base = gen_reg_rtx (Pmode);
-      if (TARGET_64BIT)
+      tp = TARGET_GNU2_TLS ? get_thread_pointer (1) : 0;
+
+      if (TARGET_64BIT && ! TARGET_GNU2_TLS)
        {
          rtx rax = gen_rtx_REG (Pmode, 0), insns, note;
 
@@ -6388,13 +6408,25 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
          note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note);
          emit_libcall_block (insns, base, rax, note);
        }
+      else if (TARGET_64BIT && TARGET_GNU2_TLS)
+       emit_insn (gen_tls_local_dynamic_base_64 (base));
       else
        emit_insn (gen_tls_local_dynamic_base_32 (base));
 
+      if (TARGET_GNU2_TLS)
+       {
+         rtx x = ix86_tls_module_base ();
+
+         base = force_reg (Pmode, gen_rtx_PLUS (Pmode, tp, base));
+
+         set_unique_reg_note (get_last_insn (), REG_EQUIV, x);
+       }
+
       off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPOFF);
       off = gen_rtx_CONST (Pmode, off);
 
-      return gen_rtx_PLUS (Pmode, base, off);
+      dest = force_reg (Pmode, gen_rtx_PLUS (Pmode, base, off));
+      break;
 
     case TLS_MODEL_INITIAL_EXEC:
       if (TARGET_64BIT)
@@ -6407,9 +6439,9 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
          if (reload_in_progress)
            regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
          pic = pic_offset_table_rtx;
-         type = TARGET_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF;
+         type = TARGET_ANY_GNU_TLS ? UNSPEC_GOTNTPOFF : UNSPEC_GOTTPOFF;
        }
-      else if (!TARGET_GNU_TLS)
+      else if (!TARGET_ANY_GNU_TLS)
        {
          pic = gen_reg_rtx (Pmode);
          emit_insn (gen_set_got (pic));
@@ -6428,7 +6460,7 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
       off = gen_const_mem (Pmode, off);
       set_mem_alias_set (off, ix86_GOT_alias_set ());
 
-      if (TARGET_64BIT || TARGET_GNU_TLS)
+      if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
        {
           base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
          off = force_reg (Pmode, off);
@@ -6444,11 +6476,11 @@ legitimize_tls_address (rtx x, enum tls_model model, int for_mov)
 
     case TLS_MODEL_LOCAL_EXEC:
       off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x),
-                           (TARGET_64BIT || TARGET_GNU_TLS)
+                           (TARGET_64BIT || TARGET_ANY_GNU_TLS)
                            ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
       off = gen_rtx_CONST (Pmode, off);
 
-      if (TARGET_64BIT || TARGET_GNU_TLS)
+      if (TARGET_64BIT || TARGET_ANY_GNU_TLS)
        {
          base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
          return gen_rtx_PLUS (Pmode, base, off);
@@ -12900,6 +12932,7 @@ ix86_init_machine_status (void)
 
   f = ggc_alloc_cleared (sizeof (struct machine_function));
   f->use_fast_prologue_epilogue_nregs = -1;
+  f->tls_descriptor_call_expanded_p = 0;
 
   return f;
 }
@@ -12942,13 +12975,32 @@ ix86_tls_get_addr (void)
   if (!ix86_tls_symbol)
     {
       ix86_tls_symbol = gen_rtx_SYMBOL_REF (Pmode,
-                                           (TARGET_GNU_TLS && !TARGET_64BIT)
+                                           (TARGET_ANY_GNU_TLS
+                                            && !TARGET_64BIT)
                                            ? "___tls_get_addr"
                                            : "__tls_get_addr");
     }
 
   return ix86_tls_symbol;
 }
+
+/* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol.  */
+
+static GTY(()) rtx ix86_tls_module_base_symbol;
+rtx
+ix86_tls_module_base (void)
+{
+
+  if (!ix86_tls_module_base_symbol)
+    {
+      ix86_tls_module_base_symbol = gen_rtx_SYMBOL_REF (Pmode,
+                                                       "_TLS_MODULE_BASE_");
+      SYMBOL_REF_FLAGS (ix86_tls_module_base_symbol)
+       |= TLS_MODEL_GLOBAL_DYNAMIC << SYMBOL_FLAG_TLS_SHIFT;
+    }
+
+  return ix86_tls_module_base_symbol;
+}
 \f
 /* Calculate the length of the memory address in the instruction
    encoding.  Does not include the one-byte modrm, opcode, or prefix.  */
index 88398d9ec2da036a8aba81fa91a37e6257b5967a..b402f3d95db4433eaa2d29571c0e0385ab83c7db 100644 (file)
@@ -1,6 +1,6 @@
 /* Definitions of target machine for GCC for IA-32.
    Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -225,6 +225,8 @@ extern int x86_prefetch_sse;
                             && (ix86_fpmath & FPMATH_387))
 
 #define TARGET_GNU_TLS (ix86_tls_dialect == TLS_DIALECT_GNU)
+#define TARGET_GNU2_TLS (ix86_tls_dialect == TLS_DIALECT_GNU2)
+#define TARGET_ANY_GNU_TLS (TARGET_GNU_TLS || TARGET_GNU2_TLS)
 #define TARGET_SUN_TLS (ix86_tls_dialect == TLS_DIALECT_SUN)
 
 #define TARGET_CMPXCHG (x86_cmpxchg & (1 << ix86_arch))
@@ -2134,6 +2136,7 @@ extern enum fpmath_unit ix86_fpmath;
 enum tls_dialect
 {
   TLS_DIALECT_GNU,
+  TLS_DIALECT_GNU2,
   TLS_DIALECT_SUN
 };
 
@@ -2275,11 +2278,30 @@ struct machine_function GTY(())
   /* Number of saved registers USE_FAST_PROLOGUE_EPILOGUE has been computed
      for.  */
   int use_fast_prologue_epilogue_nregs;
+  /* If true, the current function needs the default PIC register, not
+     an alternate register (on x86) and must not use the red zone (on
+     x86_64), even if it's a leaf function.  We don't want the
+     function to be regarded as non-leaf because TLS calls need not
+     affect register allocation.  This flag is set when a TLS call
+     instruction is expanded within a function, and never reset, even
+     if all such instructions are optimized away.  Use the
+     ix86_current_function_calls_tls_descriptor macro for a better
+     approximation.  */
+  int tls_descriptor_call_expanded_p;
 };
 
 #define ix86_stack_locals (cfun->machine->stack_locals)
 #define ix86_save_varrargs_registers (cfun->machine->save_varrargs_registers)
 #define ix86_optimize_mode_switching (cfun->machine->optimize_mode_switching)
+#define ix86_tls_descriptor_calls_expanded_in_cfun \
+  (cfun->machine->tls_descriptor_call_expanded_p)
+/* Since tls_descriptor_call_expanded is not cleared, even if all TLS
+   calls are optimized away, we try to detect cases in which it was
+   optimized away.  Since such instructions (use (reg REG_SP)), we can
+   verify whether there's any such instruction live by testing that
+   REG_SP is live.  */
+#define ix86_current_function_calls_tls_descriptor \
+  (ix86_tls_descriptor_calls_expanded_in_cfun && regs_ever_live[SP_REG])
 
 /* Control behavior of x86_file_start.  */
 #define X86_FILE_START_VERSION_DIRECTIVE false
index 146ed096c6aac36f4f615ee6f5bf6b3b00307fee..6b3b91cdc4521fa0df8969edbd1e46ff1198cf05 100644 (file)
@@ -1,6 +1,6 @@
 ;; GCC machine description for IA-32 and x86-64.
 ;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003, 2004, 2005
+;; 2001, 2002, 2003, 2004, 2005, 2006
 ;; Free Software Foundation, Inc.
 ;; Mostly by William Schelter.
 ;; x86_64 support added by Jan Hubicka
@@ -73,6 +73,7 @@
    (UNSPEC_TP                  16)
    (UNSPEC_TLS_GD              17)
    (UNSPEC_TLS_LD_BASE         18)
+   (UNSPEC_TLSDESC             19)
 
    ; Other random patterns
    (UNSPEC_SCAS                        20)
       operands[2] = gen_reg_rtx (Pmode);
       emit_insn (gen_set_got (operands[2]));
     }
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_32
+                 (operands[0], operands[1], operands[2]));
+       DONE;
+    }
   operands[3] = ix86_tls_get_addr ();
 })
 
                         UNSPEC_TLS_GD)])]
   ""
 {
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_64
+                 (operands[0], operands[1]));
+       DONE;
+    }
   operands[2] = ix86_tls_get_addr ();
 })
 
       operands[1] = gen_reg_rtx (Pmode);
       emit_insn (gen_set_got (operands[1]));
     }
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_32
+                 (operands[0], ix86_tls_module_base (), operands[1]));
+       DONE;
+    }
   operands[2] = ix86_tls_get_addr ();
 })
 
              (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)])]
   ""
 {
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_64
+                 (operands[0], ix86_tls_module_base ()));
+       DONE;
+    }
   operands[1] = ix86_tls_get_addr ();
 })
 
    (set_attr "length" "7")
    (set_attr "memory" "load")
    (set_attr "imm_disp" "false")])
+
+;; GNU2 TLS patterns can be split.
+
+(define_expand "tls_dynamic_gnu2_32"
+  [(set (match_dup 3)
+       (plus:SI (match_operand:SI 2 "register_operand" "")
+                (const:SI
+                 (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")]
+                            UNSPEC_TLSDESC))))
+   (parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (unspec:SI [(match_dup 1) (match_dup 3)
+                     (match_dup 2) (reg:SI SP_REG)]
+                     UNSPEC_TLSDESC))
+     (clobber (reg:CC FLAGS_REG))])]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+{
+  operands[3] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  ix86_tls_descriptor_calls_expanded_in_cfun = true;
+})
+
+(define_insn "*tls_dynamic_lea_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "b")
+                (const:SI
+                 (unspec:SI [(match_operand:SI 2 "tls_symbolic_operand" "")]
+                             UNSPEC_TLSDESC))))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "lea{l}\t{%a2@TLSDESC(%1), %0|%0, %a2@TLSDESC[%1]}"
+  [(set_attr "type" "lea")
+   (set_attr "mode" "SI")
+   (set_attr "length" "6")
+   (set_attr "length_address" "4")])
+
+(define_insn "*tls_dynamic_call_32"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")
+                   (match_operand:SI 2 "register_operand" "0")
+                   ;; we have to make sure %ebx still points to the GOT
+                   (match_operand:SI 3 "register_operand" "b")
+                   (reg:SI SP_REG)]
+                  UNSPEC_TLSDESC))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "call\t{*%a1@TLSCALL(%2)|[DWORD PTR [%2+%a1@TLSCALL]]}"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")
+   (set_attr "length_address" "0")])
+
+(define_insn_and_split "*tls_dynamic_gnu2_combine_32"
+  [(set (match_operand:SI 0 "register_operand" "=&a")
+       (plus:SI
+        (plus:SI (match_operand:SI 3 "tp_or_register_operand" "ir")
+                 (unspec:SI [(match_operand:SI 4 "tls_modbase_operand" "")
+                             (match_operand:SI 5 "" "")
+                             (match_operand:SI 2 "register_operand" "b")
+                             (reg:SI SP_REG)]
+                            UNSPEC_TLSDESC))
+        (const:SI (unspec:SI
+                   [(match_operand:SI 1 "tls_symbolic_operand" "")]
+                   UNSPEC_DTPOFF))))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "#"
+  ""
+  [(parallel
+    [(set (match_dup 0)
+         (plus:SI (match_dup 3)
+                  (match_dup 5)))
+     (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[5] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_dynamic_gnu2_32 (operands[5], operands[1], operands[2]));
+})
+
+(define_expand "tls_dynamic_gnu2_64"
+  [(set (match_dup 2)
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                  UNSPEC_TLSDESC))
+   (parallel
+    [(set (match_operand:DI 0 "register_operand" "")
+         (unspec:DI [(match_dup 1) (match_dup 2) (reg:DI SP_REG)]
+                    UNSPEC_TLSDESC))
+     (clobber (reg:CC FLAGS_REG))])]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+{
+  operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  ix86_tls_descriptor_calls_expanded_in_cfun = true;
+})
+
+(define_insn "*tls_dynamic_lea_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                  UNSPEC_TLSDESC))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "lea{q}\t{%a1@TLSDESC(%%rip), %0|%0, %a1@TLSDESC[%%rip]}"
+  [(set_attr "type" "lea")
+   (set_attr "mode" "DI")
+   (set_attr "length" "7")
+   (set_attr "length_address" "4")])
+
+(define_insn "*tls_dynamic_call_64"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")
+                   (match_operand:DI 2 "register_operand" "0")
+                   (reg:DI SP_REG)]
+                  UNSPEC_TLSDESC))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "call\t{*%a1@TLSCALL(%2)|[QWORD PTR [%2+%a1@TLSCALL]]}"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")
+   (set_attr "length_address" "0")])
+
+(define_insn_and_split "*tls_dynamic_gnu2_combine_64"
+  [(set (match_operand:DI 0 "register_operand" "=&a")
+       (plus:DI
+        (plus:DI (match_operand:DI 2 "tp_or_register_operand" "ir")
+                 (unspec:DI [(match_operand:DI 3 "tls_modbase_operand" "")
+                             (match_operand:DI 4 "" "")
+                             (reg:DI SP_REG)]
+                             UNSPEC_TLSDESC))
+        (const:DI (unspec:DI
+                   [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                   UNSPEC_DTPOFF))))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "#"
+  ""
+  [(parallel
+    [(set (match_dup 0)
+         (plus:DI (match_dup 2)
+                  (match_dup 4)))
+     (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[4] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_dynamic_gnu2_64 (operands[4], operands[1]));
+})
+
+;;
 \f
 ;; These patterns match the binary 387 instructions for addM3, subM3,
 ;; mulM3 and divM3.  There are three patterns for each of DFmode and
index bc16628439bc5e86b44ab220d8d9801a0715e7b3..d87284d9ab9872b9f8fbda1e40747ef71599b80f 100644 (file)
@@ -1,5 +1,5 @@
 ;; Predicate definitions for IA-32 and x86-64.
-;; Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+;; Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
 ;;
 ;; This file is part of GCC.
 ;;
   (and (match_code "symbol_ref")
        (match_test "SYMBOL_REF_TLS_MODEL (op) != 0")))
 
+(define_predicate "tls_modbase_operand"
+  (and (match_code "symbol_ref")
+       (match_test "op == ix86_tls_module_base ()")))
+
+(define_predicate "tp_or_register_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "unspec")
+           (match_test "XINT (op, 1) == UNSPEC_TP"))))
+
 ;; Test for a pc-relative call operand
 (define_predicate "constant_call_address_operand"
   (ior (match_code "symbol_ref")