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")])