diff mbox

PATCH: Remove *load_tp_x32 from i386.md

Message ID 20120327215402.GA12115@intel.com
State New
Headers show

Commit Message

H.J. Lu March 27, 2012, 9:54 p.m. UTC
Hi Richard,

Segment registers %fs and %gs are special in 64bit mode.  For a memory
operand "%fs:address", its effective address is the base address of %fs +
address.  The base address of %fs are hidden and "mov %fs, %ax" will only
access the visible part of %fs, which is the 16bit segment selector.

In 64bit mode, UNSPEC_TP refers to the base address of %fs.  To access the
base address of %fs, we can use system call:

	int arch_prctl(int code, unsigned long addr);
	int arch_prctl(int code, unsigned long *addr);

       ARCH_SET_FS
              Set the 64-bit base for the FS register to addr.

       ARCH_GET_FS
              Return the 64-bit base value for the FS register of the
	      current thread in the unsigned long pointed to by addr.

we must use the system call to update the base address of %fs,  To read
the base address of %fs, OS arranges that the base address of %fs points
to a struct:

typedef struct
{
  void *tcb;		/* Pointer to the TCB.  Not necessarily the
			   thread descriptor used by libpthread.  */
  ...
}

and sets up "tcb" == the base address of %fs so that the address of "%fs:0"
is the address of the tcb field.  For x32, the base address of %fs is
between 0 and 0xffffffff.  We can use

"mov{l}\t{%%fs:0, %k0|%k0, DWORD PTR fs:0}"

to move the base address of %fs into %r32 and %r64 directly.  In case
of %r32, we are loading "tcb", which is a 32bit memory.  For %r64, we
are loading "tcb" and zero-extend it to 64bit.  This patch is tested on
Linux/x32 with GCC and glibc with both -maddress-mode=long and
-maddress-mode=short.  OK for trunk?

Thanks.


H.J.
---
2012-03-27  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/i386.c (legitimize_pic_address): Load UNSPEC_TP
	into tp_mode register directly.

	* config/i386/i386.md (*load_tp_x32): Removed.
	(*load_tp_x32_zext): Likewise.
	(*load_tp_x32_<mode>): New.
diff mbox

Patch

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index a21f2da..14c4056 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -12491,15 +12485,7 @@  legitimize_pic_address (rtx orig, rtx reg)
 static rtx
 get_thread_pointer (enum machine_mode tp_mode, bool to_reg)
 {
-  rtx tp = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
-
-  if (GET_MODE (tp) != tp_mode)
-    {
-      gcc_assert (GET_MODE (tp) == SImode);
-      gcc_assert (tp_mode == DImode);
-
-      tp = gen_rtx_ZERO_EXTEND (tp_mode, tp);
-    }
+  rtx tp = gen_rtx_UNSPEC (tp_mode, gen_rtvec (1, const0_rtx), UNSPEC_TP);
 
   if (to_reg)
     tp = copy_to_mode_reg (tp_mode, tp);
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 2d20a52..ac6124e 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -12748,20 +12748,9 @@ 
 (define_mode_attr tp_seg [(SI "gs") (DI "fs")])
 
 ;; Load and add the thread base pointer from %<tp_seg>:0.
-(define_insn "*load_tp_x32"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-	(unspec:SI [(const_int 0)] UNSPEC_TP))]
-  "TARGET_X32"
-  "mov{l}\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 "*load_tp_x32_zext"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-	(zero_extend:DI (unspec:SI [(const_int 0)] UNSPEC_TP)))]
+(define_insn "*load_tp_x32_<mode>"
+  [(set (match_operand:SWI48x 0 "register_operand" "=r")
+	(unspec:SWI48x [(const_int 0)] UNSPEC_TP))]
   "TARGET_X32"
   "mov{l}\t{%%fs:0, %k0|%k0, DWORD PTR fs:0}"
   [(set_attr "type" "imov")