aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hongjiu.lu@intel.com>2012-03-10 18:47:52 +0000
committerH.J. Lu <hjl@gcc.gnu.org>2012-03-10 10:47:52 -0800
commit0925565205292f2d8ad5589805480af6cd8f35c6 (patch)
tree509d003bc07727357da8824fb54ec875c92e9a2f
parent21d1335b2a547a09188c62ca5f3b698920ea1438 (diff)
downloadgcc-0925565205292f2d8ad5589805480af6cd8f35c6.zip
gcc-0925565205292f2d8ad5589805480af6cd8f35c6.tar.gz
gcc-0925565205292f2d8ad5589805480af6cd8f35c6.tar.bz2
Properly generate x32 TLS IE sequence
2012-03-10 H.J. Lu <hongjiu.lu@intel.com> * config/i386/i386.c (ix86_decompose_address): Disallow fs:(reg) if Pmode != word_mode. (legitimize_tls_address): Call gen_tls_initial_exec_x32 if Pmode == SImode for x32. * config/i386/i386.md (UNSPEC_TLS_IE_X32): New. (tls_initial_exec_x32): Likewise. From-SVN: r185179
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/i386/i386.c16
-rw-r--r--gcc/config/i386/i386.md23
3 files changed, 49 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b5e3b36..8e5b4a9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2012-03-10 H.J. Lu <hongjiu.lu@intel.com>
+
+ * config/i386/i386.c (ix86_decompose_address): Disallow fs:(reg)
+ if Pmode != word_mode.
+ (legitimize_tls_address): Call gen_tls_initial_exec_x32 if
+ Pmode == SImode for x32.
+
+ * config/i386/i386.md (UNSPEC_TLS_IE_X32): New.
+ (tls_initial_exec_x32): Likewise.
+
2012-03-10 Chung-Lin Tang <cltang@codesourcery.com>
PR rtl-optimization/52528
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 567a41d..bc144a9 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -11524,6 +11524,11 @@ ix86_decompose_address (rtx addr, struct ix86_address *out)
else
disp = addr; /* displacement */
+ /* Since address override works only on the (reg32) part in fs:(reg32),
+ we can't use it as memory operand. */
+ if (Pmode != word_mode && seg == SEG_FS && (base || index))
+ return 0;
+
if (index)
{
if (REG_P (index))
@@ -12618,6 +12623,17 @@ legitimize_tls_address (rtx x, enum tls_model model, bool for_mov)
emit_insn (gen_tls_initial_exec_64_sun (dest, x));
return dest;
}
+ else if (Pmode == SImode)
+ {
+ /* Always generate
+ movl %fs:0, %reg32
+ addl xgottpoff(%rip), %reg32
+ to support linker IE->LE optimization and avoid
+ fs:(%reg32) as memory operand. */
+ dest = gen_reg_rtx (Pmode);
+ emit_insn (gen_tls_initial_exec_x32 (dest, x));
+ return dest;
+ }
pic = NULL;
type = UNSPEC_GOTNTPOFF;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a4a7d3a..dcbfab4 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -96,6 +96,7 @@
UNSPEC_TLS_LD_BASE
UNSPEC_TLSDESC
UNSPEC_TLS_IE_SUN
+ UNSPEC_TLS_IE_X32
;; Other random patterns
UNSPEC_SCAS
@@ -12777,6 +12778,28 @@
}
[(set_attr "type" "multi")])
+;; When Pmode == SImode, there may be no REX prefix for ADD. Avoid
+;; any instructions between MOV and ADD, which may interfere linker
+;; IE->LE optimization, since the last byte of the previous instruction
+;; before ADD may look like a REX prefix. This also avoids
+;; movl x@gottpoff(%rip), %reg32
+;; movl $fs:(%reg32), %reg32
+;; Since address override works only on the (reg32) part in fs:(reg32),
+;; we can't use it as memory operand.
+(define_insn "tls_initial_exec_x32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI
+ [(match_operand:SI 1 "tls_symbolic_operand" "")]
+ UNSPEC_TLS_IE_X32))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_X32"
+{
+ output_asm_insn
+ ("mov{l}\t{%%fs:0, %0|%0, DWORD PTR fs:0}", operands);
+ return "add{l}\t{%a1@gottpoff(%%rip), %0|%0, %a1@gottpoff[rip]}";
+}
+ [(set_attr "type" "multi")])
+
;; GNU2 TLS patterns can be split.
(define_expand "tls_dynamic_gnu2_32"