[PATCH]: Sparc GOTDATA support.

David Miller davem@davemloft.net
Tue Feb 16 23:11:00 GMT 2010


This patch adds support for emitting GOTDATA relocations
which allow PIC sequences to be optimized by the linker.

This is similar to x86's %GOTOFF, except that the linker
instead of the compiler optimizes the sequence, and
therefore more cases can apply.

And, to be honest, like %GOTOFF this simplification is all but a
necessity in order to support STT_GNU_IFUNC correctly.  Without this
kind of relocation transformation you need to have ugly hacks like the
ifunc-sel.h override PowerPC is using at the moment in the GLIBC
sources.  But I have confidence Alan Modra will at some point
implement powerpc facilities that make such things unnecessary. :-)

Here is an example 32-bit GOTDATA code sequence:

	.data
local_sym:	.word 0

	.text
local_addr:
	save	%sp, -128, %sp
	sethi	%hi(_GLOBAL_OFFSET_TABLE_-4), %l7
pc:	call	1f
	 or	%l7, %lo(_GLOBAL_OFFSET_TABLE_+4), %l7
	 add	%l7, %o7, %l7
	/* GOTDATA_OP sequence */
	sethi	%gdop_hix22(local_sym), %l1
	or	%l1, %gdop_lox10(local_sym), %l1
	ld	[%l7 + %l1], %i0, %gdop(local_sym)
	ret
	restore

The linker will rewrite the three instructions under the "GOTDATA_OP
sequence" comment into:

	sethi	%hix22(local_sym-_GLOBAL_OFFSET_TABLE_), %l1
	or	%l1, %lox10(local_sym-_GLOBAL_OFFSET_TABLE_), %l1
	add	%l7, %l1,, %i0

and eliminate the GOT slot.

I've checked support for these transformations into the BFD sparc
backend last week, and the Solaris sparc linker and assembler support
these sequences too.

I'd really like to see some Solaris test results with these changes
before I commit them.  Could someone check and report the results on
that platform?  In particular, make sure the configure script properly
detects support for the relocations.

Thanks!

gcc/

2010-02-16  David S. Miller  <davem@davemloft.net>

	* configure.ac: Test if linker and assembler support GOTDATA_OP
	relocations.
	* configure: Rebuild.
	* config.in: Likewise.
	* config/sparc/sparc.md (UNSPEC_MOVE_GOTDATA): New.
	(movsi_lo_sum_pic): Use %gdop_*() relocs if available.
	(movsi_high_pic): Likewise.
	(movdi_lo_sum_pic): Likewise.
	(movdi_high_pic): Likewise.
	(movsi_pic_gotdata_op): New pattern.
	(movdi_pic_gotdata_op): Likewise.
	* config/sparc/sparc.c (legitimize_pic_address): If flag_pic is 2,
	emit gen_mov{si,di}_pic_gotdata_op for the GOT slot load.
	
diff --git a/gcc/config.in b/gcc/config.in
index a3744f9..98dffa7 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -417,6 +417,12 @@
 #endif
 
 
+/* Define if your assembler and linker support GOTDATA_OP relocs. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_SPARC_GOTDATA_OP
+#endif
+
+
 /* Define if your assembler and linker support unaligned PC relative relocs.
    */
 #ifndef USED_FOR_TARGET
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index f48536f..1b626ec 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -3373,6 +3373,8 @@ legitimize_tls_address (rtx addr)
 static rtx
 legitimize_pic_address (rtx orig, rtx reg)
 {
+  bool gotdata_op = false;
+
   if (GET_CODE (orig) == SYMBOL_REF
       /* See the comment in sparc_expand_move.  */
       || (TARGET_VXWORKS_RTP && GET_CODE (orig) == LABEL_REF))
@@ -3409,15 +3411,28 @@ legitimize_pic_address (rtx orig, rtx reg)
 	      emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
 	    }
 	  address = temp_reg;
+	  gotdata_op = true;
 	}
       else
 	address = orig;
 
-      pic_ref = gen_const_mem (Pmode,
-			       gen_rtx_PLUS (Pmode,
-					     pic_offset_table_rtx, address));
       crtl->uses_pic_offset_table = 1;
-      insn = emit_move_insn (reg, pic_ref);
+      if (gotdata_op)
+	{
+	  if (TARGET_ARCH64)
+	    insn = emit_insn (gen_movdi_pic_gotdata_op (reg, pic_offset_table_rtx,
+							address, orig));
+	  else
+	    insn = emit_insn (gen_movsi_pic_gotdata_op (reg, pic_offset_table_rtx,
+							address, orig));
+	}
+      else
+	{
+	  pic_ref = gen_const_mem (Pmode,
+				   gen_rtx_PLUS (Pmode,
+						 pic_offset_table_rtx, address));
+	  insn = emit_move_insn (reg, pic_ref);
+	}
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
 	 by loop.  */
       set_unique_reg_note (insn, REG_EQUAL, orig);
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index caf8443..586c066 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -38,6 +38,7 @@
    (UNSPEC_EMB_TEXTHI		14)
    (UNSPEC_EMB_TEXTULO		15)
    (UNSPEC_EMB_SETHM		18)
+   (UNSPEC_MOVE_GOTDATA		19)
 
    (UNSPEC_MEMBAR		20)
 
@@ -1224,13 +1225,40 @@
         (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
                    (unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] UNSPEC_MOVE_PIC)))]
   "flag_pic"
-  "or\t%1, %%lo(%a2), %0")
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "xor\t%1, %%gdop_lox10(%a2), %0";
+#else
+  return "or\t%1, %%lo(%a2), %0";
+#endif
+})
 
 (define_insn "movsi_high_pic"
   [(set (match_operand:SI 0 "register_operand" "=r")
         (high:SI (unspec:SI [(match_operand 1 "" "")] UNSPEC_MOVE_PIC)))]
   "flag_pic && check_pic (1)"
-  "sethi\t%%hi(%a1), %0")
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "sethi\t%%gdop_hix22(%a1), %0";
+#else
+  return "sethi\t%%hi(%a1), %0";
+#endif
+})
+
+(define_insn "movsi_pic_gotdata_op"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+	            (match_operand:SI 2 "register_operand" "r")
+		    (match_operand 3 "symbolic_operand" "")] UNSPEC_MOVE_GOTDATA))]
+  "flag_pic && check_pic (1)"
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "ld\t[%1 + %2], %0, %%gdop(%a3)";
+#else
+  return "ld\t[%1 + %2], %0";
+#endif
+}
+  [(set_attr "type" "load")])
 
 (define_expand "movsi_pic_label_ref"
   [(set (match_dup 3) (high:SI
@@ -1430,13 +1458,40 @@
         (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
                    (unspec:DI [(match_operand:DI 2 "immediate_operand" "in")] UNSPEC_MOVE_PIC)))]
   "TARGET_ARCH64 && flag_pic"
-  "or\t%1, %%lo(%a2), %0")
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "xor\t%1, %%gdop_lox10(%a2), %0";
+#else
+  return "or\t%1, %%lo(%a2), %0";
+#endif
+})
 
 (define_insn "movdi_high_pic"
   [(set (match_operand:DI 0 "register_operand" "=r")
         (high:DI (unspec:DI [(match_operand 1 "" "")] UNSPEC_MOVE_PIC)))]
   "TARGET_ARCH64 && flag_pic && check_pic (1)"
-  "sethi\t%%hi(%a1), %0")
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "sethi\t%%gdop_hix22(%a1), %0";
+#else
+  return "sethi\t%%hi(%a1), %0";
+#endif
+})
+
+(define_insn "movdi_pic_gotdata_op"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+        (unspec:DI [(match_operand:DI 1 "register_operand" "r")
+	            (match_operand:DI 2 "register_operand" "r")
+		    (match_operand 3 "symbolic_operand" "")] UNSPEC_MOVE_GOTDATA))]
+  "TARGET_ARCH64 && flag_pic && check_pic (1)"
+{
+#ifdef HAVE_AS_SPARC_GOTDATA_OP
+  return "ldx\t[%1 + %2], %0, %%gdop(%a3)";
+#else
+  return "ldx\t[%1 + %2], %0";
+#endif
+}
+  [(set_attr "type" "load")])
 
 (define_insn "*sethi_di_medlow_embmedany_pic"
   [(set (match_operand:DI 0 "register_operand" "=r")
diff --git a/gcc/configure b/gcc/configure
index 4fc3b10..a40d16d 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -22491,6 +22491,47 @@ $as_echo "#define HAVE_AS_RELAX_OPTION 1" >>confdefs.h
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for GOTDATA_OP relocs" >&5
+$as_echo_n "checking assembler for GOTDATA_OP relocs... " >&6; }
+if test "${gcc_cv_as_sparc_gotdata_op+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_sparc_gotdata_op=no
+  if test x$gcc_cv_as != x; then
+    echo '.text
+foo:
+	nop
+bar:
+	sethi %gdop_hix22(foo), %g1
+	or    %g1, %gdop_lox10(foo), %g1
+	ld    [%l7 + %g1], %g2, %gdop(foo)' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags -K PIC -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	if test x$gcc_cv_ld != x \
+       && $gcc_cv_ld -o conftest conftest.o -G > /dev/null 2>&1; then
+	 gcc_cv_as_sparc_gotdata_op=yes
+       fi
+       rm -f conftest
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_sparc_gotdata_op" >&5
+$as_echo "$gcc_cv_as_sparc_gotdata_op" >&6; }
+if test $gcc_cv_as_sparc_gotdata_op = yes; then
+
+$as_echo "#define HAVE_AS_SPARC_GOTDATA_OP 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for unaligned pcrel relocs" >&5
 $as_echo_n "checking assembler for unaligned pcrel relocs... " >&6; }
 if test "${gcc_cv_as_sparc_ua_pcrel+set}" = set; then :
diff --git a/gcc/configure.ac b/gcc/configure.ac
index b75cc76..807dddb 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -2950,6 +2950,24 @@ case "$target" in
       [AC_DEFINE(HAVE_AS_RELAX_OPTION, 1,
 		[Define if your assembler supports -relax option.])])
 
+    gcc_GAS_CHECK_FEATURE([GOTDATA_OP relocs],
+      gcc_cv_as_sparc_gotdata_op,,
+      [-K PIC],
+[.text
+foo:
+	nop
+bar:
+	sethi %gdop_hix22(foo), %g1
+	or    %g1, %gdop_lox10(foo), %g1
+	ld    [[%l7 + %g1]], %g2, %gdop(foo)],
+      [if test x$gcc_cv_ld != x \
+       && $gcc_cv_ld -o conftest conftest.o -G > /dev/null 2>&1; then
+	 gcc_cv_as_sparc_gotdata_op=yes
+       fi
+       rm -f conftest],
+      [AC_DEFINE(HAVE_AS_SPARC_GOTDATA_OP, 1,
+		[Define if your assembler and linker support GOTDATA_OP relocs.])])
+
     gcc_GAS_CHECK_FEATURE([unaligned pcrel relocs],
       gcc_cv_as_sparc_ua_pcrel,,
       [-K PIC],



More information about the Gcc-patches mailing list