===================================================================
@@ -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
===================================================================
@@ -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; \
===================================================================
@@ -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
};
===================================================================
@@ -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)