diff options
author | Alan Modra <amodra@gmail.com> | 2010-06-15 17:03:43 +0930 |
---|---|---|
committer | Alan Modra <amodra@gcc.gnu.org> | 2010-06-15 17:03:43 +0930 |
commit | 070b27da92a270f1ada5ee00c04ee697255f2652 (patch) | |
tree | 5c65b177818e2b8c73663e18852b25e829aa44c6 /gcc/config | |
parent | 309b8e7dd612d4acda9f685ec5b9ea6a867cf0ed (diff) | |
download | gcc-070b27da92a270f1ada5ee00c04ee697255f2652.zip gcc-070b27da92a270f1ada5ee00c04ee697255f2652.tar.gz gcc-070b27da92a270f1ada5ee00c04ee697255f2652.tar.bz2 |
invoke.texi: Add mcmodel to powerpc options.
* doc/invoke.texi: Add mcmodel to powerpc options.
* configure.ac: Add HAVE_LD_LARGE_TOC test.
* configure: Regenerate.
* config.in: Regenerate.
* config/rs6000/linux64.opt (mcmodel): New.
* config/rs6000/linux64.h (TARGET_USES_LINUX64_OPT): Define.
(TARGET_CMODEL): Define.
(SUBSUBTARGET_OVERRIDE_OPTIONS): Check user -mcmodel choice,
select CMODEL_MEDIUM default.
* config/rs6000/rs6000.h (enum rs6000_cmodel): New.
(TARGET_CMODEL): Define default.
* config/rs6000/rs6000.c (cmodel): New variable.
(rs6000_explicit_options): Add cmodel field.
(rs6000_handle_option): Handle -mcmodel.
(create_TOC_reference): Add largetoc_reg param. Generate high,
lo_sum rtl for CMODEL_MEDIUM and CMODEL_LARGE. Update all callers.
(rs6000_delegitimize_address): Recognise new toc reference rtl
and minimal-toc rtl.
(rs6000_legitimize_reload_address): Handle new toc references.
(print_operand_address): Handle legitimate_constant_pool_address_p
match before lo_sum.
(rs6000_eliminate_indexed_memrefs): Tidy.
(rs6000_emit_move): Tweak threshold for inlining constants.
Keep rs6000_emit_allocate_stack large stack frame offsets
loaded into r0 inline.
(rs6000_generate_compare <cmptf_internal2>): One more clobber.
(tocrel_base, tocrel_offset): New variables.
(toc_relative_expr_p): Set them here.
(print_operand_address): Skip over any offset on constant pool
address.
(rs6000_output_addr_const_extra): Print tocrel_offset before @toc.
(rs6000_mode_dependent_address <LO_SUM>): False for new toc refs.
(offsettable_ok_by_alignment): New function.
(rs6000_emit_move): Address suitably aligned local symbol_refs
relative to the toc pointer for -mcmodel=medium.
(legitimate_constant_pool_address_p): Make param const_rtx. Add
strict param. Allow lo_sum version of addressing. Verify reg
used for -mminimal-toc and -mcmodel != small. Update all callers.
* config/rs6000/constraints.md: Update for above change.
* config/rs6000/predicates.md: Likewise.
* config/rs6000/rs6000.md (tls_gd_aix): Generate -mcmodel=medium/large
code.
(tls_gd): Split for -mcmodel=medium/large.
(tls_gd_high, tls_gd_low): New.
(tls_ld_aix, tls_ld, tls_ld_high, tls_ld_low): Similarly.
(tls_got_dtprel, tls_got_dtprel_high, tls_got_dtprel_low): Similarly.
(tls_got_tprel, tls_got_tprel_high, tls_got_tprel_low): Similarly.
(largetoc_high, largetoc_low): New.
(cmptf_internal2): Add clobber.
* config/rs6000/rs6000-protos.h: Update.
From-SVN: r160773
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/rs6000/constraints.md | 2 | ||||
-rw-r--r-- | gcc/config/rs6000/linux64.h | 32 | ||||
-rw-r--r-- | gcc/config/rs6000/linux64.opt | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/predicates.md | 2 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 4 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 244 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 14 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 221 |
8 files changed, 440 insertions, 83 deletions
diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md index bd4a1a1..7eb991a 100644 --- a/gcc/config/rs6000/constraints.md +++ b/gcc/config/rs6000/constraints.md @@ -166,7 +166,7 @@ usually better to use @samp{m} or @samp{es} in @code{asm} statements)" (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 diff --git a/gcc/config/rs6000/linux64.h b/gcc/config/rs6000/linux64.h index 39d440a..d787d29 100644 --- a/gcc/config/rs6000/linux64.h +++ b/gcc/config/rs6000/linux64.h @@ -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) diff --git a/gcc/config/rs6000/linux64.opt b/gcc/config/rs6000/linux64.opt index 0d52820..9d0e26a 100644 --- a/gcc/config/rs6000/linux64.opt +++ b/gcc/config/rs6000/linux64.opt @@ -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 diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index b4de82b..c94af46 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -837,7 +837,7 @@ 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 */ diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 3f02286..9e978bd 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -39,7 +39,7 @@ extern int small_data_operand (rtx, enum machine_mode); 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 (const_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, rtx); 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); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index a4f847d..863e7fa 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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 char *arg, int value) 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 (const_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 machine_mode mode, rtx x, int strict) 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 oldx ATTRIBUTE_UNUSED, && 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, enum machine_mode mode, } #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, enum machine_mode mode, && 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 machine_mode mode, rtx x, bool reg_ok_strict) 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 addr) 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, HOST_WIDE_INT c1, HOST_WIDE_INT c2) 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, enum machine_mode mode) /* 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, enum machine_mode mode) 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 *file, rtx x) 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 machine_mode mode) && !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 machine_mode mode) 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 largetoc_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 (largetoc_reg != NULL) + { + emit_move_insn (largetoc_reg, hi); + hi = largetoc_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 diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 5a1d7ee..cd7b928 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -293,6 +293,20 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); #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 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 9cfa74f..b3faab8 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -11004,7 +11004,12 @@ 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) @@ -11017,7 +11022,10 @@ (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") @@ -11053,13 +11061,47 @@ [(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>" @@ -11102,7 +11144,12 @@ 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)] @@ -11113,7 +11160,11 @@ (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") @@ -11146,12 +11197,44 @@ "" [(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>" @@ -11208,13 +11291,48 @@ "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") @@ -11243,13 +11361,48 @@ ;; "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") @@ -11258,7 +11411,6 @@ UNSPEC_TLSTLS))] "HAVE_AS_TLS" "add %0,%1,%2@tls") - ;; Next come insns related to the calling sequence. ;; @@ -11548,6 +11700,21 @@ "@ {cal|la} %0,%2@l(%1) {ai|addic} %0,%1,%K2") + +;; Largetoc support +(define_insn "largetoc_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 "largetoc_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 @@ -12822,26 +12989,27 @@ (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; @@ -12851,22 +13019,23 @@ 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 ()); } }) |