This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

direct segment addressing for x86 tls


This is something I worked on back in February, which Jakub
polished and added to the 3.2-rhl8 branch, but I completely
forgot about putting onto mainline.  I've updated it a bit,
and (hopefully) fixed some amd64 issues.

The effect is to make TLS code a bit smaller on x86 platforms.

	static __thread int le;
	extern __thread int ie;
	int foo() { return le + ie; }

BEFORE

        movl    %gs:0, %edx
        movl    ie@INDNTPOFF, %eax
        movl    (%edx,%eax), %eax
        addl    le@NTPOFF(%edx), %eax
	// 21 bytes

AFTER

        movl    ie@INDNTPOFF, %eax
        movl    %gs:(%eax), %eax
        addl    %gs:le@NTPOFF, %eax
	// 15 bytes



r~



        * 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.

Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.569
diff -c -p -d -r1.569 i386.c
*** config/i386/i386.c	4 Jun 2003 16:44:50 -0000	1.569
--- config/i386/i386.c	5 Jun 2003 00:06:55 -0000
*************** static rtx maybe_get_pool_constant PARAM
*** 793,799 ****
  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 void get_pc_thunk_name PARAMS ((char [32], unsigned int));
  static rtx gen_push PARAMS ((rtx));
  static int memory_address_length PARAMS ((rtx addr));
--- 793,800 ----
  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 ((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));
*************** struct ix86_address
*** 835,840 ****
--- 836,842 ----
  {
    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 *));
*************** vector_move_operand (op, mode)
*** 3863,3868 ****
--- 3865,3889 ----
    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
*************** ix86_output_function_epilogue (file, siz
*** 5403,5410 ****
  /* 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.
!    */
  
  static int
  ix86_decompose_address (addr, out)
--- 5424,5430 ----
  /* 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.  */
  
  static int
  ix86_decompose_address (addr, out)
*************** ix86_decompose_address (addr, out)
*** 5417,5463 ****
    HOST_WIDE_INT scale = 1;
    rtx scale_rtx = NULL_RTX;
    int retval = 1;
  
    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);
  
!       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)
  	{
! 	  index = XEXP (XEXP (op0, 0), 0);	/* index*scale + base + disp */
! 	  scale_rtx = XEXP (XEXP (op0, 0), 1);
! 	  base = XEXP (op0, 1);
! 	  disp = op1;
  	}
!       else if (code0 == PLUS)
  	{
! 	  index = XEXP (op0, 0);	/* index + base + disp */
! 	  base = XEXP (op0, 1);
! 	  disp = op1;
  	}
-       else
- 	return 0;
      }
    else if (GET_CODE (addr) == MULT)
      {
--- 5437,5508 ----
    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 addends[4], op;
!       int n = 0, i;
  
!       op = addr;
!       do
  	{
! 	  if (n >= 4)
! 	    return 0;
! 	  addends[n++] = XEXP (op, 1);
! 	  op = XEXP (op, 0);
  	}
!       while (GET_CODE (op) == PLUS);
!       if (n >= 4)
! 	return 0;
!       addends[n] = op;
! 
!       for (i = n; i >= 0; --i)
  	{
! 	  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 if (GET_CODE (addr) == MULT)
      {
*************** ix86_decompose_address (addr, out)
*** 5490,5499 ****
        scale = INTVAL (scale_rtx);
      }
  
!   /* 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))
      {
        rtx tmp = base;
        base = index;
--- 5535,5545 ----
        scale = INTVAL (scale_rtx);
      }
  
!   /* 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
! 	  || (REG_P (index) && REGNO (index) == STACK_POINTER_REGNUM)))
      {
        rtx tmp = base;
        base = index;
*************** ix86_decompose_address (addr, out)
*** 5526,5531 ****
--- 5572,5578 ----
    out->index = index;
    out->disp = disp;
    out->scale = scale;
+   out->seg = seg;
  
    return retval;
  }
*************** ix86_address_cost (x)
*** 5553,5558 ****
--- 5600,5607 ----
    /* 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
*************** legitimate_address_p (mode, addr, strict
*** 5871,5883 ****
        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";
--- 5920,5925 ----
*************** legitimize_pic_address (orig, reg)
*** 6267,6286 ****
    return new;
  }
  
! /* 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_MEM (Pmode, tp);
!   RTX_UNCHANGING_P (tp) = 1;
!   set_mem_alias_set (tp, ix86_GOT_alias_set ());
!   tp = force_reg (Pmode, tp);
  
!   return tp;
  }
  
  /* Try machine-dependent ways of modifying an illegitimate address
--- 6309,6459 ----
    return new;
  }
  
! /* Load the thread pointer.  If TO_REG is true, force it into a register.  */
  
  static rtx
! get_thread_pointer (to_reg)
!      int to_reg;
  {
!   rtx tp, reg, insn;
  
    tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
!   if (!to_reg)
!     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
*************** legitimize_address (x, oldx, mode)
*** 6322,6441 ****
  
    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;
!     }
  
    if (flag_pic && SYMBOLIC_CONST (x))
      return legitimize_pic_address (x, 0);
--- 6495,6501 ----
  
    log = tls_symbolic_operand (x, mode);
    if (log)
!     return legitimize_tls_address (x, log, false);
  
    if (flag_pic && SYMBOLIC_CONST (x))
      return legitimize_pic_address (x, 0);
*************** print_operand (file, x, code)
*** 7418,7425 ****
        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)
      {
        char dstr[30];
  
--- 7478,7485 ----
        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)
      {
        char dstr[30];
  
*************** print_operand_address (file, addr)
*** 7474,7492 ****
    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 ();
  
--- 7534,7539 ----
*************** print_operand_address (file, addr)
*** 7495,7529 ****
    disp = parts.disp;
    scale = parts.scale;
  
    if (!base && !index)
      {
        /* Displacement only requires special attention.  */
  
        if (GET_CODE (disp) == CONST_INT)
  	{
! 	  if (ASSEMBLER_DIALECT == ASM_INTEL)
  	    {
  	      if (USER_LABEL_PREFIX[0] == 0)
  		putc ('%', file);
  	      fputs ("ds:", file);
  	    }
! 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
  	}
        else if (flag_pic)
! 	output_pic_addr_const (file, addr, 0);
        else
! 	output_addr_const (file, addr);
  
        /* 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)))
  	fputs ("(%rip)", file);
      }
    else
--- 7542,7590 ----
    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 && parts.seg == SEG_DEFAULT)
  	    {
  	      if (USER_LABEL_PREFIX[0] == 0)
  		putc ('%', file);
  	      fputs ("ds:", file);
  	    }
! 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (disp));
  	}
        else if (flag_pic)
! 	output_pic_addr_const (file, disp, 0);
        else
! 	output_addr_const (file, disp);
  
        /* Use one byte shorter RIP relative addressing for 64bit mode.  */
        if (TARGET_64BIT
! 	  && ((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
*************** ix86_expand_move (mode, operands)
*** 8220,8241 ****
       rtx operands[];
  {
    int strict = (reload_in_progress || reload_completed);
!   rtx insn, op0, op1, tmp;
  
    op0 = operands[0];
    op1 = 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 TARGET_MACHO
        if (MACHOPIC_PURE)
--- 8281,8302 ----
       rtx operands[];
  {
    int strict = (reload_in_progress || reload_completed);
!   rtx op0, op1;
!   enum tls_model model;
  
    op0 = operands[0];
    op1 = operands[1];
  
!   model = tls_symbolic_operand (op1, Pmode);
!   if (model)
      {
!       op1 = legitimize_tls_address (op1, model, true);
!       op1 = force_operand (op1, op0);
!       if (op1 == op0)
! 	return;
      }
! 
!   if (flag_pic && mode == Pmode && symbolic_operand (op1, Pmode))
      {
  #if TARGET_MACHO
        if (MACHOPIC_PURE)
*************** ix86_expand_move (mode, operands)
*** 8248,8265 ****
  	  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 */
        if (GET_CODE (op0) == MEM)
  	op1 = force_reg (Pmode, op1);
        else
--- 8309,8319 ----
  	  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)
! 	return;
! #else
        if (GET_CODE (op0) == MEM)
  	op1 = force_reg (Pmode, op1);
        else
*************** ix86_expand_move (mode, operands)
*** 8272,8277 ****
--- 8326,8332 ----
  	    return;
  	  op1 = temp;
  	}
+ #endif /* TARGET_MACHO */
      }
    else
      {
*************** ix86_expand_move (mode, operands)
*** 8316,8324 ****
  	}
      }
  
!   insn = gen_rtx_SET (VOIDmode, op0, op1);
! 
!   emit_insn (insn);
  }
  
  void
--- 8371,8377 ----
  	}
      }
  
!   emit_insn (gen_rtx_SET (VOIDmode, op0, op1));
  }
  
  void
*************** ix86_rtx_costs (x, code, outer_code, tot
*** 15092,15097 ****
--- 15145,15155 ----
      case SQRT:
        if (FLOAT_MODE_P (mode))
  	*total = COSTS_N_INSNS (ix86_cost->fsqrt);
+       return false;
+ 
+     case UNSPEC:
+       if (XINT (x, 1) == UNSPEC_TP)
+ 	*total = 0;
        return false;
  
      default:
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.338
diff -c -p -d -r1.338 i386.h
*** config/i386/i386.h	4 Jun 2003 17:50:42 -0000	1.338
--- config/i386/i386.h	5 Jun 2003 00:06:56 -0000
*************** extern int target_flags;
*** 122,127 ****
--- 122,128 ----
  #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	*/
  
*************** extern int target_flags;
*** 201,206 ****
--- 202,210 ----
  #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)
*************** extern int x86_prefetch_sse;
*** 405,416 ****
      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") },			      \
    SUBTARGET_SWITCHES							      \
!   { "", TARGET_DEFAULT | TARGET_64BIT_DEFAULT | TARGET_SUBTARGET_DEFAULT, 0 }}
  
  #ifndef TARGET_64BIT_DEFAULT
  #define TARGET_64BIT_DEFAULT 0
  #endif
  
  /* Once GDB has been enhanced to deal with functions without frame
     pointers, we can change this to allow for elimination of
--- 409,429 ----
      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	      \
!     | 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
*************** do {						\
*** 3034,3039 ****
--- 3047,3054 ----
    {"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: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.464
diff -c -p -d -r1.464 i386.md
*** config/i386/i386.md	4 Jun 2003 20:06:34 -0000	1.464
--- config/i386/i386.md	5 Jun 2003 00:06:58 -0000
***************
*** 5312,5318 ****
  
  (define_insn "*lea_1"
    [(set (match_operand:SI 0 "register_operand" "=r")
! 	(match_operand:SI 1 "address_operand" "p"))]
    "!TARGET_64BIT"
    "lea{l}\t{%a1, %0|%0, %a1}"
    [(set_attr "type" "lea")
--- 5312,5318 ----
  
  (define_insn "*lea_1"
    [(set (match_operand:SI 0 "register_operand" "=r")
! 	(match_operand:SI 1 "no_seg_address_operand" "p"))]
    "!TARGET_64BIT"
    "lea{l}\t{%a1, %0|%0, %a1}"
    [(set_attr "type" "lea")
***************
*** 5320,5326 ****
  
  (define_insn "*lea_1_rex64"
    [(set (match_operand:SI 0 "register_operand" "=r")
! 	(subreg:SI (match_operand:DI 1 "address_operand" "p") 0))]
    "TARGET_64BIT"
    "lea{l}\t{%a1, %0|%0, %a1}"
    [(set_attr "type" "lea")
--- 5320,5326 ----
  
  (define_insn "*lea_1_rex64"
    [(set (match_operand:SI 0 "register_operand" "=r")
! 	(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")
***************
*** 5328,5334 ****
  
  (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)))]
    "TARGET_64BIT"
    "lea{l}\t{%a1, %k0|%k0, %a1}"
    [(set_attr "type" "lea")
--- 5328,5335 ----
  
  (define_insn "*lea_1_zext"
    [(set (match_operand:DI 0 "register_operand" "=r")
! 	(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")
***************
*** 5336,5342 ****
  
  (define_insn "*lea_2_rex64"
    [(set (match_operand:DI 0 "register_operand" "=r")
! 	(match_operand:DI 1 "address_operand" "p"))]
    "TARGET_64BIT"
    "lea{q}\t{%a1, %0|%0, %a1}"
    [(set_attr "type" "lea")
--- 5337,5343 ----
  
  (define_insn "*lea_2_rex64"
    [(set (match_operand:DI 0 "register_operand" "=r")
! 	(match_operand:DI 1 "no_seg_address_operand" "p"))]
    "TARGET_64BIT"
    "lea{q}\t{%a1, %0|%0, %a1}"
    [(set_attr "type" "lea")
***************
*** 14636,14641 ****
--- 14637,14692 ----
  	      (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")])
  
  ;; These patterns match the binary 387 instructions for addM3, subM3,
  ;; mulM3 and divM3.  There are three patterns for each of DFmode and
Index: config/i386/linux.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/linux.h,v
retrieving revision 1.45
diff -c -p -d -r1.45 linux.h
*** config/i386/linux.h	4 Jun 2003 16:44:50 -0000	1.45
--- config/i386/linux.h	5 Jun 2003 00:06:58 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 40,45 ****
--- 40,49 ----
  #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: config/i386/linux64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/linux64.h,v
retrieving revision 1.22
diff -c -p -d -r1.22 linux64.h
*** config/i386/linux64.h	4 Jun 2003 16:44:50 -0000	1.22
--- config/i386/linux64.h	5 Jun 2003 00:06:58 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 47,52 ****
--- 47,56 ----
  #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: doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.288
diff -c -p -d -r1.288 invoke.texi
*** doc/invoke.texi	4 Jun 2003 20:59:56 -0000	1.288
--- doc/invoke.texi	5 Jun 2003 00:21:03 -0000
*************** in the following sections.
*** 490,496 ****
  -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
  -mcmodel=@var{code-model} @gol
  -m32  -m64}
  
--- 490,496 ----
  -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 -mno-tls-direct-seg-refs @gol
  -mcmodel=@var{code-model} @gol
  -m32  -m64}
  
*************** avoids the instructions to save, set up 
*** 8401,8406 ****
--- 8401,8417 ----
  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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]