===================================================================
@@ -744,6 +744,7 @@ See RS/6000 and PowerPC Options.
@emph{RS/6000 and PowerPC Options}
@gccoptlist{-mcpu=@var{cpu-type} @gol
-mtune=@var{cpu-type} @gol
+-mcmodel=@var{code-model} @gol
-mpower -mno-power -mpower2 -mno-power2 @gol
-mpowerpc -mpowerpc64 -mno-powerpc @gol
-maltivec -mno-altivec @gol
@@ -14976,6 +14977,22 @@ values for @var{cpu_type} are used for @
architecture, registers, and mnemonics set by @option{-mcpu}, but the
scheduling parameters set by @option{-mtune}.
+@item -mcmodel=small
+@opindex mcmodel=small
+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
+in size. Other data and code is only limited by the 64-bit address
+space.
+
@item -maltivec
@itemx -mno-altivec
@opindex maltivec
===================================================================
@@ -3996,6 +3996,36 @@ EOF
AC_DEFINE(HAVE_LD_NO_DOT_SYMS, 1,
[Define if your PowerPC64 linker only needs function descriptor syms.])
fi
+
+ AC_CACHE_CHECK(linker large toc support,
+ gcc_cv_ld_large_toc,
+ [gcc_cv_ld_large_toc=no
+ if test $in_tree_ld = yes ; then
+ if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 21 -o "$gcc_cv_gld_major_version" -gt 2; then
+ gcc_cv_ld_large_toc=yes
+ fi
+ elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then
+ cat > conftest.s <<EOF
+ .section ".tbss","awT",@nobits
+ .align 3
+ie0: .space 8
+ .global _start
+ .text
+_start:
+ addis 9,13,ie0@got@tprel@ha
+ ld 9,ie0@got@tprel@l(9)
+EOF
+ if $gcc_cv_as -a64 -o conftest.o conftest.s > /dev/null 2>&1 \
+ && $gcc_cv_ld -melf64ppc --no-toc-sort -o conftest conftest.o > /dev/null 2>&1; then
+ gcc_cv_ld_large_toc=yes
+ fi
+ rm -f conftest conftest.o conftest.s
+ fi
+ ])
+ if test x"$gcc_cv_ld_large_toc" = xyes; then
+ AC_DEFINE(HAVE_LD_LARGE_TOC, 1,
+ [Define if your PowerPC64 linker supports a large TOC.])
+ fi
;;
esac
===================================================================
@@ -22,3 +22,7 @@
mprofile-kernel
Target Report Var(profile_kernel)
Call mcount for profiling before a function prologue
+
+mcmodel=
+Target RejectNegative Joined
+Select code model
===================================================================
@@ -63,6 +63,16 @@ extern int dot_symbols;
#define TARGET_PROFILE_KERNEL profile_kernel
+#define TARGET_USES_LINUX64_OPT 1
+#ifdef HAVE_LD_LARGE_TOC
+extern enum rs6000_cmodel cmodel;
+#undef TARGET_CMODEL
+#define TARGET_CMODEL cmodel
+#define SET_CMODEL(opt) cmodel = opt
+#else
+#define SET_CMODEL(opt)
+#endif
+
#undef PROCESSOR_DEFAULT
#define PROCESSOR_DEFAULT PROCESSOR_POWER6
#undef PROCESSOR_DEFAULT64
@@ -114,6 +124,23 @@ extern int dot_symbols;
target_flags |= MASK_POWERPC64; \
error ("-m64 requires a PowerPC64 cpu"); \
} \
+ if ((target_flags_explicit & MASK_MINIMAL_TOC) != 0) \
+ { \
+ if (rs6000_explicit_options.cmodel \
+ && cmodel != CMODEL_SMALL) \
+ error ("-mcmodel incompatible with other toc options"); \
+ SET_CMODEL (CMODEL_SMALL); \
+ } \
+ else \
+ { \
+ if (!rs6000_explicit_options.cmodel) \
+ SET_CMODEL (CMODEL_MEDIUM); \
+ if (cmodel != CMODEL_SMALL) \
+ { \
+ TARGET_NO_FP_IN_TOC = 0; \
+ TARGET_NO_SUM_IN_TOC = 0; \
+ } \
+ } \
} \
else \
{ \
@@ -124,6 +151,11 @@ extern int dot_symbols;
TARGET_PROFILE_KERNEL = 0; \
error (INVALID_32BIT, "profile-kernel"); \
} \
+ if (rs6000_explicit_options.cmodel) \
+ { \
+ SET_CMODEL (CMODEL_SMALL); \
+ error (INVALID_32BIT, "cmodel"); \
+ } \
} \
} \
while (0)
===================================================================
@@ -293,6 +293,20 @@ extern const char *host_detect_local_cpu
#define TARGET_SECURE_PLT 0
#endif
+/* Code model for 64-bit linux.
+ small: 16-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
+};
+
+#ifndef TARGET_CMODEL
+#define TARGET_CMODEL CMODEL_SMALL
+#endif
+
#define TARGET_32BIT (! TARGET_64BIT)
#ifndef HAVE_AS_TLS
===================================================================
@@ -279,6 +279,9 @@ static GTY(()) section *toc_section;
/* String from -malign-XXXXX. */
int rs6000_alignment_flags;
+/* Code model for 64-bit linux. */
+enum rs6000_cmodel cmodel;
+
/* True for any options that were explicitly set. */
static struct {
bool aix_struct_ret; /* True if -maix-struct-ret was used. */
@@ -290,6 +293,7 @@ static struct {
bool long_double; /* True if -mlong-double- was used. */
bool ieee; /* True if -mabi=ieee/ibmlongdouble used. */
bool vrsave; /* True if -mvrsave was used. */
+ bool cmodel; /* True if -mcmodel was used. */
} rs6000_explicit_options;
struct builtin_description
@@ -3645,6 +3649,22 @@ rs6000_handle_option (size_t code, const
break;
#endif
+#if defined (HAVE_LD_LARGE_TOC) && defined (TARGET_USES_LINUX64_OPT)
+ case OPT_mcmodel_:
+ if (strcmp (arg, "small") == 0)
+ cmodel = CMODEL_SMALL;
+ else if (strcmp (arg, "medium") == 0)
+ cmodel = CMODEL_MEDIUM;
+ else if (strcmp (arg, "large") == 0)
+ cmodel = CMODEL_LARGE;
+ else
+ {
+ error ("invalid option for -mcmodel: '%s'", arg);
+ return false;
+ }
+ rs6000_explicit_options.cmodel = true;
+#endif
+
#ifdef TARGET_USES_AIX64_OPT
case OPT_maix64:
#else
@@ -5098,26 +5118,29 @@ constant_pool_expr_p (rtx op)
&& ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (base), Pmode));
}
+static rtx tocrel_base, tocrel_offset;
+
bool
toc_relative_expr_p (rtx op)
{
- rtx base, offset;
-
if (GET_CODE (op) != CONST)
return false;
- split_const (op, &base, &offset);
- return (GET_CODE (base) == UNSPEC
- && XINT (base, 1) == UNSPEC_TOCREL);
+ split_const (op, &tocrel_base, &tocrel_offset);
+ return (GET_CODE (tocrel_base) == UNSPEC
+ && XINT (tocrel_base, 1) == UNSPEC_TOCREL);
}
bool
-legitimate_constant_pool_address_p (rtx x)
+legitimate_constant_pool_address_p (rtx x, bool strict)
{
return (TARGET_TOC
- && GET_CODE (x) == PLUS
+ && (GET_CODE (x) == PLUS || GET_CODE (x) == LO_SUM)
&& GET_CODE (XEXP (x, 0)) == REG
- && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
+ && (REGNO (XEXP (x, 0)) == TOC_REGISTER
+ || ((TARGET_MINIMAL_TOC
+ || TARGET_CMODEL != CMODEL_SMALL)
+ && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict)))
&& toc_relative_expr_p (XEXP (x, 1)));
}
@@ -5146,7 +5169,7 @@ rs6000_legitimate_offset_address_p (enum
return false;
if (!reg_offset_addressing_ok_p (mode))
return virtual_stack_registers_memory_p (x);
- if (legitimate_constant_pool_address_p (x))
+ if (legitimate_constant_pool_address_p (x, strict))
return true;
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
return false;
@@ -5494,7 +5517,8 @@ rs6000_legitimize_address (rtx x, rtx ol
&& constant_pool_expr_p (x)
&& ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
{
- return create_TOC_reference (x);
+ rtx reg = TARGET_CMODEL != CMODEL_SMALL ? gen_reg_rtx (Pmode) : NULL_RTX;
+ return create_TOC_reference (x, reg);
}
else
return x;
@@ -5585,10 +5609,13 @@ rs6000_delegitimize_address (rtx orig_x)
if (MEM_P (x))
x = XEXP (x, 0);
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 1)) == CONST
+ if ((GET_CODE (x) == PLUS
+ || GET_CODE (x) == LO_SUM)
&& GET_CODE (XEXP (x, 0)) == REG
- && REGNO (XEXP (x, 0)) == TOC_REGISTER)
+ && (REGNO (XEXP (x, 0)) == TOC_REGISTER
+ || TARGET_MINIMAL_TOC
+ || TARGET_CMODEL != CMODEL_SMALL)
+ && GET_CODE (XEXP (x, 1)) == CONST)
{
y = XEXP (XEXP (x, 1), 0);
if (GET_CODE (y) == UNSPEC
@@ -5600,7 +5627,6 @@ rs6000_delegitimize_address (rtx orig_x)
else
return replace_equiv_address_nv (orig_x, y);
}
- return orig_x;
}
if (TARGET_MACHO
@@ -5896,6 +5922,24 @@ rs6000_legitimize_reload_address (rtx x,
}
#endif
+ if (TARGET_CMODEL != CMODEL_SMALL
+ && GET_CODE (x) == LO_SUM
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+ && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH
+ && GET_CODE (XEXP (x, 1)) == CONST
+ && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
+ && XINT (XEXP (XEXP (x, 1), 0), 1) == UNSPEC_TOCREL
+ && rtx_equal_p (XEXP (XEXP (XEXP (x, 0), 1), 0), XEXP (x, 1)))
+ {
+ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+ opnum, (enum reload_type) type);
+ *win = 1;
+ return x;
+ }
+
/* Force ld/std non-word aligned offset into base register by wrapping
in offset 0. */
if (GET_CODE (x) == PLUS
@@ -6021,7 +6065,11 @@ rs6000_legitimize_reload_address (rtx x,
&& constant_pool_expr_p (x)
&& ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
{
- x = create_TOC_reference (x);
+ x = create_TOC_reference (x, NULL_RTX);
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+ BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+ opnum, (enum reload_type) type);
*win = 1;
return x;
}
@@ -6104,7 +6152,7 @@ rs6000_legitimate_address_p (enum machin
return 1;
if (reg_offset_p && legitimate_small_data_p (mode, x))
return 1;
- if (reg_offset_p && legitimate_constant_pool_address_p (x))
+ if (reg_offset_p && legitimate_constant_pool_address_p (x, reg_ok_strict))
return 1;
/* If not REG_OK_STRICT (before reload) let pass any stack offset. */
if (! reg_ok_strict
@@ -6212,7 +6260,9 @@ rs6000_mode_dependent_address (const_rtx
break;
case LO_SUM:
- return true;
+ /* Anything in the constant pool is sufficiently aligned that
+ all bytes have the same high part address. */
+ return !legitimate_constant_pool_address_p (addr, false);
/* Auto-increment cases are now treated generically in recog.c. */
case PRE_MODIFY:
@@ -6568,23 +6618,54 @@ rs6000_emit_set_long_const (rtx dest, HO
static void
rs6000_eliminate_indexed_memrefs (rtx operands[2])
{
+ if (reload_in_progress)
+ return;
+
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) != REG
- && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0))
- && ! reload_in_progress)
+ && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0), false))
operands[0]
= replace_equiv_address (operands[0],
copy_addr_to_reg (XEXP (operands[0], 0)));
if (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) != REG
- && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0))
- && ! reload_in_progress)
+ && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0), false))
operands[1]
= replace_equiv_address (operands[1],
copy_addr_to_reg (XEXP (operands[1], 0)));
}
+/* 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;
+
+ /* 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 (!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;
+
+ return DECL_ALIGN_UNIT (decl) >= dsize;
+}
+
/* Emit a move from SOURCE to DEST in mode MODE. */
void
rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -6898,25 +6979,43 @@ 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])
+ && SYMBOL_REF_LOCAL_P (operands[1])
+ && offsettable_ok_by_alignment (SYMBOL_REF_DECL (operands[1]))))
{
- operands[1] = create_TOC_reference (operands[1]);
+ rtx reg = NULL_RTX;
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ {
+ if (can_create_pseudo_p ())
+ reg = gen_reg_rtx (Pmode);
+ else
+ reg = operands[0];
+ }
+ operands[1] = create_TOC_reference (operands[1], reg);
}
else if (mode == Pmode
&& CONSTANT_P (operands[1])
&& ((GET_CODE (operands[1]) != CONST_INT
&& ! easy_fp_constant (operands[1], mode))
|| (GET_CODE (operands[1]) == CONST_INT
- && num_insns_constant (operands[1], mode) > 2)
+ && (num_insns_constant (operands[1], mode)
+ > (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2)))
|| (GET_CODE (operands[0]) == REG
&& FP_REGNO_P (REGNO (operands[0]))))
&& GET_CODE (operands[1]) != HIGH
- && ! legitimate_constant_pool_address_p (operands[1])
- && ! toc_relative_expr_p (operands[1]))
+ && ! legitimate_constant_pool_address_p (operands[1], false)
+ && ! toc_relative_expr_p (operands[1])
+ && (TARGET_CMODEL == CMODEL_SMALL
+ || can_create_pseudo_p ()
+ || (REG_P (operands[0])
+ && INT_REG_OK_FOR_BASE_P (operands[0], true))))
{
#if TARGET_MACHO
@@ -6962,9 +7061,17 @@ rs6000_emit_move (rtx dest, rtx source,
get_pool_constant (XEXP (operands[1], 0)),
get_pool_mode (XEXP (operands[1], 0))))
{
- operands[1]
- = gen_const_mem (mode,
- create_TOC_reference (XEXP (operands[1], 0)));
+ rtx tocref;
+ rtx reg = NULL_RTX;
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ {
+ if (can_create_pseudo_p ())
+ reg = gen_reg_rtx (Pmode);
+ else
+ reg = operands[0];
+ }
+ tocref = create_TOC_reference (XEXP (operands[1], 0), reg);
+ operands[1] = gen_const_mem (mode, tocref);
set_mem_alias_set (operands[1], get_TOC_alias_set ());
}
}
@@ -15328,14 +15435,6 @@ print_operand_address (FILE *file, rtx x
else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
-#if TARGET_ELF
- else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
- && CONSTANT_P (XEXP (x, 1)))
- {
- output_addr_const (file, XEXP (x, 1));
- fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
- }
-#endif
#if TARGET_MACHO
else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
&& CONSTANT_P (XEXP (x, 1)))
@@ -15345,11 +15444,29 @@ print_operand_address (FILE *file, rtx x
fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
}
#endif
- else if (legitimate_constant_pool_address_p (x))
+ else if (legitimate_constant_pool_address_p (x, true))
+ {
+ /* This hack along with a corresponding hack in
+ rs6000_output_addr_const_extra arranges to output addends
+ where the assembler expects to find them. eg.
+ (lo_sum (reg 9)
+ . (const (plus (unspec [symbol_ref ("x") tocrel]) 8)))
+ without this hack would be output as "x@toc+8@l(9)". We
+ want "x+8@toc@l(9)". */
+ output_addr_const (file, tocrel_base);
+ if (GET_CODE (x) == LO_SUM)
+ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+ else
+ fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
+ }
+#if TARGET_ELF
+ else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
+ && CONSTANT_P (XEXP (x, 1)))
{
output_addr_const (file, XEXP (x, 1));
- fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
+ fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
}
+#endif
else
gcc_unreachable ();
}
@@ -15363,9 +15480,14 @@ rs6000_output_addr_const_extra (FILE *fi
switch (XINT (x, 1))
{
case UNSPEC_TOCREL:
- x = XVECEXP (x, 0, 0);
- gcc_assert (GET_CODE (x) == SYMBOL_REF);
- output_addr_const (file, x);
+ gcc_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF);
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ if (x == tocrel_base && tocrel_offset != const0_rtx)
+ {
+ if (INTVAL (tocrel_offset) >= 0)
+ fprintf (file, "+");
+ output_addr_const (file, tocrel_offset);
+ }
if (!TARGET_AIX || (TARGET_ELF && TARGET_MINIMAL_TOC))
{
putc ('-', file);
@@ -15689,7 +15811,7 @@ rs6000_generate_compare (rtx cmp, enum m
&& !TARGET_IEEEQUAD
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
emit_insn (gen_rtx_PARALLEL (VOIDmode,
- gen_rtvec (9,
+ gen_rtvec (10,
gen_rtx_SET (VOIDmode,
compare_result,
gen_rtx_COMPARE (comp_mode, op0, op1)),
@@ -15700,7 +15822,8 @@ rs6000_generate_compare (rtx cmp, enum m
gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
- gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (Pmode)))));
else if (GET_CODE (op1) == UNSPEC
&& XINT (op1, 1) == UNSPEC_SP_TEST)
{
@@ -18259,8 +18382,10 @@ uses_TOC (void)
#endif
rtx
-create_TOC_reference (rtx symbol)
+create_TOC_reference (rtx symbol, rtx bigtoc_reg)
{
+ rtx tocrel, tocreg;
+
if (TARGET_DEBUG_ADDR)
{
if (GET_CODE (symbol) == SYMBOL_REF)
@@ -18276,10 +18401,23 @@ create_TOC_reference (rtx symbol)
if (!can_create_pseudo_p ())
df_set_regs_ever_live (TOC_REGISTER, true);
- return gen_rtx_PLUS (Pmode,
- gen_rtx_REG (Pmode, TOC_REGISTER),
- gen_rtx_CONST (Pmode,
- gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol), UNSPEC_TOCREL)));
+
+ tocrel = gen_rtx_CONST (Pmode,
+ gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol),
+ UNSPEC_TOCREL));
+ tocreg = gen_rtx_REG (Pmode, TOC_REGISTER);
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ {
+ rtx hi = gen_rtx_PLUS (Pmode, tocreg, gen_rtx_HIGH (Pmode, tocrel));
+ if (bigtoc_reg != NULL)
+ {
+ emit_move_insn (bigtoc_reg, hi);
+ hi = bigtoc_reg;
+ }
+ return gen_rtx_LO_SUM (Pmode, hi, copy_rtx (tocrel));
+ }
+ else
+ return gen_rtx_PLUS (Pmode, tocreg, tocrel);
}
/* Issue assembly directives that create a reference to the given DWARF
===================================================================
@@ -166,7 +166,7 @@ (define_address_constraint "a"
(define_constraint "R"
"AIX TOC entry"
- (match_test "legitimate_constant_pool_address_p (op)"))
+ (match_test "legitimate_constant_pool_address_p (op, false)"))
;; General constraints
===================================================================
@@ -837,7 +837,7 @@ (define_predicate "input_operand"
return 1;
/* A SYMBOL_REF referring to the TOC is valid. */
- if (legitimate_constant_pool_address_p (op))
+ if (legitimate_constant_pool_address_p (op, false))
return 1;
/* A constant pool expression (relative to the TOC) is valid */
===================================================================
@@ -11003,7 +11003,12 @@ (define_insn_and_split "tls_gd_aix<TLSmo
UNSPEC_TLSGD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
- "addi %0,%1,%2@got@tlsgd\;bl %z3\;%."
+{
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;bl %z3\;%.";
+ else
+ return "addi %0,%1,%2@got@tlsgd\;bl %z3\;%.";
+}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:TLSmode [(match_dup 1)
@@ -11016,7 +11021,10 @@ (define_insn_and_split "tls_gd_aix<TLSmo
(clobber (reg:SI LR_REGNO))])]
""
[(set_attr "type" "two")
- (set_attr "length" "12")])
+ (set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 16)
+ (const_int 12)))])
(define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
@@ -11052,13 +11060,47 @@ (define_insn_and_split "tls_gd_sysv<TLSm
[(set_attr "type" "two")
(set_attr "length" "8")])
-(define_insn "*tls_gd<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGD))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS"
"addi %0,%1,%2@got@tlsgd"
+ "&& TARGET_CMODEL != CMODEL_SMALL"
+ [(set (match_dup 3)
+ (plus:TLSmode (match_dup 1)
+ (high:TLSmode
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD))))
+ (set (match_dup 0)
+ (lo_sum:TLSmode (match_dup 3)
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))]
+ "
+{
+ operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+ [(set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 8)
+ (const_int 4)))])
+
+(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (high:TLSmode
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGD))))]
+ "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+ "addis %0,%1,%2@got@tlsgd@ha"
+ [(set_attr "length" "4")])
+
+(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGD)))]
+ "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+ "addi %0,%1,%2@got@tlsgd@l"
[(set_attr "length" "4")])
(define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>"
@@ -11101,7 +11143,12 @@ (define_insn_and_split "tls_ld_aix<TLSmo
UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))]
"HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX"
- "addi %0,%1,%&@got@tlsld\;bl %z2\;%."
+{
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;bl %z2\;%.";
+ else
+ return "addi %0,%1,%&@got@tlsld\;bl %z2\;%.";
+}
"&& TARGET_TLS_MARKERS"
[(set (match_dup 0)
(unspec:TLSmode [(match_dup 1)]
@@ -11112,7 +11159,11 @@ (define_insn_and_split "tls_ld_aix<TLSmo
(unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)
(clobber (reg:SI LR_REGNO))])]
""
- [(set_attr "length" "12")])
+ [(set_attr "type" "two")
+ (set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 16)
+ (const_int 12)))])
(define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
@@ -11145,12 +11196,44 @@ (define_insn_and_split "tls_ld_sysv<TLSm
""
[(set_attr "length" "8")])
-(define_insn "*tls_ld<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")]
UNSPEC_TLSLD))]
"HAVE_AS_TLS && TARGET_TLS_MARKERS"
"addi %0,%1,%&@got@tlsld"
+ "&& TARGET_CMODEL != CMODEL_SMALL"
+ [(set (match_dup 2)
+ (plus:TLSmode (match_dup 1)
+ (high:TLSmode
+ (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))
+ (set (match_dup 0)
+ (lo_sum:TLSmode (match_dup 2)
+ (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))]
+ "
+{
+ operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+ [(set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 8)
+ (const_int 4)))])
+
+(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (high:TLSmode
+ (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))]
+ "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+ "addis %0,%1,%&@got@tlsld@ha"
+ [(set_attr "length" "4")])
+
+(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))]
+ "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL"
+ "addi %0,%1,%&@got@tlsld@l"
[(set_attr "length" "4")])
(define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>"
@@ -11207,13 +11290,48 @@ (define_insn "tls_dtprel_lo_<TLSmode:tls
"HAVE_AS_TLS"
"addi %0,%1,%2@dtprel@l")
-(define_insn "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGOTDTPREL))]
"HAVE_AS_TLS"
- "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)")
+ "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)"
+ "&& TARGET_CMODEL != CMODEL_SMALL"
+ [(set (match_dup 3)
+ (plus:TLSmode (match_dup 1)
+ (high:TLSmode
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL))))
+ (set (match_dup 0)
+ (lo_sum:TLSmode (match_dup 3)
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))]
+ "
+{
+ operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+ [(set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 8)
+ (const_int 4)))])
+
+(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (high:TLSmode
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTDTPREL))))]
+ "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+ "addis %0,%1,%2@got@dtprel@ha"
+ [(set_attr "length" "4")])
+
+(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
+ (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTDTPREL)))]
+ "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+ "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)"
+ [(set_attr "length" "4")])
(define_insn "tls_tprel_<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
@@ -11242,13 +11360,48 @@ (define_insn "tls_tprel_lo_<TLSmode:tls_
;; "b" output constraint here and on tls_tls input to support linker tls
;; optimization. The linker may edit the instructions emitted by a
;; tls_got_tprel/tls_tls pair to addis,addi.
-(define_insn "tls_got_tprel_<TLSmode:tls_abi_suffix>"
+(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
(unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")
(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
UNSPEC_TLSGOTTPREL))]
"HAVE_AS_TLS"
- "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)")
+ "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)"
+ "&& TARGET_CMODEL != CMODEL_SMALL"
+ [(set (match_dup 3)
+ (plus:TLSmode (match_dup 1)
+ (high:TLSmode
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL))))
+ (set (match_dup 0)
+ (lo_sum:TLSmode (match_dup 3)
+ (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))]
+ "
+{
+ operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode);
+}"
+ [(set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL"))
+ (const_int 8)
+ (const_int 4)))])
+
+(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b")
+ (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (high:TLSmode
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTTPREL))))]
+ "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+ "addis %0,%1,%2@got@tprel@ha"
+ [(set_attr "length" "4")])
+
+(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>"
+ [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
+ (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b")
+ (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")]
+ UNSPEC_TLSGOTTPREL)))]
+ "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL"
+ "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)"
+ [(set_attr "length" "4")])
(define_insn "tls_tls_<TLSmode:tls_abi_suffix>"
[(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r")
@@ -11257,7 +11410,6 @@ (define_insn "tls_tls_<TLSmode:tls_abi_s
UNSPEC_TLSTLS))]
"HAVE_AS_TLS"
"add %0,%1,%2@tls")
-
;; Next come insns related to the calling sequence.
;;
@@ -11547,6 +11699,21 @@ (define_insn "elf_low"
"@
{cal|la} %0,%2@l(%1)
{ai|addic} %0,%1,%K2")
+
+;; Bigtoc support
+(define_insn "bigtoc_high"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=b")
+ (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b")
+ (high:DI (match_operand:DI 2 "" ""))))]
+ "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
+ "{cau|addis} %0,%1,%2@ha")
+
+(define_insn "bigtoc_low"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b")
+ (match_operand:DI 2 "" "")))]
+ "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL"
+ "{cal %0,%2@l(%1)|addi %0,%1,%2@l}")
;; A function pointer under AIX is a pointer to a data area whose first word
;; contains the actual address of the function, whose second word contains a
@@ -12821,26 +12988,27 @@ (define_insn_and_split "*cmptf_internal2
(clobber (match_scratch:DF 7 "=d"))
(clobber (match_scratch:DF 8 "=d"))
(clobber (match_scratch:DF 9 "=d"))
- (clobber (match_scratch:DF 10 "=d"))]
+ (clobber (match_scratch:DF 10 "=d"))
+ (clobber (match_scratch:GPR 11 "=b"))]
"!TARGET_IEEEQUAD && TARGET_XL_COMPAT
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128"
"#"
"&& reload_completed"
- [(set (match_dup 3) (match_dup 13))
- (set (match_dup 4) (match_dup 14))
+ [(set (match_dup 3) (match_dup 14))
+ (set (match_dup 4) (match_dup 15))
(set (match_dup 9) (abs:DF (match_dup 5)))
(set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 3)))
(set (pc) (if_then_else (ne (match_dup 0) (const_int 0))
- (label_ref (match_dup 11))
+ (label_ref (match_dup 12))
(pc)))
(set (match_dup 0) (compare:CCFP (match_dup 5) (match_dup 7)))
- (set (pc) (label_ref (match_dup 12)))
- (match_dup 11)
+ (set (pc) (label_ref (match_dup 13)))
+ (match_dup 12)
(set (match_dup 10) (minus:DF (match_dup 5) (match_dup 7)))
(set (match_dup 9) (minus:DF (match_dup 6) (match_dup 8)))
(set (match_dup 9) (plus:DF (match_dup 10) (match_dup 9)))
(set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 4)))
- (match_dup 12)]
+ (match_dup 13)]
{
REAL_VALUE_TYPE rv;
const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
@@ -12850,22 +13018,23 @@ (define_insn_and_split "*cmptf_internal2
operands[6] = simplify_gen_subreg (DFmode, operands[1], TFmode, lo_word);
operands[7] = simplify_gen_subreg (DFmode, operands[2], TFmode, hi_word);
operands[8] = simplify_gen_subreg (DFmode, operands[2], TFmode, lo_word);
- operands[11] = gen_label_rtx ();
operands[12] = gen_label_rtx ();
+ operands[13] = gen_label_rtx ();
real_inf (&rv);
- operands[13] = force_const_mem (DFmode,
- CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode));
operands[14] = force_const_mem (DFmode,
+ CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode));
+ operands[15] = force_const_mem (DFmode,
CONST_DOUBLE_FROM_REAL_VALUE (dconst0,
DFmode));
if (TARGET_TOC)
{
- operands[13] = gen_const_mem (DFmode,
- create_TOC_reference (XEXP (operands[13], 0)));
- operands[14] = gen_const_mem (DFmode,
- create_TOC_reference (XEXP (operands[14], 0)));
- set_mem_alias_set (operands[13], get_TOC_alias_set ());
+ rtx tocref;
+ tocref = create_TOC_reference (XEXP (operands[14], 0), operands[11]);
+ operands[14] = gen_const_mem (DFmode, tocref);
+ tocref = create_TOC_reference (XEXP (operands[15], 0), operands[11]);
+ operands[15] = gen_const_mem (DFmode, tocref);
set_mem_alias_set (operands[14], get_TOC_alias_set ());
+ set_mem_alias_set (operands[15], get_TOC_alias_set ());
}
})
===================================================================
@@ -39,7 +39,7 @@ extern int small_data_operand (rtx, enum
extern bool toc_relative_expr_p (rtx);
extern bool invalid_e500_subreg (rtx, enum machine_mode);
extern void validate_condition_mode (enum rtx_code, enum machine_mode);
-extern bool legitimate_constant_pool_address_p (rtx);
+extern bool legitimate_constant_pool_address_p (rtx, bool);
extern bool legitimate_indirect_address_p (rtx, int);
extern bool legitimate_indexed_address_p (rtx, int);
extern bool avoiding_indexed_address_p (enum machine_mode);
@@ -111,7 +111,7 @@ extern void rs6000_emit_swrsqrt (rtx, rt
extern void output_toc (FILE *, rtx, int, enum machine_mode);
extern rtx rs6000_longcall_ref (rtx);
extern void rs6000_fatal_bad_address (rtx);
-extern rtx create_TOC_reference (rtx);
+extern rtx create_TOC_reference (rtx, rtx);
extern void rs6000_split_multireg_move (rtx, rtx);
extern void rs6000_emit_move (rtx, rtx, enum machine_mode);
extern rtx rs6000_secondary_memory_needed_rtx (enum machine_mode);