Sophie

Sophie

distrib > Mageia > 5 > i586 > by-pkgid > 82bbe2f6a96ddca05c0f6c96b0a9d5ce > files > 53

gcc3.3-3.3.6-11.mga5.src.rpm

2003-02-24  Richard Henderson  <rth@redhat.com>

	* config/i386/i386.c (struct ix86_address): Add seg.
	(no_seg_address_operand): New function.
	(ix86_decompose_address): Support segment overrides.
	(ix86_address_cost): Take segment overrides into account.
	(legitimate_address_p): Remove UNSPEC_TP special casing.
	(get_thread_pointer): Add to_reg argument.
	(legitimize_address): Move TLS emit code...
	(legitimize_tls_address): ...here.  New function.
	(print_operand_address): Handle segment overrides.
	(ix86_expand_move): Use legitimize_tls_address.
	* config/i386/i386.h (MASK_SVR3_SHLIB, TARGET_SVR3_SHLIB): Remove.
	(MASK_TLS_DIRECT_SEG_REFS, TARGET_TLS_DIRECT_SEG_REFS): Define.
	(TARGET_SWITCHES): Remove -msvr3-shlib, add
	TARGET_TLS_DIRECT_SEG_REFS_DEFAULT to default.
	(TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define to 0 if not defined.
	(RTX_COSTS): Handle segment overrides.
	(PREDICATE_CODES): Add no_seg_address_operand.
	* config/i386/i386.md (UNSPEC_TP_MEM): Define.
	(load_tp_si, load_tp_di, add_tp_si, add_tp_di): New insns.
	* config/i386/linux.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define.
	* config/i386/linux64.h (TARGET_TLS_DIRECT_SEG_REFS_DEFAULT): Define.

--- gcc-3.3.2/gcc/config/i386/i386.c.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/config/i386/i386.c	2003-12-15 15:56:22.000000000 +0100
@@ -798,7 +798,8 @@ static rtx maybe_get_pool_constant PARAM
 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));
@@ -839,6 +840,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 *));
@@ -3845,6 +3847,25 @@ no_seg_address_operand (register rtx op,
   return address_operand (op, mode);
 }
 
+/* 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
@@ -5455,8 +5476,7 @@ ix86_output_function_epilogue (file, siz
 /* 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)
@@ -5469,47 +5489,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 = 0; i <= n; ++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)
     {
@@ -5531,6 +5576,13 @@ ix86_decompose_address (addr, out)
       scale = 1 << scale;
       retval = -1;
     }
+  else if (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_TP_MEM)
+    {
+      if (seg != SEG_DEFAULT)
+	return 0;
+      seg = TARGET_64BIT ? SEG_FS : SEG_GS;
+      disp = const0_rtx;
+    }
   else
     disp = addr;			/* displacement */
 
@@ -5578,6 +5630,7 @@ ix86_decompose_address (addr, out)
   out->index = index;
   out->disp = disp;
   out->scale = scale;
+  out->seg = seg;
 
   return retval;
 }
@@ -5605,6 +5658,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
@@ -5945,13 +6000,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";
@@ -6420,20 +6468,151 @@ ix86_strip_name_encoding (str)
   return str;
 }
 
-/* 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
@@ -6475,120 +6654,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);
@@ -7571,8 +7637,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];
 
@@ -7627,19 +7693,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 ();
 
@@ -7648,35 +7701,53 @@ print_operand_address (file, addr)
   disp = parts.disp;
   scale = parts.scale;
 
+  switch (parts.seg)
+    {
+    case SEG_DEFAULT:
+      break;
+    case SEG_FS:
+      if (USER_LABEL_PREFIX[0] == 0)
+	putc ('%', file);
+      fputs ("fs:", file);
+      break;
+    case SEG_GS:
+      if (USER_LABEL_PREFIX[0] == 0)
+	putc ('%', file);
+      fputs ("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
@@ -8390,22 +8461,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)
@@ -8421,14 +8492,14 @@ ix86_expand_move (mode, operands)
       else
 	{
 	  if (MACHOPIC_INDIRECT)
-	    op1 = machopic_indirect_data_reference (op1, 0);
+	op1 = machopic_indirect_data_reference (op1, 0);
 	}
       if (op0 != op1)
 	{
 	  insn = gen_rtx_SET (VOIDmode, op0, op1);
 	  emit_insn (insn);
 	}
-      return;
+	return;
 #endif /* TARGET_MACHO */
       if (GET_CODE (op0) == MEM)
 	op1 = force_reg (Pmode, op1);
@@ -8486,9 +8557,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
--- gcc-3.3.2/gcc/config/i386/i386.h.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/config/i386/i386.h	2003-12-15 15:56:22.000000000 +0100
@@ -203,6 +203,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_cpu == PROCESSOR_I386)
 #define TARGET_486 (ix86_cpu == PROCESSOR_I486)
 #define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM)
@@ -402,12 +405,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
@@ -2888,6 +2900,10 @@ do {							\
       TOPLEVEL_COSTS_N_INSNS (ix86_cost->fsqrt);			\
     break;								\
 									\
+  case UNSPEC:								\
+    if (XINT ((X), 1) == UNSPEC_TP)					\
+      return 0;								\
+									\
   egress_rtx_costs:							\
     break;
 
--- gcc-3.3.2/gcc/config/i386/i386.md.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/config/i386/i386.md	2003-12-15 15:56:22.000000000 +0100
@@ -75,6 +75,7 @@
    (UNSPEC_TP			15)
    (UNSPEC_TLS_GD		16)
    (UNSPEC_TLS_LD_BASE		17)
+   (UNSPEC_TP_MEM		18)
 
    ; Other random patterns
    (UNSPEC_SCAS			20)
@@ -14636,6 +14637,56 @@
 	      (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" "=*a,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" "6,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{q}\t{%%fs:0, %0|%0, DWORD 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_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 "*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, DWORD PTR %%fs:0}"
+  [(set_attr "type" "alu")
+   (set_attr "modrm" "0")
+   (set_attr "length" "7")
+   (set_attr "memory" "load")
+   (set_attr "imm_disp" "false")])
 
 ;; These patterns match the binary 387 instructions for addM3, subM3,
 ;; mulM3 and divM3.  There are three patterns for each of DFmode and
--- gcc-3.3.2/gcc/config/i386/linux.h.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/config/i386/linux.h	2003-12-15 15:56:22.000000000 +0100
@@ -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 "#"
 
--- gcc-3.3.2/gcc/config/i386/linux64.h.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/config/i386/linux64.h	2003-12-15 15:56:22.000000000 +0100
@@ -53,6 +53,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
--- gcc-3.3.2/gcc/doc/invoke.texi.tls-direct-segment-addressing	2003-12-15 15:56:19.000000000 +0100
+++ gcc-3.3.2/gcc/doc/invoke.texi	2003-12-15 15:56:22.000000000 +0100
@@ -477,7 +477,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}
 
@@ -8210,6 +8210,17 @@ avoids the instructions to save, set up 
 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