http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52848
             Bug #: 52848
           Summary: [x32] *load_tp_x32 in i386.md isn't necessary
    Classification: Unclassified
           Product: gcc
           Version: 4.8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
        AssignedTo: unassig...@gcc.gnu.org
        ReportedBy: hjl.to...@gmail.com
            Target: x32


Segment register %fs is used as thread pointer for x32 in 64bit hardware 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" only
accesses the visible part of %fs, which is the 16bit segment selector.

In x32, UNSPEC_TP refers to the base address of %fs.  To access the
base address of %fs, a system call is provided:

    int arch_prctl(int code, unsigned long long addr);
    int arch_prctl(int code, unsigned long 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 arch_prctl 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.  We can use

;; Load and add the thread base pointer from %<tp_seg>:0.
(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")
   (set_attr "modrm" "0")
   (set_attr "length" "7")
   (set_attr "memory" "load")
   (set_attr "imm_disp" "false")])

instead of

;; 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)))]
  "TARGET_X32"
  "mov{l}\t{%%fs:0, %k0|%k0, 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")])

Reply via email to