OSDN Git Service

* config/i386/i386.c (struct ix86_address): Add seg.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 5 Jun 2003 00:23:23 +0000 (00:23 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 5 Jun 2003 00:23:23 +0000 (00:23 +0000)
        (no_seg_address_operand): New.
        (ix86_decompose_address): Restructure PLUS loop.  Accept one
        UNSPEC_TP if TARGET_TLS_DIRECT_SEG_REFS.  Adjust ESP swap test
        to test for a regnum, not stack_pointer_rtx.
        (ix86_address_cost): Reduce cost if non-default segment.
        (legitimate_address_p): Remove UNSPEC_TP check.
        (get_thread_pointer): Add to_reg argument.  Don't represent
        the thread pointer as a memory load.
        (legitimize_tls_address): Split out of ...
        (legitimize_address): ... here.
        (print_operand_address): Handle parts.seg.
        (ix86_expand_move): Use legitimize_tls_address.
        (ix86_rtx_costs): Handle UNSPEC_TP.
        * config/i386/i386.h (MASK_TLS_DIRECT_SEG_REFS): New.
        (TARGET_TLS_DIRECT_SEG_REFS): New.
        (TARGET_SWITCHES): Add tls-direct-seg-refs.
        (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Default.
        (PREDICATE_CODES): Add no_seg_address_operand.
        * config/i386/i386.md (lea_1): Use it.
        (lea_1_rex64, lea_1_zext, lea_2_rex64): Likewise.
        (load_tp_si, add_tp_si, load_tp_di, add_tp_di): New.
        * config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
        * config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
        * doc/invoke.texi: Add -mtls-direct-seg-refs.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@67475 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/config/i386/linux.h
gcc/config/i386/linux64.h
gcc/doc/invoke.texi

index a3a252a..a057fc2 100644 (file)
@@ -1,3 +1,31 @@
+2003-06-04  Richard Henderson  <rth@redhat.com>
+
+       * config/i386/i386.c (struct ix86_address): Add seg.
+       (no_seg_address_operand): New.
+       (ix86_decompose_address): Restructure PLUS loop.  Accept one
+       UNSPEC_TP if TARGET_TLS_DIRECT_SEG_REFS.  Adjust ESP swap test
+       to test for a regnum, not stack_pointer_rtx.
+       (ix86_address_cost): Reduce cost if non-default segment.
+       (legitimate_address_p): Remove UNSPEC_TP check.
+       (get_thread_pointer): Add to_reg argument.  Don't represent
+       the thread pointer as a memory load.
+       (legitimize_tls_address): Split out of ...
+       (legitimize_address): ... here.
+       (print_operand_address): Handle parts.seg.
+       (ix86_expand_move): Use legitimize_tls_address.
+       (ix86_rtx_costs): Handle UNSPEC_TP.
+       * config/i386/i386.h (MASK_TLS_DIRECT_SEG_REFS): New.
+       (TARGET_TLS_DIRECT_SEG_REFS): New.
+       (TARGET_SWITCHES): Add tls-direct-seg-refs.
+       (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Default.
+       (PREDICATE_CODES): Add no_seg_address_operand.
+       * config/i386/i386.md (lea_1): Use it.
+       (lea_1_rex64, lea_1_zext, lea_2_rex64): Likewise.
+       (load_tp_si, add_tp_si, load_tp_di, add_tp_di): New.
+       * config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
+       * config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): New.
+       * doc/invoke.texi: Add -mtls-direct-seg-refs.
+
 2003-06-04  Mark Mitchell  <mark@codesourcery.com>
 
        * Makefile.in (QMTESTRUNFLAGS): Set for DejaGNU emulation.
index f2d94c2..f36c99c 100644 (file)
@@ -793,7 +793,8 @@ 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 get_thread_pointer PARAMS ((int));
+static rtx legitimize_tls_address PARAMS ((rtx, enum tls_model, int));
 static void get_pc_thunk_name PARAMS ((char [32], unsigned int));
 static rtx gen_push PARAMS ((rtx));
 static int memory_address_length PARAMS ((rtx addr));
@@ -835,6 +836,7 @@ struct ix86_address
 {
   rtx base, index, disp;
   HOST_WIDE_INT scale;
+  enum ix86_address_seg { SEG_DEFAULT, SEG_FS, SEG_GS } seg;
 };
 
 static int ix86_decompose_address PARAMS ((rtx, struct ix86_address *));
@@ -3863,6 +3865,25 @@ vector_move_operand (op, mode)
   return (op == CONST0_RTX (GET_MODE (op)));
 }
 
+/* Return true if op if a valid address, and does not contain
+   a segment override.  */
+
+int
+no_seg_address_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  struct ix86_address parts;
+
+  if (! address_operand (op, mode))
+    return 0;
+
+  if (! ix86_decompose_address (op, &parts))
+    abort ();
+
+  return parts.seg == SEG_DEFAULT;
+}
+
 /* Return 1 if OP is a comparison that can be used in the CMPSS/CMPPS
    insns.  */
 int
@@ -5403,8 +5424,7 @@ ix86_output_function_epilogue (file, size)
 /* Extract the parts of an RTL expression that is a valid memory address
    for an instruction.  Return 0 if the structure of the address is
    grossly off.  Return -1 if the address contains ASHIFT, so it is not
-   strictly valid, but still used for computing length of lea instruction.
-   */
+   strictly valid, but still used for computing length of lea instruction.  */
 
 static int
 ix86_decompose_address (addr, out)
@@ -5417,47 +5437,72 @@ ix86_decompose_address (addr, out)
   HOST_WIDE_INT scale = 1;
   rtx scale_rtx = NULL_RTX;
   int retval = 1;
+  enum ix86_address_seg seg = SEG_DEFAULT;
 
   if (REG_P (addr) || GET_CODE (addr) == SUBREG)
     base = addr;
   else if (GET_CODE (addr) == PLUS)
     {
-      rtx op0 = XEXP (addr, 0);
-      rtx op1 = XEXP (addr, 1);
-      enum rtx_code code0 = GET_CODE (op0);
-      enum rtx_code code1 = GET_CODE (op1);
+      rtx addends[4], op;
+      int n = 0, i;
 
-      if (code0 == REG || code0 == SUBREG)
-       {
-         if (code1 == REG || code1 == SUBREG)
-           index = op0, base = op1;    /* index + base */
-         else
-           base = op0, disp = op1;     /* base + displacement */
-       }
-      else if (code0 == MULT)
-       {
-         index = XEXP (op0, 0);
-         scale_rtx = XEXP (op0, 1);
-         if (code1 == REG || code1 == SUBREG)
-           base = op1;                 /* index*scale + base */
-         else
-           disp = op1;                 /* index*scale + disp */
-       }
-      else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
+      op = addr;
+      do
        {
-         index = XEXP (XEXP (op0, 0), 0);      /* index*scale + base + disp */
-         scale_rtx = XEXP (XEXP (op0, 0), 1);
-         base = XEXP (op0, 1);
-         disp = op1;
+         if (n >= 4)
+           return 0;
+         addends[n++] = XEXP (op, 1);
+         op = XEXP (op, 0);
        }
-      else if (code0 == PLUS)
+      while (GET_CODE (op) == PLUS);
+      if (n >= 4)
+       return 0;
+      addends[n] = op;
+
+      for (i = n; i >= 0; --i)
        {
-         index = XEXP (op0, 0);        /* index + base + disp */
-         base = XEXP (op0, 1);
-         disp = op1;
+         op = addends[i];
+         switch (GET_CODE (op))
+           {
+           case MULT:
+             if (index)
+               return 0;
+             index = XEXP (op, 0);
+             scale_rtx = XEXP (op, 1);
+             break;
+
+           case UNSPEC:
+             if (XINT (op, 1) == UNSPEC_TP
+                 && TARGET_TLS_DIRECT_SEG_REFS
+                 && seg == SEG_DEFAULT)
+               seg = TARGET_64BIT ? SEG_FS : SEG_GS;
+             else
+               return 0;
+             break;
+
+           case REG:
+           case SUBREG:
+             if (!base)
+               base = op;
+             else if (!index)
+               index = op;
+             else
+               return 0;
+             break;
+
+           case CONST:
+           case CONST_INT:
+           case SYMBOL_REF:
+           case LABEL_REF:
+             if (disp)
+               return 0;
+             disp = op;
+             break;
+
+           default:
+             return 0;
+           }
        }
-      else
-       return 0;
     }
   else if (GET_CODE (addr) == MULT)
     {
@@ -5490,10 +5535,11 @@ ix86_decompose_address (addr, out)
       scale = INTVAL (scale_rtx);
     }
 
-  /* Allow arg pointer and stack pointer as index if there is not scaling */
+  /* Allow arg pointer and stack pointer as index if there is not scaling */
   if (base && index && scale == 1
-      && (index == arg_pointer_rtx || index == frame_pointer_rtx
-          || index == stack_pointer_rtx))
+      && (index == arg_pointer_rtx
+         || index == frame_pointer_rtx
+         || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM)))
     {
       rtx tmp = base;
       base = index;
@@ -5526,6 +5572,7 @@ ix86_decompose_address (addr, out)
   out->index = index;
   out->disp = disp;
   out->scale = scale;
+  out->seg = seg;
 
   return retval;
 }
@@ -5553,6 +5600,8 @@ ix86_address_cost (x)
   /* More complex memory references are better.  */
   if (parts.disp && parts.disp != const0_rtx)
     cost--;
+  if (parts.seg != SEG_DEFAULT)
+    cost--;
 
   /* Attempt to minimize number of registers in the address.  */
   if ((parts.base
@@ -5871,13 +5920,6 @@ legitimate_address_p (mode, addr, strict)
       debug_rtx (addr);
     }
 
-  if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP)
-    {
-      if (TARGET_DEBUG_ADDR)
-       fprintf (stderr, "Success.\n");
-      return TRUE;
-    }
-
   if (ix86_decompose_address (addr, &parts) <= 0)
     {
       reason = "decomposition failed";
@@ -6267,20 +6309,151 @@ legitimize_pic_address (orig, reg)
   return new;
 }
 \f
-/* Load the thread pointer into a register.  */
+/* Load the thread pointer.  If TO_REG is true, force it into a register.  */
 
 static rtx
-get_thread_pointer ()
+get_thread_pointer (to_reg)
+     int to_reg;
 {
-  rtx tp;
+  rtx tp, reg, insn;
 
   tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
-  tp = gen_rtx_MEM (Pmode, tp);
-  RTX_UNCHANGING_P (tp) = 1;
-  set_mem_alias_set (tp, ix86_GOT_alias_set ());
-  tp = force_reg (Pmode, tp);
+  if (!to_reg)
+    return tp;
 
-  return tp;
+  reg = gen_reg_rtx (Pmode);
+  insn = gen_rtx_SET (VOIDmode, reg, tp);
+  insn = emit_insn (insn);
+
+  return reg;
+}
+
+/* A subroutine of legitimize_address and ix86_expand_move.  FOR_MOV is
+   false if we expect this to be used for a memory address and true if
+   we expect to load the address into a register.  */
+
+static rtx
+legitimize_tls_address (x, model, for_mov)
+     rtx x;
+     enum tls_model model;
+     int for_mov;
+{
+  rtx dest, base, off, pic;
+  int type;
+
+  switch (model)
+    {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      dest = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       {
+         rtx rax = gen_rtx_REG (Pmode, 0), insns;
+
+         start_sequence ();
+         emit_call_insn (gen_tls_global_dynamic_64 (rax, x));
+         insns = get_insns ();
+         end_sequence ();
+
+         emit_libcall_block (insns, dest, rax, x);
+       }
+      else
+       emit_insn (gen_tls_global_dynamic_32 (dest, x));
+      break;
+
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      base = gen_reg_rtx (Pmode);
+      if (TARGET_64BIT)
+       {
+         rtx rax = gen_rtx_REG (Pmode, 0), insns, note;
+
+         start_sequence ();
+         emit_call_insn (gen_tls_local_dynamic_base_64 (rax));
+         insns = get_insns ();
+         end_sequence ();
+
+         note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
+         note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note);
+         emit_libcall_block (insns, base, rax, note);
+       }
+      else
+       emit_insn (gen_tls_local_dynamic_base_32 (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 (TARGET_64BIT)
+       {
+         pic = NULL;
+         type = UNSPEC_GOTNTPOFF;
+       }
+      else if (flag_pic)
+       {
+         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;
+       }
+      else if (!TARGET_GNU_TLS)
+       {
+         pic = gen_reg_rtx (Pmode);
+         emit_insn (gen_set_got (pic));
+         type = UNSPEC_GOTTPOFF;
+       }
+      else
+       {
+         pic = NULL;
+         type = UNSPEC_INDNTPOFF;
+       }
+
+      off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), type);
+      off = gen_rtx_CONST (Pmode, off);
+      if (pic)
+       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 ());
+
+      if (TARGET_64BIT || TARGET_GNU_TLS)
+       {
+          base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
+         off = force_reg (Pmode, off);
+         return gen_rtx_PLUS (Pmode, base, off);
+       }
+      else
+       {
+         base = get_thread_pointer (true);
+         dest = gen_reg_rtx (Pmode);
+         emit_insn (gen_subsi3 (dest, base, off));
+       }
+      break;
+
+    case TLS_MODEL_LOCAL_EXEC:
+      off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x),
+                           (TARGET_64BIT || TARGET_GNU_TLS)
+                           ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
+      off = gen_rtx_CONST (Pmode, off);
+
+      if (TARGET_64BIT || TARGET_GNU_TLS)
+       {
+         base = get_thread_pointer (for_mov || !TARGET_TLS_DIRECT_SEG_REFS);
+         return gen_rtx_PLUS (Pmode, base, off);
+       }
+      else
+       {
+         base = get_thread_pointer (true);
+         dest = gen_reg_rtx (Pmode);
+         emit_insn (gen_subsi3 (dest, base, off));
+       }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return dest;
 }
 
 /* Try machine-dependent ways of modifying an illegitimate address
@@ -6322,120 +6495,7 @@ legitimize_address (x, oldx, mode)
 
   log = tls_symbolic_operand (x, mode);
   if (log)
-    {
-      rtx dest, base, off, pic;
-      int type;
-
-      switch (log)
-        {
-        case TLS_MODEL_GLOBAL_DYNAMIC:
-         dest = gen_reg_rtx (Pmode);
-         if (TARGET_64BIT)
-           {
-             rtx rax = gen_rtx_REG (Pmode, 0), insns;
-
-             start_sequence ();
-             emit_call_insn (gen_tls_global_dynamic_64 (rax, x));
-             insns = get_insns ();
-             end_sequence ();
-
-             emit_libcall_block (insns, dest, rax, x);
-           }
-         else
-           emit_insn (gen_tls_global_dynamic_32 (dest, x));
-         break;
-
-        case TLS_MODEL_LOCAL_DYNAMIC:
-         base = gen_reg_rtx (Pmode);
-         if (TARGET_64BIT)
-           {
-             rtx rax = gen_rtx_REG (Pmode, 0), insns, note;
-
-             start_sequence ();
-             emit_call_insn (gen_tls_local_dynamic_base_64 (rax));
-             insns = get_insns ();
-             end_sequence ();
-
-             note = gen_rtx_EXPR_LIST (VOIDmode, const0_rtx, NULL);
-             note = gen_rtx_EXPR_LIST (VOIDmode, ix86_tls_get_addr (), note);
-             emit_libcall_block (insns, base, rax, note);
-           }
-         else
-           emit_insn (gen_tls_local_dynamic_base_32 (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 (TARGET_64BIT)
-           {
-             pic = NULL;
-             type = UNSPEC_GOTNTPOFF;
-           }
-         else if (flag_pic)
-           {
-             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;
-           }
-         else if (!TARGET_GNU_TLS)
-           {
-             pic = gen_reg_rtx (Pmode);
-             emit_insn (gen_set_got (pic));
-             type = UNSPEC_GOTTPOFF;
-           }
-         else
-           {
-             pic = NULL;
-             type = UNSPEC_INDNTPOFF;
-           }
-
-         base = get_thread_pointer ();
-
-         off = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), type);
-         off = gen_rtx_CONST (Pmode, off);
-         if (pic)
-           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 ());
-         dest = gen_reg_rtx (Pmode);
-
-         if (TARGET_64BIT || TARGET_GNU_TLS)
-           {
-             emit_move_insn (dest, off);
-             return gen_rtx_PLUS (Pmode, base, dest);
-           }
-         else
-           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_64BIT || TARGET_GNU_TLS)
-                               ? UNSPEC_NTPOFF : UNSPEC_TPOFF);
-         off = gen_rtx_CONST (Pmode, off);
-
-         if (TARGET_64BIT || 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;
-    }
+    return legitimize_tls_address (x, log, false);
 
   if (flag_pic && SYMBOLIC_CONST (x))
     return legitimize_pic_address (x, 0);
@@ -7418,8 +7478,8 @@ print_operand (file, x, code)
       fprintf (file, "0x%lx", l);
     }
 
- /* These float cases don't actually occur as immediate operands.  */
- else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
 /* These float cases don't actually occur as immediate operands.  */
 else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
     {
       char dstr[30];
 
@@ -7474,19 +7534,6 @@ print_operand_address (file, addr)
   rtx base, index, disp;
   int scale;
 
-  if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP)
-    {
-      if (ASSEMBLER_DIALECT == ASM_INTEL)
-       fputs ("DWORD PTR ", file);
-      if (ASSEMBLER_DIALECT == ASM_ATT || USER_LABEL_PREFIX[0] == 0)
-       putc ('%', file);
-      if (TARGET_64BIT)
-       fputs ("fs:0", file);
-      else
-       fputs ("gs:0", file);
-      return;
-    }
-
   if (! ix86_decompose_address (addr, &parts))
     abort ();
 
@@ -7495,35 +7542,49 @@ print_operand_address (file, addr)
   disp = parts.disp;
   scale = parts.scale;
 
+  switch (parts.seg)
+    {
+    case SEG_DEFAULT:
+      break;
+    case SEG_FS:
+    case SEG_GS:
+      if (USER_LABEL_PREFIX[0] == 0)
+       putc ('%', file);
+      fputs ((parts.seg == SEG_FS ? "fs:" : "gs:"), file);
+      break;
+    default:
+      abort ();
+    }
+
   if (!base && !index)
     {
       /* Displacement only requires special attention.  */
 
       if (GET_CODE (disp) == CONST_INT)
        {
-         if (ASSEMBLER_DIALECT == ASM_INTEL)
+         if (ASSEMBLER_DIALECT == ASM_INTEL && parts.seg == SEG_DEFAULT)
            {
              if (USER_LABEL_PREFIX[0] == 0)
                putc ('%', file);
              fputs ("ds:", file);
            }
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
        }
       else if (flag_pic)
-       output_pic_addr_const (file, addr, 0);
+       output_pic_addr_const (file, disp, 0);
       else
-       output_addr_const (file, addr);
+       output_addr_const (file, disp);
 
       /* Use one byte shorter RIP relative addressing for 64bit mode.  */
       if (TARGET_64BIT
-         && ((GET_CODE (addr) == SYMBOL_REF
-              && ! tls_symbolic_operand (addr, GET_MODE (addr)))
-             || GET_CODE (addr) == LABEL_REF
-             || (GET_CODE (addr) == CONST
-                 && GET_CODE (XEXP (addr, 0)) == PLUS
-                 && (GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF
-                     || GET_CODE (XEXP (XEXP (addr, 0), 0)) == LABEL_REF)
-                 && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)))
+         && ((GET_CODE (disp) == SYMBOL_REF
+              && ! tls_symbolic_operand (disp, GET_MODE (disp)))
+             || GET_CODE (disp) == LABEL_REF
+             || (GET_CODE (disp) == CONST
+                 && GET_CODE (XEXP (disp, 0)) == PLUS
+                 && (GET_CODE (XEXP (XEXP (disp, 0), 0)) == SYMBOL_REF
+                     || GET_CODE (XEXP (XEXP (disp, 0), 0)) == LABEL_REF)
+                 && GET_CODE (XEXP (XEXP (disp, 0), 1)) == CONST_INT)))
        fputs ("(%rip)", file);
     }
   else
@@ -8220,22 +8281,22 @@ ix86_expand_move (mode, operands)
      rtx operands[];
 {
   int strict = (reload_in_progress || reload_completed);
-  rtx insn, op0, op1, tmp;
+  rtx op0, op1;
+  enum tls_model model;
 
   op0 = operands[0];
   op1 = operands[1];
 
-  if (tls_symbolic_operand (op1, Pmode))
+  model = tls_symbolic_operand (op1, Pmode);
+  if (model)
     {
-      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;
-       }
+      op1 = legitimize_tls_address (op1, model, true);
+      op1 = force_operand (op1, op0);
+      if (op1 == op0)
+       return;
     }
-  else if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
+
+  if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
     {
 #if TARGET_MACHO
       if (MACHOPIC_PURE)
@@ -8248,18 +8309,11 @@ ix86_expand_move (mode, operands)
          op1 = machopic_legitimize_pic_address (op1, mode,
                                                 temp == op1 ? 0 : temp);
        }
-      else
-       {
-         if (MACHOPIC_INDIRECT)
-           op1 = machopic_indirect_data_reference (op1, 0);
-       }
-      if (op0 != op1)
-       {
-         insn = gen_rtx_SET (VOIDmode, op0, op1);
-         emit_insn (insn);
-       }
-      return;
-#endif /* TARGET_MACHO */
+      else if (MACHOPIC_INDIRECT)
+       op1 = machopic_indirect_data_reference (op1, 0);
+      if (op0 == op1)
+       return;
+#else
       if (GET_CODE (op0) == MEM)
        op1 = force_reg (Pmode, op1);
       else
@@ -8272,6 +8326,7 @@ ix86_expand_move (mode, operands)
            return;
          op1 = temp;
        }
+#endif /* TARGET_MACHO */
     }
   else
     {
@@ -8316,9 +8371,7 @@ ix86_expand_move (mode, operands)
        }
     }
 
-  insn = gen_rtx_SET (VOIDmode, op0, op1);
-
-  emit_insn (insn);
+  emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
 }
 
 void
@@ -15094,6 +15147,11 @@ ix86_rtx_costs (x, code, outer_code, total)
        *total = COSTS_N_INSNS (ix86_cost->fsqrt);
       return false;
 
+    case UNSPEC:
+      if (XINT (x, 1) == UNSPEC_TP)
+       *total = 0;
+      return false;
+
     default:
       return false;
     }
index fe47b03..f543c28 100644 (file)
@@ -122,6 +122,7 @@ extern int target_flags;
 #define MASK_128BIT_LONG_DOUBLE 0x00040000     /* long double size is 128bit */
 #define MASK_64BIT             0x00080000      /* Produce 64bit code */
 #define MASK_MS_BITFIELD_LAYOUT 0x00100000     /* Use native (MS) bitfield layout */
+#define MASK_TLS_DIRECT_SEG_REFS 0x00200000    /* Avoid adding %gs:0  */
 
 /* Unused:                     0x03e0000       */
 
@@ -201,6 +202,9 @@ extern int target_flags;
 #endif
 #endif
 
+/* Avoid adding %gs:0 in TLS references; use %gs:address directly.  */
+#define TARGET_TLS_DIRECT_SEG_REFS (target_flags & MASK_TLS_DIRECT_SEG_REFS)
+
 #define TARGET_386 (ix86_tune == PROCESSOR_I386)
 #define TARGET_486 (ix86_tune == PROCESSOR_I486)
 #define TARGET_PENTIUM (ix86_tune == PROCESSOR_PENTIUM)
@@ -405,12 +409,21 @@ extern int x86_prefetch_sse;
     N_("Use red-zone in the x86-64 code") },                                 \
   { "no-red-zone",             MASK_NO_RED_ZONE,                             \
     N_("Do not use red-zone in the x86-64 code") },                          \
+  { "tls-direct-seg-refs",     MASK_TLS_DIRECT_SEG_REFS,                     \
+    N_("Use direct references against %gs when accessing tls data") },       \
+  { "no-tls-direct-seg-refs",  -MASK_TLS_DIRECT_SEG_REFS,                    \
+    N_("Do not use direct references against %gs when accessing tls data") }, \
   SUBTARGET_SWITCHES                                                         \
-  { "", TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT, 0 }}
+  { "",                                                                              \
+    TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT         \
+    | TARGET_TLS_DIRECT_SEG_REFS_DEFAULT, 0 }}
 
 #ifndef TARGET_64BIT_DEFAULT
 #define TARGET_64BIT_DEFAULT 0
 #endif
+#ifndef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT
+#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT 0
+#endif
 
 /* Once GDB has been enhanced to deal with functions without frame
    pointers, we can change this to allow for elimination of
@@ -3034,6 +3047,8 @@ do {                                              \
   {"register_and_not_fp_reg_operand", {REG}},                          \
   {"zero_extended_scalar_load_operand", {MEM}},                                \
   {"vector_move_operand", {CONST_VECTOR, SUBREG, REG, MEM}},           \
+  {"no_seg_address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
+                             LABEL_REF, SUBREG, REG, MEM, PLUS, MULT}},
 
 /* A list of predicates that do special things with modes, and so
    should not elicit warnings for VOIDmode match_operand.  */
index 6806c7a..a027a76 100644 (file)
 
 (define_insn "*lea_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (match_operand:SI 1 "address_operand" "p"))]
+       (match_operand:SI 1 "no_seg_address_operand" "p"))]
   "!TARGET_64BIT"
   "lea{l}\t{%a1, %0|%0, %a1}"
   [(set_attr "type" "lea")
 
 (define_insn "*lea_1_rex64"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (subreg:SI (match_operand:DI 1 "address_operand" "p") 0))]
+       (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0))]
   "TARGET_64BIT"
   "lea{l}\t{%a1, %0|%0, %a1}"
   [(set_attr "type" "lea")
 
 (define_insn "*lea_1_zext"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (zero_extend:DI (subreg:SI (match_operand:DI 1 "address_operand" "p") 0)))]
+       (zero_extend:DI
+        (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0)))]
   "TARGET_64BIT"
   "lea{l}\t{%a1, %k0|%k0, %a1}"
   [(set_attr "type" "lea")
 
 (define_insn "*lea_2_rex64"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (match_operand:DI 1 "address_operand" "p"))]
+       (match_operand:DI 1 "no_seg_address_operand" "p"))]
   "TARGET_64BIT"
   "lea{q}\t{%a1, %0|%0, %a1}"
   [(set_attr "type" "lea")
              (clobber (match_dup 5))
              (clobber (reg:CC 17))])]
   "")
+
+;; Load and add the thread base pointer from %gs:0.
+
+(define_insn "*load_tp_si"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(const_int 0)] UNSPEC_TP))]
+  "!TARGET_64BIT"
+  "mov{l}\t{%%gs:0, %0|%0, DWORD PTR %%gs:0}"
+  [(set_attr "type" "imov")
+   (set_attr "modrm" "0")
+   (set_attr "length" "7")
+   (set_attr "memory" "load")
+   (set_attr "imm_disp" "false")])
+
+(define_insn "*add_tp_si"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (unspec:SI [(const_int 0)] UNSPEC_TP)
+                (match_operand:SI 1 "register_operand" "0")))
+   (clobber (reg:CC 17))]
+  "!TARGET_64BIT"
+  "add{l}\t{%%gs:0, %0|%0, DWORD PTR %%gs:0}"
+  [(set_attr "type" "alu")
+   (set_attr "modrm" "0")
+   (set_attr "length" "7")
+   (set_attr "memory" "load")
+   (set_attr "imm_disp" "false")])
+
+(define_insn "*load_tp_di"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI [(const_int 0)] UNSPEC_TP))]
+  "TARGET_64BIT"
+  "mov{l}\t{%%fs:0, %0|%0, QWORD PTR %%fs:0}"
+  [(set_attr "type" "imov")
+   (set_attr "modrm" "0")
+   (set_attr "length" "7")
+   (set_attr "memory" "load")
+   (set_attr "imm_disp" "false")])
+
+(define_insn "*add_tp_di"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (plus:DI (unspec:DI [(const_int 0)] UNSPEC_TP)
+                (match_operand:DI 1 "register_operand" "0")))
+   (clobber (reg:CC 17))]
+  "TARGET_64BIT"
+  "add{q}\t{%%fs:0, %0|%0, QWORD PTR %%fs:0}"
+  [(set_attr "type" "alu")
+   (set_attr "modrm" "0")
+   (set_attr "length" "7")
+   (set_attr "memory" "load")
+   (set_attr "imm_disp" "false")])
 \f
 ;; These patterns match the binary 387 instructions for addM3, subM3,
 ;; mulM3 and divM3.  There are three patterns for each of DFmode and
index 3041368..8f0a22c 100644 (file)
@@ -40,6 +40,10 @@ Boston, MA 02111-1307, USA.  */
 #undef DEFAULT_PCC_STRUCT_RETURN
 #define DEFAULT_PCC_STRUCT_RETURN 1
 
+/* We arrange for the whole %gs segment to map the tls area.  */
+#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT
+#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS
+
 #undef ASM_COMMENT_START
 #define ASM_COMMENT_START "#"
 
index 341ef32..ec398de 100644 (file)
@@ -47,6 +47,10 @@ Boston, MA 02111-1307, USA.  */
 #undef DEFAULT_PCC_STRUCT_RETURN
 #define DEFAULT_PCC_STRUCT_RETURN 1
 
+/* We arrange for the whole %fs segment to map the tls area.  */
+#undef TARGET_TLS_DIRECT_SEG_REFS_DEFAULT
+#define TARGET_TLS_DIRECT_SEG_REFS_DEFAULT MASK_TLS_DIRECT_SEG_REFS
+
 /* Provide a LINK_SPEC.  Here we provide support for the special GCC
    options -static and -shared, which allow us to link things in one
    of these three modes by applying the appropriate combinations of
index 66ef987..b87d310 100644 (file)
@@ -490,7 +490,7 @@ in the following sections.
 -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
 -m96bit-long-double  -mregparm=@var{num}  -momit-leaf-frame-pointer @gol
--mno-red-zone @gol
+-mno-red-zone -mno-tls-direct-seg-refs @gol
 -mcmodel=@var{code-model} @gol
 -m32  -m64}
 
@@ -8401,6 +8401,17 @@ avoids the instructions to save, set up and restore frame pointers and
 makes an extra register available in leaf functions.  The option
 @option{-fomit-frame-pointer} removes the frame pointer for all functions
 which might make debugging harder.
+
+@item -mtls-direct-seg-refs
+@itemx -mno-tls-direct-seg-refs
+@opindex mtls-direct-seg-refs
+Controls whether TLS variables may be accessed with offsets from the
+TLS segment register (@code{%gs} for 32-bit, @code{%fs} for 64-bit),
+or whether the thread base pointer must be added.  Whether or not this
+is legal depends on the operating system, and whether it maps the
+segment to cover the entire TLS area.
+
+For systems that use GNU libc, the default is on.
 @end table
 
 These @samp{-m} switches are supported in addition to the above