diff mbox

PowerPC64 large toc model

Message ID 20100906121133.GL16874@bubble.grove.modra.org
State New
Headers show

Commit Message

Alan Modra Sept. 6, 2010, 12:11 p.m. UTC
This patch reinstates the -mcmodel=medium option for PowerPC64 Linux.
When I removed this option, I stated that I could implement the
optimisation in the linker but that turns out to not be true.  The
problem is that there is no relocation on instructions that load an
address out of the TOC, and you need one to reliably tie together the
whole instruction sequence for the linker.

The patch is not just a simple reversion of my 2010-06-25 patch, so I
guess it needs a review.  toc_relative_ok has been added to work
around the potential shared library problem, and a test for NULL
DECL_SIZE_UNIT added to offsettable_ok_by_alignment.

Bootstrapped powerpc64-linux.  Regression tests still running, C, C++
passed so far.  OK to apply assuming no regressions found?

	* doc/invoke.text: Reinstate mcmodel=medium.
	* config/rs6000/linux64.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Set
	CMODEL_MEDIUM as default.
	* config/rs6000/rs6000.h (enum rs6000_cmodel): Add CMODEL_MEDIUM.
	* config/rs6000/rs6000.c (rs6000_handle_option): Add mcmodel=medium.
	(toc_relative_ok, offsettable_ok_by_alignment): New functions.
	(rs6000_emit_move): Reinstate mcmodel=medium optimization.

Comments

David Edelsohn Sept. 8, 2010, 1:10 p.m. UTC | #1
On Mon, Sep 6, 2010 at 8:11 AM, Alan Modra <amodra@gmail.com> wrote:
> This patch reinstates the -mcmodel=medium option for PowerPC64 Linux.
> When I removed this option, I stated that I could implement the
> optimisation in the linker but that turns out to not be true.  The
> problem is that there is no relocation on instructions that load an
> address out of the TOC, and you need one to reliably tie together the
> whole instruction sequence for the linker.
>
> The patch is not just a simple reversion of my 2010-06-25 patch, so I
> guess it needs a review.  toc_relative_ok has been added to work
> around the potential shared library problem, and a test for NULL
> DECL_SIZE_UNIT added to offsettable_ok_by_alignment.
>
> Bootstrapped powerpc64-linux.  Regression tests still running, C, C++
> passed so far.  OK to apply assuming no regressions found?
>
>        * doc/invoke.text: Reinstate mcmodel=medium.
>        * config/rs6000/linux64.h (SUBSUBTARGET_OVERRIDE_OPTIONS): Set
>        CMODEL_MEDIUM as default.
>        * config/rs6000/rs6000.h (enum rs6000_cmodel): Add CMODEL_MEDIUM.
>        * config/rs6000/rs6000.c (rs6000_handle_option): Add mcmodel=medium.
>        (toc_relative_ok, offsettable_ok_by_alignment): New functions.
>        (rs6000_emit_move): Reinstate mcmodel=medium optimization.

Okay.

Thanks, David
diff mbox

Patch

Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 163887)
+++ gcc/doc/invoke.texi	(working copy)
@@ -15212,6 +15212,11 @@  scheduling parameters set by @option{-mt
 Generate PowerPC64 code for the small model: The TOC is limited to
 64k.
 
+@item -mcmodel=medium
+@opindex mcmodel=medium
+Generate PowerPC64 code for the medium model: The TOC and other static
+data may be up to a total of 4G in size.
+
 @item -mcmodel=large
 @opindex mcmodel=large
 Generate PowerPC64 code for the large model: The TOC may be up to 4G
Index: gcc/config/rs6000/linux64.h
===================================================================
--- gcc/config/rs6000/linux64.h	(revision 163887)
+++ gcc/config/rs6000/linux64.h	(working copy)
@@ -134,7 +134,7 @@  extern enum rs6000_cmodel cmodel;
 	  else							\
 	    {							\
 	      if (!rs6000_explicit_options.cmodel)		\
-		SET_CMODEL (CMODEL_LARGE);			\
+		SET_CMODEL (CMODEL_MEDIUM);			\
 	      if (cmodel != CMODEL_SMALL)			\
 		{						\
 		  TARGET_NO_FP_IN_TOC = 0;			\
Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 163887)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -297,9 +297,11 @@  extern const char *host_detect_local_cpu
 
 /* Code model for 64-bit linux.
    small: 16-bit toc offsets.
-   large: 32-bit toc offsets.  */
+   medium: 32-bit toc offsets, static data and code within 2G of TOC pointer.
+   large: 32-bit toc offsets, no limit on static data and code.  */
 enum rs6000_cmodel {
   CMODEL_SMALL,
+  CMODEL_MEDIUM,
   CMODEL_LARGE
 };
 
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 163887)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -6992,6 +6992,80 @@  rs6000_eliminate_indexed_memrefs (rtx op
 			       copy_addr_to_reg (XEXP (operands[1], 0)));
 }
 
+/* Return true if OP, a SYMBOL_REF, should be considered local when
+   generating -mcmodel=medium code.  */
+
+static bool
+toc_relative_ok (rtx op)
+{
+  tree decl;
+
+  if (!SYMBOL_REF_LOCAL_P (op))
+    return false;
+
+  /* This is a bit hard to explain.  When building shared libraries,
+     you are supposed to pass -fpic or -fPIC to the compiler.
+     -fpic/-fPIC not only generate position independent code but also
+     generate code that supports ELF shared library global function
+     or variable overriding.  ppc64 is always PIC and at least some of
+     the ELF shared libaray semantics of global variables happen to be
+     supported without -fpic/-fPIC.  So people may not be careful
+     about using -fPIC for shared libs.
+     With -mcmodel=medium this situation changes.  A shared library
+     built without -fpic/-fPIC requires text relocs for global var
+     access (and would fail to load since glibc ld.so doesn't support
+     the required dynamic relocs).  So avoid this potential
+     problem by using -mcmodel=large access for global vars, unless
+     we know we are compiling for an executable.  */
+  if (flag_pie)
+    return true;
+
+  decl = SYMBOL_REF_DECL (op);
+  if (!decl || !DECL_P (decl))
+    return true;
+  if (!TREE_PUBLIC (decl))
+    return true;
+  if (DECL_VISIBILITY (decl) != VISIBILITY_DEFAULT)
+    return true;
+
+  /* If we get here we must have a global var.  See binds_local_p.  */
+  return flag_whole_program;
+}
+
+/* Return true if memory accesses to DECL are known to never straddle
+   a 32k boundary.  */
+
+static bool
+offsettable_ok_by_alignment (tree decl)
+{
+  unsigned HOST_WIDE_INT dsize, dalign;
+
+  /* Presume any compiler generated symbol_ref is suitably aligned.  */
+  if (!decl)
+    return true;
+
+  if (TREE_CODE (decl) != VAR_DECL
+      && TREE_CODE (decl) != PARM_DECL
+      && TREE_CODE (decl) != RESULT_DECL
+      && TREE_CODE (decl) != FIELD_DECL)
+    return true;
+
+  if (!DECL_SIZE_UNIT (decl))
+    return false;
+
+  if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+    return false;
+
+  dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+  if (dsize <= 1)
+    return true;
+  if (dsize > 32768)
+    return false;
+
+  dalign = DECL_ALIGN_UNIT (decl);
+  return dalign >= dsize;
+}
+
 /* Emit a move from SOURCE to DEST in mode MODE.  */
 void
 rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -7305,11 +7379,16 @@  rs6000_emit_move (rtx dest, rtx source, 
       /* If this is a SYMBOL_REF that refers to a constant pool entry,
 	 and we have put it in the TOC, we just need to make a TOC-relative
 	 reference to it.  */
-      if (TARGET_TOC
-	  && GET_CODE (operands[1]) == SYMBOL_REF
-	  && constant_pool_expr_p (operands[1])
-	  && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
-					      get_pool_mode (operands[1])))
+      if ((TARGET_TOC
+	   && GET_CODE (operands[1]) == SYMBOL_REF
+	   && constant_pool_expr_p (operands[1])
+	   && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
+					       get_pool_mode (operands[1])))
+	  || (TARGET_CMODEL == CMODEL_MEDIUM
+	      && GET_CODE (operands[1]) == SYMBOL_REF
+	      && !CONSTANT_POOL_ADDRESS_P (operands[1])
+	      && toc_relative_ok (operands[1])
+	      && offsettable_ok_by_alignment (SYMBOL_REF_DECL (operands[1]))))
 	{
 	  rtx reg = NULL_RTX;
 	  if (TARGET_CMODEL != CMODEL_SMALL)