Hi, In x32, thread pointer is 32bit and choice of segment register for the thread base ptr load should be based on TARGET_64BIT. This patch implements it. OK for trunk?
Thanks. H.J. --- 2011-07-27 H.J. Lu <hongjiu...@intel.com> PR target/47715 * config/i386/i386.c (get_thread_pointer): Use ptr_mode instead of Pmode with UNSPEC_TP. * config/i386/i386.md (tp_seg): Removed. (*load_tp_<mode>): Replace :P with :PTR. (*add_tp_<mode>): Likewise. (*load_tp_x32): New. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 8723dc5..d32d64d 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -12120,7 +12120,9 @@ get_thread_pointer (bool to_reg) { rtx tp, reg, insn; - tp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx), UNSPEC_TP); + tp = gen_rtx_UNSPEC (ptr_mode, gen_rtvec (1, const0_rtx), UNSPEC_TP); + if (ptr_mode != Pmode) + tp = convert_to_mode (Pmode, tp, 1); if (!to_reg) return tp; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index e91a299..c772f94 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -951,9 +951,14 @@ ;; This mode iterator allows :P to be used for patterns that operate on ;; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) + +;; This mode iterator allows :PTR to be used for patterns that operate on +;; ptr_mode sized quantities. +(define_mode_iterator PTR + [(SI "ptr_mode == SImode") (DI "ptr_mode == DImode")]) ;; Pointer modes in 64bit. (define_mode_iterator PTR64 [(SI "TARGET_X32") DI]) ;; Scheduling descriptions output_asm_insn ("lea{q}\t{%a1@tlsgd(%%rip), %%rdi|rdi, %a1@tlsgd[rip]}", operands); fputs (ASM_SHORT "0x6666\n", asm_out_file); (define_insn "*tls_local_dynamic_base_32_gnu" @@ -12438,15 +12451,28 @@ (clobber (match_dup 5)) (clobber (reg:CC FLAGS_REG))])]) -;; Segment register for the thread base ptr load -(define_mode_attr tp_seg [(SI "gs") (DI "fs")]) - -;; Load and add the thread base pointer from %<tp_seg>:0. +;; Load and add the thread base pointer from %gs:0 or %fs:0. (define_insn "*load_tp_<mode>" - [(set (match_operand:P 0 "register_operand" "=r") - (unspec:P [(const_int 0)] UNSPEC_TP))] + [(set (match_operand:PTR 0 "register_operand" "=r") + (unspec:PTR [(const_int 0)] UNSPEC_TP))] "" - "mov{<imodesuffix>}\t{%%<tp_seg>:0, %0|%0, <iptrsize> PTR <tp_seg>:0}" +{ + if (TARGET_64BIT) + return "mov{<imodesuffix>}\t{%%fs:0, %0|%0, <iptrsize> PTR fs:0}"; + else + return "mov{<imodesuffix>}\t{%%gs:0, %0|%0, <iptrsize> 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 "*load_tp_x32" + [(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") @@ -12454,12 +12480,17 @@ (set_attr "imm_disp" "false")]) (define_insn "*add_tp_<mode>" - [(set (match_operand:P 0 "register_operand" "=r") - (plus:P (unspec:P [(const_int 0)] UNSPEC_TP) - (match_operand:P 1 "register_operand" "0"))) + [(set (match_operand:PTR 0 "register_operand" "=r") + (plus:PTR (unspec:PTR [(const_int 0)] UNSPEC_TP) + (match_operand:PTR 1 "register_operand" "0"))) (clobber (reg:CC FLAGS_REG))] "" - "add{<imodesuffix>}\t{%%<tp_seg>:0, %0|%0, <iptrsize> PTR <tp_seg>:0}" +{ + if (TARGET_64BIT) + return "add{<imodesuffix>}\t{%%fs:0, %0|%0, <iptrsize> PTR fs:0}"; + else + return "add{<imodesuffix>}\t{%%gs:0, %0|%0, <iptrsize> PTR gs:0}"; +} [(set_attr "type" "alu") (set_attr "modrm" "0") (set_attr "length" "7")