From patchwork Thu Aug 19 16:09:11 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Stubbs X-Patchwork-Id: 62192 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 0E99FB70E8 for ; Fri, 20 Aug 2010 02:09:46 +1000 (EST) Received: (qmail 12970 invoked by alias); 19 Aug 2010 16:09:44 -0000 Received: (qmail 12955 invoked by uid 22791); 19 Aug 2010 16:09:34 -0000 X-SWARE-Spam-Status: No, hits=0.6 required=5.0 tests=AWL, BAYES_50, KAM_STOCKGEN, TW_FN, TW_LG, TW_QR, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 19 Aug 2010 16:09:17 +0000 Received: (qmail 31893 invoked from network); 19 Aug 2010 16:09:13 -0000 Received: from unknown (HELO ?192.168.0.104?) (ams@127.0.0.2) by mail.codesourcery.com with ESMTPA; 19 Aug 2010 16:09:13 -0000 Message-ID: <4C6D5727.5020407@codesourcery.com> Date: Thu, 19 Aug 2010 17:09:11 +0100 From: Andrew Stubbs User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.2.8) Gecko/20100802 Lightning/1.0b2 Thunderbird/3.1.2 MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org Subject: [PATCH 3/3] SH-2A FDPIC: backend support Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org This patch adds FDPIC support for SH-2A uClinux. The binutils patch was already accepted and committed. The result is a functional compiler that will build a working busybox-based uClinux system, and pass the majority of the tests in the GCC testsuite. It has been tested on a Renesas SH7203. The compiler is known to be less than perfect, but it is a start and will provide a basis for future improvement. There is no existing SH FDPIC support, so this is not a regression. The ABI for the new system is published here: http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt OK to commit? Andrew Stubbs 2010-08-19 Daniel Jacobowitz Joseph Myers Mark Shinwell Andrew Stubbs gcc/ * config.gcc: Handle sh-*-uclinux* | sh[12]-*-uclinux*. Handle --enable-fdpic. * config/sh/constraints.md: Add Ccl constraint. * config/sh/lib1funcs.asm (set_fpscr): Handle FDPIC. * config/sh/predicates.md (pseudo_register_operand): New. * config/sh/sh-protos.h (sh_load_function_descriptor, sh_legitimate_constant_p, sh_our_fdpic_reg): Declare. (function_symbol): Update prototype. * config/sh/sh.c (sh_assemble_integer, sh_cannot_force_const_mem_p, sh_delegitimize_address, sh_reloc_rw_mask, sh_legitimate_constant_p, sh_cannot_force_const_mem_p, sh_load_function_descriptor, sh_our_fdpic_reg, sh_reloc_rw_mask): New. (TARGET_ASM_INTEGER, TARGET_DELEGITIMIZE_ADDRESS, TARGET_CANNOT_FORCE_CONST_MEM, TARGET_ASM_RELOC_RW_MASK): Define. (sh_override_options, expand_block_move, prepare_move_operands, sh_cannot_copy_insn_p, expand_ashiftrt, sh_expand_prologue, nonpic_symbol_mentioned_p, legitimize_pic_address, sh_trampoline_init, sh_output_mi_thunk, function_symbol): Support FDPIC. * config/sh/sh.h (TARGET_CPU_CPP_BUILTINS): Add __SH_FDPIC__ and __FDPIC__. (CONDITIONAL_REGISTER_USAGE, TRAMPOLINE_SIZE, OUTPUT_ADDR_CONST_EXTRA, ASM_PREFERRED_EH_DATA_FORMAT, ASM_MAYBE_OUTPUT_ENCODED_ADDR_RTX): Support FDPIC. (DRIVER_SELF_SPECS): Insert SUBTARGET_DRIVER_SELF_SPECS. (SUBTARGET_DRIVER_SELF_SPECS, PIC_OFFSET_TABLE_REG_CALL_CLOBBERED, OUR_FDPIC_REG, SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P, CRT_GET_RFIB_DATA): Define. (LEGITIMATE_CONSTANT_P): Use sh_legitimate_constant_p. * config/sh/sh.md (R12_REG, UNSPEC_GOTFUNCDESC, UNSPEC_GOTOFFFUNCDESC, sym2GOTFUNCDESC, symGOTFUNCDESC2reg, sym2GOTOFFFUNCDESC, symGOTOFFFUNCDESC2reg): Define. (udivsi3_i1, udivsi3_i4, udivsi3_i4_single, udivsi3, divsi_inv_call_combine, divsi3_i4_media, divsi3_i4, divsi3_i4_single, divsi3, mulsi3, ashrsi3_n, ic_invalidate_line, initialize_trampoline, calli, call_valuei, call, call_pop, call_value, sibcalli, sibcall_pcrel, sibcall, sibcall_valuei, sibcall_valuei_pcrel, sibcall_value_pcrel, sibcall_value, call_value_pop, GOTaddr2picreg, symGOT_load, symGOTOFF2reg, shcompact_return_tramp, block_move_real, block_lump_real, block_move_real_i4, block_lump_real_i4): Support FDPIC, and update calls to functions with new parameters. (calli_fdpic, call_valuei_fdpic, sibcalli_fdpic, sibcalli_pcrel_fdpic, sibcall_pcrel_fdpic, sibcall_valuei_fdpic, sibcall_valuei_pcrel_fdpic, sibcall_value_pcrel_fdpic, use_initial_val, sym2GOTFUNCDESC, symGOTFUNCDESC2reg, sym2GOTOFFFUNCDESC, symGOTOFFFUNCDESC2reg): New. * config/sh/sh.opt (-mfdpic): New option. * config/sh/t-uclinux: New file. * config/sh/uclinux.h: New file. * doc/install.texi (Options specification): Add --enable-fdpic. * doc/invoke.texi (SH Options): Add -mfdpic. * longlong.h (udiv_qrnnd): Add FDPIC compatible version. gcc/testsuite/ * gcc.target/sh/sh-relax.c: Add xfail for sh*-*-uclinux. libgcc/ * libgcc/config.host: Handle sh-*-uclinux* and sh[2346lbe]*-*-uclinux*. --- src/gcc-mainline/gcc/config.gcc | 9 src/gcc-mainline/gcc/config/sh/constraints.md | 6 src/gcc-mainline/gcc/config/sh/lib1funcs.asm | 9 src/gcc-mainline/gcc/config/sh/predicates.md | 7 src/gcc-mainline/gcc/config/sh/sh-protos.h | 5 src/gcc-mainline/gcc/config/sh/sh.c | 352 ++++++++++++-- src/gcc-mainline/gcc/config/sh/sh.h | 74 ++- src/gcc-mainline/gcc/config/sh/sh.md | 500 +++++++++++++++++--- src/gcc-mainline/gcc/config/sh/sh.opt | 4 src/gcc-mainline/gcc/config/sh/t-uclinux | 4 src/gcc-mainline/gcc/config/sh/uclinux.h | 96 ++++ src/gcc-mainline/gcc/doc/install.texi | 4 src/gcc-mainline/gcc/doc/invoke.texi | 5 src/gcc-mainline/gcc/longlong.h | 30 + .../gcc/testsuite/gcc.target/sh/sh-relax.c | 1 src/gcc-mainline/libgcc/config.host | 1 16 files changed, 962 insertions(+), 145 deletions(-) create mode 100644 src/gcc-mainline/gcc/config/sh/t-uclinux create mode 100644 src/gcc-mainline/gcc/config/sh/uclinux.h diff --git a/src/gcc-mainline/gcc/config.gcc b/src/gcc-mainline/gcc/config.gcc index 9170fc8..4b44f4b 100644 --- a/src/gcc-mainline/gcc/config.gcc +++ b/src/gcc-mainline/gcc/config.gcc @@ -2208,6 +2208,7 @@ score-*-elf) sh-*-elf* | sh[12346l]*-*-elf* | \ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ sh-*-linux* | sh[2346lbe]*-*-linux* | \ + sh-*-uclinux* | sh[12]-*-uclinux* | \ sh-*-netbsdelf* | shl*-*-netbsdelf* | sh5-*-netbsd* | sh5l*-*-netbsd* | \ sh64-*-netbsd* | sh64l*-*-netbsd*) tmake_file="${tmake_file} sh/t-sh sh/t-elf" @@ -2245,6 +2246,13 @@ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ sh*-*-linux*) tmake_file="${tmake_file} sh/t-linux" tm_file="${tm_file} linux.h glibc-stdint.h sh/linux.h" ;; sh*-*-netbsd*) tm_file="${tm_file} netbsd.h netbsd-elf.h sh/netbsd-elf.h" ;; + sh*-*-uclinux*) if test x$enable_fdpic != xno; then + tmake_file="${tmake_file} t-slibgcc-elf-ver" + tm_file="${tm_file} sh/uclinux.h" + tm_defines="$tm_defines FDPIC_DEFAULT=1" + else + tm_file="${tm_file} flat.h sh/uclinux.h" + fi ;; sh*-superh-elf) if test x$with_libgloss != xno; then with_libgloss=yes tm_file="${tm_file} sh/newlib.h" @@ -2271,6 +2279,7 @@ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ *-*-netbsd) tmake_file="${tmake_file} sh/t-netbsd" ;; + sh*-*-uclinux*) tmake_file="${tmake_file} sh/t-uclinux" ;; sh64*-*-linux*) tmake_file="${tmake_file} sh/t-sh64 sh/t-linux64" tm_file="${tm_file} sh/sh64.h" diff --git a/src/gcc-mainline/gcc/config/sh/constraints.md b/src/gcc-mainline/gcc/config/sh/constraints.md index 6b0e5d2..640b28e 100644 --- a/src/gcc-mainline/gcc/config/sh/constraints.md +++ b/src/gcc-mainline/gcc/config/sh/constraints.md @@ -22,6 +22,7 @@ ;; Bsc: SCRATCH - for the scratch register in movsi_ie in the ;; fldi0 / fldi0 cases ;; Cxx: Constants other than only CONST_INT +;; Ccl: call site label ;; Css: signed 16-bit constant, literal or symbolic ;; Csu: unsigned 16-bit constant, literal or symbolic ;; Csy: label or symbol @@ -183,6 +184,11 @@ hence mova is being used, hence do not select this pattern." (match_code "scratch")) +(define_constraint "Ccl" + "A call site label, for bsrf." + (and (match_code "unspec") + (match_test "XINT (op, 1) == UNSPEC_CALLER"))) + (define_constraint "Css" "A signed 16-bit constant, literal or symbolic." (and (match_code "const") diff --git a/src/gcc-mainline/gcc/config/sh/lib1funcs.asm b/src/gcc-mainline/gcc/config/sh/lib1funcs.asm index 2f0ca16..c32bfd3 100644 --- a/src/gcc-mainline/gcc/config/sh/lib1funcs.asm +++ b/src/gcc-mainline/gcc/config/sh/lib1funcs.asm @@ -1973,7 +1973,10 @@ GLOBAL(moddi3): HIDDEN_FUNC(GLOBAL(set_fpscr)) GLOBAL(set_fpscr): lds r4,fpscr -#ifdef __PIC__ +#if defined(__SH_FDPIC__) + mov.l LOCAL(set_fpscr_L1),r0 + mov.l @(r0,r12),r1 +#elif defined(__PIC__) mov.l r12,@-r15 #ifdef __vxworks mov.l LOCAL(set_fpscr_L0_base),r12 @@ -2018,7 +2021,8 @@ GLOBAL(set_fpscr): mov.l r3,@(4,r1) #endif .align 2 -#ifdef __PIC__ +#if defined __PIC__ || defined __SH_FDPIC__ +#ifndef __SH_FDPIC__ #ifdef __vxworks LOCAL(set_fpscr_L0_base): .long ___GOTT_BASE__ @@ -2028,6 +2032,7 @@ LOCAL(set_fpscr_L0_index): LOCAL(set_fpscr_L0): .long _GLOBAL_OFFSET_TABLE_ #endif +#endif /* __SH_FDPIC__ */ LOCAL(set_fpscr_L1): .long GLOBAL(fpscr_values@GOT) #else diff --git a/src/gcc-mainline/gcc/config/sh/predicates.md b/src/gcc-mainline/gcc/config/sh/predicates.md index b6508b7..6815e08 100644 --- a/src/gcc-mainline/gcc/config/sh/predicates.md +++ b/src/gcc-mainline/gcc/config/sh/predicates.md @@ -831,3 +831,10 @@ } return 0; }) + +(define_predicate "pseudo_register_operand" + (match_code "reg") +{ + return (reload_completed || reload_in_progress + || REGNO (op) >= FIRST_PSEUDO_REGISTER); +}) \ No newline at end of file diff --git a/src/gcc-mainline/gcc/config/sh/sh-protos.h b/src/gcc-mainline/gcc/config/sh/sh-protos.h index dc68af1..f717f65 100644 --- a/src/gcc-mainline/gcc/config/sh/sh-protos.h +++ b/src/gcc-mainline/gcc/config/sh/sh-protos.h @@ -156,7 +156,7 @@ extern void fpscr_set_from_mem (int, HARD_REG_SET); extern void sh_pr_interrupt (struct cpp_reader *); extern void sh_pr_trapa (struct cpp_reader *); extern void sh_pr_nosave_low_regs (struct cpp_reader *); -extern rtx function_symbol (rtx, const char *, enum sh_function_kind); +extern rtx function_symbol (rtx, const char *, enum sh_function_kind, rtx *); extern rtx sh_get_pr_initial_val (void); extern rtx sh_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); @@ -180,6 +180,9 @@ extern int sh2a_get_function_vector_number (rtx); extern int sh2a_is_function_vector_call (rtx); extern void sh_fix_range (const char *); extern bool sh_hard_regno_mode_ok (unsigned int, enum machine_mode); +extern bool sh_legitimate_constant_p (rtx); +extern rtx sh_load_function_descriptor (rtx); +extern rtx sh_our_fdpic_reg (void); #endif /* ! GCC_SH_PROTOS_H */ #ifdef SYMBIAN diff --git a/src/gcc-mainline/gcc/config/sh/sh.c b/src/gcc-mainline/gcc/config/sh/sh.c index 8ace99c..36b6561 100644 --- a/src/gcc-mainline/gcc/config/sh/sh.c +++ b/src/gcc-mainline/gcc/config/sh/sh.c @@ -237,6 +237,7 @@ static tree sh_media_builtin_decl (unsigned, bool); static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int); static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static void sh_file_start (void); +static bool sh_assemble_integer (rtx, unsigned, int); static int flow_dependent_p (rtx, rtx); static void flow_dependent_p_1 (rtx, const_rtx, void *); static int shiftcosts (rtx); @@ -245,12 +246,14 @@ static int addsubcosts (rtx); static int multcosts (rtx); static bool unspec_caller_rtx_p (rtx); static bool sh_cannot_copy_insn_p (rtx); +static bool sh_cannot_force_const_mem_p (rtx); static bool sh_rtx_costs (rtx, int, int, int *, bool); static int sh_address_cost (rtx, bool); static int sh_pr_n_sets (void); static rtx sh_allocate_initial_value (rtx); static bool sh_legitimate_address_p (enum machine_mode, rtx, bool); static rtx sh_legitimize_address (rtx, rtx, enum machine_mode); +static rtx sh_delegitimize_address (rtx); static int shmedia_target_regs_stack_space (HARD_REG_SET *); static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); @@ -288,6 +291,7 @@ static void sh_encode_section_info (tree, rtx, int); static int sh2a_function_vector_p (tree); static void sh_trampoline_init (rtx, tree, rtx); static rtx sh_trampoline_adjust_address (rtx); +static int sh_reloc_rw_mask (void); static const struct attribute_spec sh_attribute_table[] = { @@ -351,6 +355,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER sh_assemble_integer + #undef TARGET_DEFAULT_TARGET_FLAGS #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT #undef TARGET_HANDLE_OPTION @@ -424,6 +431,11 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address +#if 0 +#undef TARGET_DELEGITIMIZE_ADDRESS +#define TARGET_DELEGITIMIZE_ADDRESS sh_delegitimize_address +#endif + #undef TARGET_CANNOT_MODIFY_JUMPS_P #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p #undef TARGET_BRANCH_TARGET_REGISTER_CLASS @@ -551,6 +563,12 @@ static const struct attribute_spec sh_attribute_table[] = /* Machine-specific symbol_ref flags. */ #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM sh_cannot_force_const_mem_p + +#undef TARGET_ASM_RELOC_RW_MASK +#define TARGET_ASM_RELOC_RW_MASK sh_reloc_rw_mask + struct gcc_target targetm = TARGET_INITIALIZER; /* Implement TARGET_HANDLE_OPTION. */ @@ -861,6 +879,10 @@ sh_override_options (void) sh_branch_cost = TARGET_SH5 ? 1 : ! TARGET_SH2 || TARGET_HARD_SH4 ? 2 : 1; + if (TARGET_FDPIC + && (TARGET_SHMEDIA || TARGET_SHCOMPACT || !TARGET_SH2)) + sorry ("non-SH2 FDPIC"); + for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (! VALID_REGISTER_P (regno)) sh_register_names[regno][0] = '\0'; @@ -871,7 +893,7 @@ sh_override_options (void) flag_omit_frame_pointer = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); - if ((flag_pic && ! TARGET_PREFERGOT) + if (((flag_pic || TARGET_FDPIC) && ! TARGET_PREFERGOT) || (TARGET_SHMEDIA && !TARGET_PT_FIXED)) flag_no_function_cse = 1; @@ -1512,11 +1534,13 @@ expand_block_move (rtx *operands) rtx func_addr_rtx = gen_reg_rtx (Pmode); rtx r4 = gen_rtx_REG (SImode, 4); rtx r5 = gen_rtx_REG (SImode, 5); + rtx lab; - function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC); + function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC, + &lab); force_into (XEXP (operands[0], 0), r4); force_into (XEXP (operands[1], 0), r5); - emit_insn (gen_block_move_real_i4 (func_addr_rtx)); + emit_insn (gen_block_move_real_i4 (func_addr_rtx, lab)); return 1; } else if (! TARGET_SMALLCODE) @@ -1527,15 +1551,16 @@ expand_block_move (rtx *operands) rtx r4 = gen_rtx_REG (SImode, 4); rtx r5 = gen_rtx_REG (SImode, 5); rtx r6 = gen_rtx_REG (SImode, 6); + rtx lab; entry_name = (bytes & 4 ? "__movmem_i4_odd" : "__movmem_i4_even"); - function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC); + function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC, &lab); force_into (XEXP (operands[0], 0), r4); force_into (XEXP (operands[1], 0), r5); dwords = bytes >> 3; emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1))); - emit_insn (gen_block_lump_real_i4 (func_addr_rtx)); + emit_insn (gen_block_lump_real_i4 (func_addr_rtx, lab)); return 1; } else @@ -1547,12 +1572,13 @@ expand_block_move (rtx *operands) rtx func_addr_rtx = gen_reg_rtx (Pmode); rtx r4 = gen_rtx_REG (SImode, 4); rtx r5 = gen_rtx_REG (SImode, 5); + rtx lab; sprintf (entry, "__movmemSI%d", bytes); - function_symbol (func_addr_rtx, entry, SFUNC_STATIC); + function_symbol (func_addr_rtx, entry, SFUNC_STATIC, &lab); force_into (XEXP (operands[0], 0), r4); force_into (XEXP (operands[1], 0), r5); - emit_insn (gen_block_move_real (func_addr_rtx)); + emit_insn (gen_block_move_real (func_addr_rtx, lab)); return 1; } @@ -1565,8 +1591,9 @@ expand_block_move (rtx *operands) rtx r4 = gen_rtx_REG (SImode, 4); rtx r5 = gen_rtx_REG (SImode, 5); rtx r6 = gen_rtx_REG (SImode, 6); + rtx lab; - function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC); + function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC, &lab); force_into (XEXP (operands[0], 0), r4); force_into (XEXP (operands[1], 0), r5); @@ -1579,7 +1606,7 @@ expand_block_move (rtx *operands) final_switch = 16 - ((bytes / 4) % 16); while_loop = ((bytes / 4) / 16 - 1) * 16; emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch))); - emit_insn (gen_block_lump_real (func_addr_rtx)); + emit_insn (gen_block_lump_real (func_addr_rtx, lab)); return 1; } @@ -1592,8 +1619,10 @@ expand_block_move (rtx *operands) int prepare_move_operands (rtx operands[], enum machine_mode mode) { + rtx tmp, base, offset; + if ((mode == SImode || mode == DImode) - && flag_pic + && (flag_pic || TARGET_FDPIC) && ! ((mode == Pmode || mode == ptr_mode) && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE)) { @@ -1684,12 +1713,22 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) { case TLS_MODEL_GLOBAL_DYNAMIC: tga_ret = gen_rtx_REG (Pmode, R0_REG); + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } emit_call_insn (gen_tls_global_dynamic (tga_ret, op1)); op1 = tga_ret; break; case TLS_MODEL_LOCAL_DYNAMIC: tga_ret = gen_rtx_REG (Pmode, R0_REG); + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } emit_call_insn (gen_tls_local_dynamic (tga_ret, op1)); tmp = gen_reg_rtx (Pmode); @@ -1719,6 +1758,11 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) } tga_op1 = !can_create_pseudo_p () ? op0 : gen_reg_rtx (Pmode); tmp = gen_sym2GOTTPOFF (op1); + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } emit_insn (gen_tls_initial_exec (tga_op1, tmp)); op1 = tga_op1; break; @@ -1746,6 +1790,21 @@ prepare_move_operands (rtx operands[], enum machine_mode mode) } } + if (SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P) + { + split_const (operands[1], &base, &offset); + if (GET_CODE (base) == SYMBOL_REF + && !offset_within_block_p (base, INTVAL (offset))) + { + tmp = can_create_pseudo_p () ? gen_reg_rtx (mode) : operands[0]; + emit_move_insn (tmp, base); + if (!arith_operand (offset, mode)) + offset = force_reg (mode, offset); + emit_insn (gen_add3_insn (operands[0], tmp, offset)); + return 1; + } + } + return 0; } @@ -2693,6 +2752,26 @@ sh_file_start (void) } } +/* Implementation of TARGET_ASM_INTEGER for SH. Pointers to functions + need to be output as pointers to function descriptors for + FDPIC. */ + +static bool +sh_assemble_integer (rtx value, unsigned int size, int aligned_p) +{ + if (TARGET_FDPIC + && size == UNITS_PER_WORD + && GET_CODE (value) == SYMBOL_REF + && SYMBOL_REF_FUNCTION_P (value)) + { + fputs ("\t.long\t", asm_out_file); + output_addr_const (asm_out_file, value); + fputs ("@FUNCDESC\n", asm_out_file); + return true; + } + return default_assemble_integer (value, size, aligned_p); +} + /* Check if PAT includes UNSPEC_CALLER unspec pattern. */ static bool @@ -2721,15 +2800,27 @@ sh_cannot_copy_insn_p (rtx insn) { rtx pat; - if (!reload_completed || !flag_pic) - return false; - if (!NONJUMP_INSN_P (insn)) return false; if (asm_noperands (insn) >= 0) return false; pat = PATTERN (insn); + if (GET_CODE (pat) == CLOBBER || GET_CODE (pat) == USE) + return false; + + if (TARGET_FDPIC + && GET_CODE (pat) == PARALLEL) + { + rtx t = XVECEXP (pat, 0, XVECLEN (pat, 0) - 1); + if (GET_CODE (t) == USE + && unspec_caller_rtx_p (XEXP (t, 0))) + return true; + } + + if (!reload_completed || (!flag_pic && !TARGET_FDPIC)) + return false; + if (GET_CODE (pat) != SET) return false; pat = SET_SRC (pat); @@ -3261,6 +3352,7 @@ expand_ashiftrt (rtx *operands) rtx wrk; char func[18]; int value; + rtx lab; if (TARGET_SH3) { @@ -3326,8 +3418,8 @@ expand_ashiftrt (rtx *operands) /* Load the value into an arg reg and call a helper. */ emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); sprintf (func, "__ashiftrt_r4_%d", value); - function_symbol (wrk, func, SFUNC_STATIC); - emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk)); + function_symbol (wrk, func, SFUNC_STATIC, &lab); + emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk, lab)); emit_move_insn (operands[0], gen_rtx_REG (SImode, 4)); return 1; } @@ -7096,7 +7188,9 @@ sh_expand_prologue (void) else push_regs (&live_regs_mask, current_function_interrupt); - if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) + if (flag_pic + && !TARGET_FDPIC + && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) emit_insn (gen_GOTaddr2picreg ()); if (SHMEDIA_REGS_STACK_ADJUST ()) @@ -7106,7 +7200,7 @@ sh_expand_prologue (void) function_symbol (gen_rtx_REG (Pmode, R0_REG), (TARGET_FPU_ANY ? "__GCC_push_shmedia_regs" - : "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT); + : "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT, NULL); emit_insn (gen_shmedia_save_restore_regs_compact (GEN_INT (-SHMEDIA_REGS_STACK_ADJUST ()))); } @@ -7128,7 +7222,7 @@ sh_expand_prologue (void) /* This must NOT go through the PLT, otherwise mach and macl may be clobbered. */ function_symbol (gen_rtx_REG (Pmode, R0_REG), - "__GCC_shcompact_incoming_args", SFUNC_GOT); + "__GCC_shcompact_incoming_args", SFUNC_GOT, NULL); emit_insn (gen_shcompact_incoming_args ()); } } @@ -7207,7 +7301,7 @@ sh_expand_epilogue (bool sibcall_p) function_symbol (gen_rtx_REG (Pmode, R0_REG), (TARGET_FPU_ANY ? "__GCC_pop_shmedia_regs" - : "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT); + : "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT, NULL); /* This must NOT go through the PLT, otherwise mach and macl may be clobbered. */ emit_insn (gen_shmedia_save_restore_regs_compact @@ -9582,7 +9676,9 @@ nonpic_symbol_mentioned_p (rtx x) || XINT (x, 1) == UNSPEC_TPOFF || XINT (x, 1) == UNSPEC_PLT || XINT (x, 1) == UNSPEC_SYMOFF - || XINT (x, 1) == UNSPEC_PCREL_SYMOFF)) + || XINT (x, 1) == UNSPEC_PCREL_SYMOFF + || XINT (x, 1) == UNSPEC_GOTFUNCDESC + || XINT (x, 1) == UNSPEC_GOTOFFFUNCDESC)) return 0; fmt = GET_RTX_FORMAT (GET_CODE (x)); @@ -9618,7 +9714,26 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, if (reg == 0) reg = gen_reg_rtx (Pmode); - emit_insn (gen_symGOTOFF2reg (reg, orig)); + if (TARGET_FDPIC + && GET_CODE (orig) == SYMBOL_REF + && SYMBOL_REF_FUNCTION_P (orig)) + { + /* Weak functions may be NULL which doesn't work with + GOTOFFFUNCDESC because the runtime offset is not known. */ + if (SYMBOL_REF_WEAK (orig)) + emit_insn (gen_symGOTFUNCDESC2reg (reg, orig)); + else + emit_insn (gen_symGOTOFFFUNCDESC2reg (reg, orig)); + } + else if (TARGET_FDPIC + && (GET_CODE (orig) == LABEL_REF + || (GET_CODE (orig) == SYMBOL_REF + && SYMBOL_REF_DECL (orig) + && TREE_READONLY (SYMBOL_REF_DECL (orig))))) + /* In FDPIC, GOTOFF can only be used for writable data. */ + emit_insn (gen_symGOT2reg (reg, orig)); + else + emit_insn (gen_symGOTOFF2reg (reg, orig)); return reg; } else if (GET_CODE (orig) == SYMBOL_REF) @@ -9626,7 +9741,10 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, if (reg == 0) reg = gen_reg_rtx (Pmode); - emit_insn (gen_symGOT2reg (reg, orig)); + if (TARGET_FDPIC && SYMBOL_REF_FUNCTION_P (orig)) + emit_insn (gen_symGOTFUNCDESC2reg (reg, orig)); + else + emit_insn (gen_symGOT2reg (reg, orig)); return reg; } return orig; @@ -9686,6 +9804,23 @@ sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) return x; } +static rtx +sh_delegitimize_address (rtx orig_x) +{ + rtx x = orig_x; + + if (GET_CODE (x) != MEM) + return orig_x; + + x = XEXP (x, 0); + if (GET_CODE (x) == UNSPEC + && XINT (x, 1) == UNSPEC_SYMOFF + && GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF) + return XVECEXP (x, 0, 0); + + return orig_x; +} + /* Attempt to replace *P, which is an address that needs reloading, with a valid memory address for an operand of mode MODE. Like for sh_legitimize_address, for the SH we try to get a normal form @@ -10698,20 +10833,40 @@ sh_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt) emit_insn (gen_initialize_trampoline (tramp, cxt, fnaddr)); return; } - emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX), - gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301, - SImode)); - emit_move_insn (adjust_address (tramp_mem, SImode, 4), - gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009, - SImode)); - emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt); - emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr); + if (TARGET_FDPIC) + { + rtx a = force_reg (Pmode, plus_constant (XEXP (tramp_mem, 0), 8)); + emit_move_insn (adjust_address (tramp_mem, SImode, 0), a); + emit_move_insn (adjust_address (tramp_mem, SImode, 4), OUR_FDPIC_REG); + emit_move_insn (adjust_address (tramp_mem, SImode, 8), + gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd203d302 : 0xd302d203, + SImode)); + emit_move_insn (adjust_address (tramp_mem, SImode, 12), + gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x5c216122 : 0x61225c21, + SImode)); + emit_move_insn (adjust_address (tramp_mem, SImode, 16), + gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009412b : 0x412b0009, + SImode)); + emit_move_insn (adjust_address (tramp_mem, SImode, 20), cxt); + emit_move_insn (adjust_address (tramp_mem, SImode, 24), fnaddr); + } + else + { + emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX), + gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301, + SImode)); + emit_move_insn (adjust_address (tramp_mem, SImode, 4), + gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009, + SImode)); + emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt); + emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr); + } if (TARGET_HARVARD) { if (!TARGET_INLINE_IC_INVALIDATE || (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE)) emit_library_call (function_symbol (NULL, "__ic_invalidate", - FUNCTION_ORDINARY), + FUNCTION_ORDINARY, NULL), LCT_NORMAL, VOIDmode, 1, tramp, SImode); else emit_insn (gen_ic_invalidate_line (tramp)); @@ -11539,10 +11694,18 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, sibcall = gen_sibcalli_thunk (funexp, const0_rtx); else #endif - if (TARGET_SH2 && flag_pic) + if (TARGET_SH2 && (flag_pic || TARGET_FDPIC)) { - sibcall = gen_sibcall_pcrel (funexp, const0_rtx); - XEXP (XVECEXP (sibcall, 0, 2), 0) = scratch2; + if (TARGET_FDPIC) + { + sibcall = gen_sibcall_pcrel_fdpic (funexp, const0_rtx); + XEXP (XVECEXP (sibcall, 0, 3), 0) = scratch2; + } + else + { + sibcall = gen_sibcall_pcrel (funexp, const0_rtx); + XEXP (XVECEXP (sibcall, 0, 2), 0) = scratch2; + } } else { @@ -11588,11 +11751,24 @@ sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, epilogue_completed = 0; } +/* Return an RTX for the address of a function NAME of kind KIND, + placing the result in TARGET if not NULL. LAB should be non-NULL + for SFUNC_STATIC, if FDPIC; it will be set to (const_int 0) if jsr + should be used, or a label_ref if bsrf should be used. For FDPIC, + both SFUNC_GOT and SFUNC_STATIC will return the address of the + function itself, not a function descriptor, so they can only be + used with functions not using the FDPIC register that are known to + be called directory without a PLT entry. */ + rtx -function_symbol (rtx target, const char *name, enum sh_function_kind kind) +function_symbol (rtx target, const char *name, enum sh_function_kind kind, + rtx *lab) { rtx sym; + if (lab) + *lab = const0_rtx; + /* If this is not an ordinary function, the name usually comes from a string literal or an sprintf buffer. Make sure we use the same string consistently, so that cse will be able to unify address loads. */ @@ -11600,7 +11776,7 @@ function_symbol (rtx target, const char *name, enum sh_function_kind kind) name = IDENTIFIER_POINTER (get_identifier (name)); sym = gen_rtx_SYMBOL_REF (Pmode, name); SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION; - if (flag_pic) + if (flag_pic || TARGET_FDPIC) switch (kind) { case FUNCTION_ORDINARY: @@ -11615,14 +11791,27 @@ function_symbol (rtx target, const char *name, enum sh_function_kind kind) } case SFUNC_STATIC: { - /* ??? To allow cse to work, we use GOTOFF relocations. - we could add combiner patterns to transform this into - straight pc-relative calls with sym2PIC / bsrf when - label load and function call are still 1:1 and in the - same basic block during combine. */ rtx reg = target ? target : gen_reg_rtx (Pmode); - emit_insn (gen_symGOTOFF2reg (reg, sym)); + if (TARGET_FDPIC) + { + /* We use PC-relative calls, since GOTOFF can only refer + to writable data. This works along with + sh_sfunc_call. */ + gcc_assert (lab != NULL); + *lab = PATTERN (gen_call_site ()); + emit_insn (gen_sym_label2reg (reg, sym, *lab)); + } + else + { + /* ??? To allow cse to work, we use GOTOFF relocations. + we could add combiner patterns to transform this into + straight pc-relative calls with sym2PIC / bsrf when + label load and function call are still 1:1 and in the + same basic block during combine. */ + emit_insn (gen_symGOTOFF2reg (reg, sym)); + } + sym = reg; break; } @@ -12268,4 +12457,83 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT; +bool +sh_legitimate_constant_p (rtx x) +{ + if (SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P) + { + rtx base, offset; + + split_const (x, &base, &offset); + if (GET_CODE (base) == SYMBOL_REF + && !offset_within_block_p (base, INTVAL (offset))) + return false; + } + + if (TARGET_FDPIC + && (SYMBOLIC_CONST_P (x) + || (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS + && SYMBOLIC_CONST_P (XEXP (XEXP (x, 0), 0))))) + return false; + + if (TARGET_SHMEDIA) + return ((GET_MODE (x) != DFmode + && GET_MODE_CLASS (GET_MODE (x)) != MODE_VECTOR_FLOAT) + || (x) == CONST0_RTX (GET_MODE (x)) + || ! TARGET_SHMEDIA_FPU + || TARGET_SHMEDIA64); + + return (GET_CODE (x) != CONST_DOUBLE + || GET_MODE (x) == DFmode || GET_MODE (x) == SFmode + || GET_MODE (x) == DImode || GET_MODE (x) == VOIDmode); +} + +bool +sh_cannot_force_const_mem_p (rtx x ATTRIBUTE_UNUSED) +{ + if (TARGET_FDPIC) + return true; + + return false; +} + +/* Emit insns to load the function address from FUNCDESC (an FDPIC + function descriptor) into r1 and the GOT address into r12, + returning an rtx for r1. */ + +rtx +sh_load_function_descriptor (rtx funcdesc) +{ + rtx r1 = gen_rtx_REG (Pmode, R1_REG); + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + rtx fnaddr = gen_rtx_MEM (Pmode, funcdesc); + rtx gotaddr = gen_rtx_MEM (Pmode, plus_constant (funcdesc, 4)); + + emit_move_insn (r1, fnaddr); + /* The ABI requires the entry point address to be loaded first, so + prevent the load from being moved after that of the GOT + address. */ + emit_insn (gen_blockage ()); + emit_move_insn (pic_reg, gotaddr); + return r1; +} + +/* Return an rtx holding the initial value of the FDPIC register (the + FDPIC pointer passed in from the caller). */ + +rtx +sh_our_fdpic_reg (void) +{ + return get_hard_reg_initial_val (Pmode, PIC_REG); +} + +/* Relocatable data for FDPIC binaries is not permitted in read-only + segments. */ + +static int +sh_reloc_rw_mask (void) +{ + return (flag_pic || TARGET_FDPIC) ? 3 : 0; +} + #include "gt-sh.h" diff --git a/src/gcc-mainline/gcc/config/sh/sh.h b/src/gcc-mainline/gcc/config/sh/sh.h index ee3e059..531238e 100644 --- a/src/gcc-mainline/gcc/config/sh/sh.h +++ b/src/gcc-mainline/gcc/config/sh/sh.h @@ -94,6 +94,11 @@ do { \ builtin_define ("__HITACHI__"); \ if (TARGET_FMOVD) \ builtin_define ("__FMOVD_ENABLED__"); \ + if (TARGET_FDPIC) \ + { \ + builtin_define ("__SH_FDPIC__"); \ + builtin_define ("__FDPIC__"); \ + } \ builtin_define (TARGET_LITTLE_ENDIAN \ ? "__LITTLE_ENDIAN__" : "__BIG_ENDIAN__"); \ } while (0) @@ -133,6 +138,12 @@ do { \ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ } \ + if (TARGET_FDPIC) \ + { \ + fixed_regs[PIC_REG] = 1; \ + call_used_regs[PIC_REG] = 1; \ + call_really_used_regs[PIC_REG] = 1; \ + } \ /* Renesas saves and restores mac registers on call. */ \ if (TARGET_HITACHI && ! TARGET_NOMACSAVE) \ { \ @@ -468,7 +479,9 @@ do { \ #define SH_DIV_STR_FOR_SIZE "call" #endif -#define DRIVER_SELF_SPECS "%{m2a:%{ml:%eSH2a does not support little-endian}}" +#define DRIVER_SELF_SPECS SUBTARGET_DRIVER_SELF_SPECS \ + "%{m2a:%{ml:%eSH2a does not support little-endian}}" +#define SUBTARGET_DRIVER_SELF_SPECS #define OPTIMIZATION_OPTIONS(LEVEL,SIZE) sh_optimization_options (LEVEL, SIZE) @@ -1007,6 +1020,14 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ code access to data items. */ #define PIC_OFFSET_TABLE_REGNUM (flag_pic ? PIC_REG : INVALID_REGNUM) +/* For FDPIC, the FDPIC register is call-clobbered (otherwise PLT + entries would need to handle saving and restoring it). */ +#define PIC_OFFSET_TABLE_REG_CALL_CLOBBERED TARGET_FDPIC + +/* An rtx holding the initial value of the FDPIC register (the FDPIC + pointer passed in from the caller). */ +#define OUR_FDPIC_REG sh_our_fdpic_reg () + #define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_" /* Definitions for register eliminations. @@ -1790,7 +1811,8 @@ struct sh_args { 6 000c 00000000 l2: .long function */ /* Length in units of the trampoline for entering a nested function. */ -#define TRAMPOLINE_SIZE (TARGET_SHMEDIA64 ? 40 : TARGET_SH5 ? 24 : 16) +#define TRAMPOLINE_SIZE \ + (TARGET_SHMEDIA64 ? 40 : TARGET_SH5 ? 24 : TARGET_FDPIC ? 32 : 16) /* Alignment required for a trampoline in bits . */ #define TRAMPOLINE_ALIGNMENT \ @@ -1851,6 +1873,10 @@ struct sh_args { || GENERAL_REGISTER_P ((unsigned) reg_renumber[(REGNO)])) \ : (REGNO) == R0_REG || (unsigned) reg_renumber[(REGNO)] == R0_REG) +/* True if SYMBOL + OFFSET constants must refer to something within + SYMBOL's section. */ +#define SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 0 + /* Maximum number of registers that can appear in a valid memory address. */ @@ -1863,16 +1889,7 @@ struct sh_args { /* Nonzero if the constant value X is a legitimate general operand. */ /* can_store_by_pieces constructs VOIDmode CONST_DOUBLEs. */ -#define LEGITIMATE_CONSTANT_P(X) \ - (TARGET_SHMEDIA \ - ? ((GET_MODE (X) != DFmode \ - && GET_MODE_CLASS (GET_MODE (X)) != MODE_VECTOR_FLOAT) \ - || (X) == CONST0_RTX (GET_MODE (X)) \ - || ! TARGET_SHMEDIA_FPU \ - || TARGET_SHMEDIA64) \ - : (GET_CODE (X) != CONST_DOUBLE \ - || GET_MODE (X) == DFmode || GET_MODE (X) == SFmode \ - || GET_MODE (X) == DImode || GET_MODE (X) == VOIDmode)) +#define LEGITIMATE_CONSTANT_P(X) sh_legitimate_constant_p (X) /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. @@ -2529,6 +2546,14 @@ struct sh_args { output_addr_const (STREAM, XVECEXP (X, 0, 1)); \ fputs ("-.)", STREAM); \ break; \ + case UNSPEC_GOTFUNCDESC: \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + fputs ("@GOTFUNCDESC", (STREAM)); \ + break; \ + case UNSPEC_GOTOFFFUNCDESC: \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + fputs ("@GOTOFFFUNCDESC", (STREAM)); \ + break; \ default: \ goto FAIL; \ } \ @@ -2674,12 +2699,20 @@ extern int current_function_interrupt; #define EH_RETURN_STACKADJ_REGNO STATIC_CHAIN_REGNUM #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO) +#ifdef __SH_FDPIC__ +#define CRT_GET_RFIB_DATA(dbase) \ + ({ register int r12 __asm__("r12"); (dbase) = r12; }) +#endif + /* We have to distinguish between code and data, so that we apply datalabel where and only where appropriate. Use sdataN for data. */ #define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ - ((flag_pic && (GLOBAL) ? DW_EH_PE_indirect : 0) \ - | (flag_pic ? DW_EH_PE_pcrel : DW_EH_PE_absptr) \ - | ((CODE) ? 0 : (TARGET_SHMEDIA64 ? DW_EH_PE_sdata8 : DW_EH_PE_sdata4))) + ((TARGET_FDPIC \ + ? ((GLOBAL) ? DW_EH_PE_indirect | DW_EH_PE_datarel \ + : DW_EH_PE_pcrel) \ + : ((flag_pic && (GLOBAL) ? DW_EH_PE_indirect : 0) \ + | (flag_pic ? DW_EH_PE_pcrel : DW_EH_PE_absptr))) \ + | ((CODE) ? 0 : (TARGET_SHMEDIA64 ? DW_EH_PE_sdata8 : DW_EH_PE_sdata4))) /* Handle special EH pointer encodings. Absolute, pc-relative, and indirect are handled automatically. */ @@ -2692,6 +2725,17 @@ extern int current_function_interrupt; SYMBOL_REF_FLAGS (ADDR) |= SYMBOL_FLAG_FUNCTION; \ if (0) goto DONE; \ } \ + if (TARGET_FDPIC \ + && ((ENCODING) & 0xf0) == (DW_EH_PE_indirect | DW_EH_PE_datarel)) \ + { \ + fputs ("\t.ualong ", FILE); \ + output_addr_const (FILE, ADDR); \ + if (GET_CODE (ADDR) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (ADDR)) \ + fputs ("@GOTFUNCDESC", FILE); \ + else \ + fputs ("@GOT", FILE); \ + goto DONE; \ + } \ } while (0) #if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__ diff --git a/src/gcc-mainline/gcc/config/sh/sh.md b/src/gcc-mainline/gcc/config/sh/sh.md index 495e151..5f9d16d 100644 --- a/src/gcc-mainline/gcc/config/sh/sh.md +++ b/src/gcc-mainline/gcc/config/sh/sh.md @@ -99,6 +99,7 @@ (R8_REG 8) (R9_REG 9) (R10_REG 10) + (R12_REG 12) (R20_REG 20) (R21_REG 21) (R22_REG 22) @@ -165,6 +166,10 @@ ;; (unspec [OFFSET ANCHOR] UNSPEC_PCREL_SYMOFF) == OFFSET - (ANCHOR - .). (UNSPEC_PCREL_SYMOFF 46) + (UNSPEC_GOTFUNCDESC 50) + (UNSPEC_GOTOFFFUNCDESC 51) + (UNSPEC_INITVAL 52) + ;; These are used with unspec_volatile. (UNSPECV_BLOCKAGE 0) (UNSPECV_ALIGN 1) @@ -1602,14 +1607,17 @@ ;; If we let reload allocate r0, then this problem can never happen. (define_insn "udivsi3_i1" - [(set (match_operand:SI 0 "register_operand" "=z") + [(set (match_operand:SI 0 "register_operand" "=z,z") (udiv:SI (reg:SI R4_REG) (reg:SI R5_REG))) (clobber (reg:SI T_REG)) (clobber (reg:SI PR_REG)) (clobber (reg:SI R4_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "TARGET_SH1 && ! TARGET_SH4" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) @@ -1659,7 +1667,7 @@ }") (define_insn "udivsi3_i4" - [(set (match_operand:SI 0 "register_operand" "=y") + [(set (match_operand:SI 0 "register_operand" "=y,y") (udiv:SI (reg:SI R4_REG) (reg:SI R5_REG))) (clobber (reg:SI T_REG)) (clobber (reg:SI PR_REG)) @@ -1671,15 +1679,18 @@ (clobber (reg:SI R4_REG)) (clobber (reg:SI R5_REG)) (use (reg:PSI FPSCR_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "TARGET_SH4 && ! TARGET_FPU_SINGLE" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "fp_mode" "double") (set_attr "needs_delay_slot" "yes")]) (define_insn "udivsi3_i4_single" - [(set (match_operand:SI 0 "register_operand" "=y") + [(set (match_operand:SI 0 "register_operand" "=y,y") (udiv:SI (reg:SI R4_REG) (reg:SI R5_REG))) (clobber (reg:SI T_REG)) (clobber (reg:SI PR_REG)) @@ -1690,9 +1701,12 @@ (clobber (reg:SI R1_REG)) (clobber (reg:SI R4_REG)) (clobber (reg:SI R5_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) @@ -1747,16 +1761,17 @@ emit_move_insn (operands[0], operands[2]); DONE; } - function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT); + function_symbol (operands[3], \"__udivsi3_i4i\", SFUNC_GOT, NULL); last = gen_udivsi3_i4_int (operands[0], operands[3]); } else if (TARGET_DIVIDE_CALL_FP) { - function_symbol (operands[3], \"__udivsi3_i4\", SFUNC_STATIC); + rtx lab; + function_symbol (operands[3], \"__udivsi3_i4\", SFUNC_STATIC, &lab); if (TARGET_FPU_SINGLE) - last = gen_udivsi3_i4_single (operands[0], operands[3]); + last = gen_udivsi3_i4_single (operands[0], operands[3], lab); else - last = gen_udivsi3_i4 (operands[0], operands[3]); + last = gen_udivsi3_i4 (operands[0], operands[3], lab); } else if (TARGET_SHMEDIA_FPU) { @@ -1776,19 +1791,20 @@ { function_symbol (operands[3], TARGET_FPU_ANY ? \"__udivsi3_i4\" : \"__udivsi3\", - SFUNC_STATIC); + SFUNC_STATIC, NULL); if (TARGET_SHMEDIA) last = gen_udivsi3_i1_media (operands[0], operands[3]); else if (TARGET_FPU_ANY) - last = gen_udivsi3_i4_single (operands[0], operands[3]); + last = gen_udivsi3_i4_single (operands[0], operands[3], const0_rtx); else - last = gen_udivsi3_i1 (operands[0], operands[3]); + last = gen_udivsi3_i1 (operands[0], operands[3], const0_rtx); } else { - function_symbol (operands[3], \"__udivsi3\", SFUNC_STATIC); - last = gen_udivsi3_i1 (operands[0], operands[3]); + rtx lab; + function_symbol (operands[3], \"__udivsi3\", SFUNC_STATIC, &lab); + last = gen_udivsi3_i1 (operands[0], operands[3], lab); } emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); emit_move_insn (gen_rtx_REG (SImode, 5), operands[2]); @@ -1917,7 +1933,7 @@ emit_move_insn (gen_rtx_REG (DImode, R20_REG), x); break; } - sym = function_symbol (NULL, name, kind); + sym = function_symbol (NULL, name, kind, NULL); emit_insn (gen_divsi3_media_2 (operands[0], sym)); DONE; }" @@ -1938,29 +1954,35 @@ }") (define_insn "divsi3_i4" - [(set (match_operand:SI 0 "register_operand" "=y") + [(set (match_operand:SI 0 "register_operand" "=y,y") (div:SI (reg:SI R4_REG) (reg:SI R5_REG))) (clobber (reg:SI PR_REG)) (clobber (reg:DF DR0_REG)) (clobber (reg:DF DR2_REG)) (use (reg:PSI FPSCR_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "TARGET_SH4 && ! TARGET_FPU_SINGLE" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "fp_mode" "double") (set_attr "needs_delay_slot" "yes")]) (define_insn "divsi3_i4_single" - [(set (match_operand:SI 0 "register_operand" "=y") + [(set (match_operand:SI 0 "register_operand" "=y,y") (div:SI (reg:SI R4_REG) (reg:SI R5_REG))) (clobber (reg:SI PR_REG)) (clobber (reg:DF DR0_REG)) (clobber (reg:DF DR2_REG)) (clobber (reg:SI R2_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) @@ -2000,16 +2022,17 @@ /* Emit the move of the address to a pseudo outside of the libcall. */ if (TARGET_DIVIDE_CALL_TABLE) { - function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT); + function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL); last = gen_divsi3_i4_int (operands[0], operands[3]); } else if (TARGET_DIVIDE_CALL_FP) { - function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC); + rtx lab; + function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC, &lab); if (TARGET_FPU_SINGLE) - last = gen_divsi3_i4_single (operands[0], operands[3]); + last = gen_divsi3_i4_single (operands[0], operands[3], lab); else - last = gen_divsi3_i4 (operands[0], operands[3]); + last = gen_divsi3_i4 (operands[0], operands[3], lab); } else if (TARGET_SH2A) { @@ -2114,23 +2137,23 @@ emit_move_insn (gen_rtx_REG (Pmode, R20_REG), tab_base); } if (TARGET_FPU_ANY && TARGET_SH1) - function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC); + function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_STATIC, NULL); else if (TARGET_DIVIDE_CALL2) - function_symbol (operands[3], \"__sdivsi3_2\", SFUNC_STATIC); + function_symbol (operands[3], \"__sdivsi3_2\", SFUNC_STATIC, NULL); else - function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT); + function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL); if (TARGET_SHMEDIA) last = ((TARGET_DIVIDE_CALL2 ? gen_divsi3_media_2 : gen_divsi3_i1_media) (operands[0], operands[3])); else if (TARGET_FPU_ANY) - last = gen_divsi3_i4_single (operands[0], operands[3]); + last = gen_divsi3_i4_single (operands[0], operands[3], const0_rtx); else last = gen_divsi3_i1 (operands[0], operands[3]); } else { - function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT); + function_symbol (operands[3], sh_divsi3_libfunc, SFUNC_GOT, NULL); last = gen_divsi3_i1 (operands[0], operands[3]); } emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); @@ -2722,7 +2745,7 @@ label: { /* The address must be set outside the libcall, since it goes into a pseudo. */ - rtx sym = function_symbol (NULL, \"__mulsi3\", SFUNC_STATIC); + rtx sym = function_symbol (NULL, \"__mulsi3\", SFUNC_STATIC, NULL); rtx addr = force_reg (SImode, sym); rtx insns = gen_mulsi3_call (operands[0], operands[1], operands[2], addr); @@ -3693,12 +3716,15 @@ label: (define_insn "ashrsi3_n" [(set (reg:SI R4_REG) (ashiftrt:SI (reg:SI R4_REG) - (match_operand:SI 0 "const_int_operand" "i"))) + (match_operand:SI 0 "const_int_operand" "i,i"))) (clobber (reg:SI T_REG)) (clobber (reg:SI PR_REG)) - (use (match_operand:SI 1 "arith_reg_operand" "r"))] + (use (match_operand:SI 1 "arith_reg_operand" "r,r")) + (use (match_operand 2 "" "Z,Ccl"))] "TARGET_SH1" - "jsr @%1%#" + "@ + jsr @%1%# + bsrf %1\\n%O2:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) @@ -5132,7 +5158,8 @@ label: } else if (TARGET_SHCOMPACT) { - operands[1] = function_symbol (NULL, \"__ic_invalidate\", SFUNC_STATIC); + operands[1] = function_symbol (NULL, \"__ic_invalidate\", SFUNC_STATIC, + NULL); operands[1] = force_reg (Pmode, operands[1]); emit_insn (gen_ic_invalidate_line_compact (operands[0], operands[1])); DONE; @@ -5201,7 +5228,7 @@ label: tramp = force_reg (Pmode, operands[0]); sfun = force_reg (Pmode, function_symbol (NULL, \"__init_trampoline\", - SFUNC_STATIC)); + SFUNC_STATIC, NULL)); emit_move_insn (gen_rtx_REG (SImode, R2_REG), operands[1]); emit_move_insn (gen_rtx_REG (SImode, R3_REG), operands[2]); @@ -7141,7 +7168,29 @@ label: (match_operand 1 "" "")) (use (reg:PSI FPSCR_REG)) (clobber (reg:SI PR_REG))] - "TARGET_SH1" + "TARGET_SH1 && !TARGET_FDPIC" + "* + { + if (TARGET_SH2A && (dbr_sequence_length () == 0)) + return \"jsr/n\\t@%0\"; + else + return \"jsr\\t@%0%#\"; + }" + + [(set_attr "type" "call") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "needs_delay_slot" "yes") + (set_attr "fp_set" "unknown")]) + +(define_insn "calli_fdpic" + [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r")) + (match_operand 1 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (clobber (reg:SI PR_REG))] + "TARGET_SH1 && TARGET_FDPIC" "* { if (TARGET_SH2A && (dbr_sequence_length () == 0)) @@ -7276,7 +7325,29 @@ label: (match_operand 2 "" ""))) (use (reg:PSI FPSCR_REG)) (clobber (reg:SI PR_REG))] - "TARGET_SH1" + "TARGET_SH1 && !TARGET_FDPIC" + "* + { + if (TARGET_SH2A && (dbr_sequence_length () == 0)) + return \"jsr/n\\t@%1\"; + else + return \"jsr\\t@%1%#\"; + }" + [(set_attr "type" "call") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "needs_delay_slot" "yes") + (set_attr "fp_set" "unknown")]) + +(define_insn "call_valuei_fdpic" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r")) + (match_operand 2 "" ""))) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (clobber (reg:SI PR_REG))] + "TARGET_SH1 && TARGET_FDPIC" "* { if (TARGET_SH2A && (dbr_sequence_length () == 0)) @@ -7418,6 +7489,12 @@ label: "" " { + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } + if (TARGET_SHMEDIA) { operands[0] = shmedia_prepare_call_address (operands[0], 0); @@ -7454,7 +7531,7 @@ label: operands[0] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[0] = force_reg (SImode, operands[0]); emit_move_insn (r0, func); @@ -7478,7 +7555,7 @@ label: emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[0], 0))); XEXP (operands[0], 0) = reg; } - if (!flag_pic && TARGET_SH2A + if (!flag_pic && !TARGET_FDPIC && TARGET_SH2A && MEM_P (operands[0]) && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) { @@ -7489,7 +7566,7 @@ label: DONE; } } - if (flag_pic && TARGET_SH2 + if ((flag_pic || TARGET_FDPIC) && TARGET_SH2 && MEM_P (operands[0]) && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) { @@ -7502,7 +7579,13 @@ label: operands[1] = operands[2]; } - emit_call_insn (gen_calli (operands[0], operands[1])); + if (TARGET_FDPIC) + { + operands[0] = sh_load_function_descriptor (operands[0]); + emit_call_insn (gen_calli_fdpic (operands[0], operands[1])); + } + else + emit_call_insn (gen_calli (operands[0], operands[1])); DONE; }") @@ -7583,7 +7666,7 @@ label: emit_insn (gen_force_mode_for_call ()); operands[0] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[0] = force_reg (SImode, operands[0]); emit_move_insn (r0, func); @@ -7609,6 +7692,12 @@ label: "" " { + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } + if (TARGET_SHMEDIA) { operands[1] = shmedia_prepare_call_address (operands[1], 0); @@ -7646,7 +7735,7 @@ label: operands[1] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[1] = force_reg (SImode, operands[1]); emit_move_insn (r0, func); @@ -7672,7 +7761,7 @@ label: emit_insn (gen_symGOTPLT2reg (reg, XEXP (operands[1], 0))); XEXP (operands[1], 0) = reg; } - if (!flag_pic && TARGET_SH2A + if (!flag_pic && !TARGET_FDPIC && TARGET_SH2A && MEM_P (operands[1]) && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) { @@ -7683,7 +7772,7 @@ label: DONE; } } - if (flag_pic && TARGET_SH2 + if ((flag_pic || TARGET_FDPIC) && TARGET_SH2 && MEM_P (operands[1]) && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) { @@ -7694,7 +7783,14 @@ label: else operands[1] = force_reg (SImode, XEXP (operands[1], 0)); - emit_call_insn (gen_call_valuei (operands[0], operands[1], operands[2])); + if (TARGET_FDPIC) + { + operands[1] = sh_load_function_descriptor (operands[1]); + emit_call_insn (gen_call_valuei_fdpic (operands[0], operands[1], + operands[2])); + } + else + emit_call_insn (gen_call_valuei (operands[0], operands[1], operands[2])); DONE; }") @@ -7703,7 +7799,21 @@ label: (match_operand 1 "" "")) (use (reg:PSI FPSCR_REG)) (return)] - "TARGET_SH1" + "TARGET_SH1 && !TARGET_FDPIC" + "jmp @%0%#" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + +(define_insn "sibcalli_fdpic" + [(call (mem:SI (match_operand:SI 0 "register_operand" "k")) + (match_operand 1 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (return)] + "TARGET_SH1 && TARGET_FDPIC" "jmp @%0%#" [(set_attr "needs_delay_slot" "yes") (set (attr "fp_mode") @@ -7717,7 +7827,22 @@ label: (use (match_operand 2 "" "")) (use (reg:PSI FPSCR_REG)) (return)] - "TARGET_SH2" + "TARGET_SH2 && !TARGET_FDPIC" + "braf %0\\n%O2:%#" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + +(define_insn "sibcalli_pcrel_fdpic" + [(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "k")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (return)] + "TARGET_SH2 && TARGET_FDPIC" "braf %0\\n%O2:%#" [(set_attr "needs_delay_slot" "yes") (set (attr "fp_mode") @@ -7747,7 +7872,7 @@ label: (use (reg:PSI FPSCR_REG)) (clobber (match_scratch:SI 2 "=k")) (return)] - "TARGET_SH2" + "TARGET_SH2 && !TARGET_FDPIC" "#" "reload_completed" [(const_int 0)] @@ -7768,6 +7893,34 @@ label: (const_string "single") (const_string "double"))) (set_attr "type" "jump_ind")]) +(define_insn_and_split "sibcall_pcrel_fdpic" + [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "")) + (match_operand 1 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (clobber (match_scratch:SI 2 "=k")) + (return)] + "TARGET_SH2 && TARGET_FDPIC" + "#" + "reload_completed" + [(const_int 0)] + " +{ + rtx lab = PATTERN (gen_call_site ()); + rtx call_insn; + + emit_insn (gen_sym_label2reg (operands[2], operands[0], lab)); + call_insn = emit_call_insn (gen_sibcalli_pcrel_fdpic (operands[2], operands[1], + copy_rtx (lab))); + SIBLING_CALL_P (call_insn) = 1; + DONE; +}" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + (define_insn "sibcall_compact" [(call (mem:SI (match_operand:SI 0 "register_operand" "k,k")) (match_operand 1 "" "")) @@ -7806,6 +7959,12 @@ label: "" " { + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } + if (TARGET_SHMEDIA) { operands[0] = shmedia_prepare_call_address (operands[0], 1); @@ -7852,7 +8011,7 @@ label: operands[0] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[0] = force_reg (SImode, operands[0]); /* We don't need a return trampoline, since the callee will @@ -7878,7 +8037,7 @@ label: emit_insn (gen_symGOT2reg (reg, XEXP (operands[0], 0))); XEXP (operands[0], 0) = reg; } - if (flag_pic && TARGET_SH2 + if ((flag_pic || TARGET_FDPIC) && TARGET_SH2 && MEM_P (operands[0]) && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF /* The PLT needs the PIC register, but the epilogue would have @@ -7886,13 +8045,24 @@ label: static functions. */ && SYMBOL_REF_LOCAL_P (XEXP (operands[0], 0))) { - emit_call_insn (gen_sibcall_pcrel (XEXP (operands[0], 0), operands[1])); + if (TARGET_FDPIC) + emit_call_insn (gen_sibcall_pcrel_fdpic (XEXP (operands[0], 0), + operands[1])); + else + emit_call_insn (gen_sibcall_pcrel (XEXP (operands[0], 0), + operands[1])); DONE; } else operands[0] = force_reg (SImode, XEXP (operands[0], 0)); - emit_call_insn (gen_sibcalli (operands[0], operands[1])); + if (TARGET_FDPIC) + { + operands[0] = sh_load_function_descriptor (operands[0]); + emit_call_insn (gen_sibcalli_fdpic (operands[0], operands[1])); + } + else + emit_call_insn (gen_sibcalli (operands[0], operands[1])); DONE; }") @@ -7902,7 +8072,22 @@ label: (match_operand 2 "" ""))) (use (reg:PSI FPSCR_REG)) (return)] - "TARGET_SH1" + "TARGET_SH1 && !TARGET_FDPIC" + "jmp @%1%#" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + +(define_insn "sibcall_valuei_fdpic" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "register_operand" "k")) + (match_operand 2 "" ""))) + (use (reg:PSI FPSCR_REG)) + (use (reg:SI PIC_REG)) + (return)] + "TARGET_SH1 && TARGET_FDPIC" "jmp @%1%#" [(set_attr "needs_delay_slot" "yes") (set (attr "fp_mode") @@ -7917,7 +8102,23 @@ label: (use (match_operand 3 "" "")) (use (reg:PSI FPSCR_REG)) (return)] - "TARGET_SH2" + "TARGET_SH2 && !TARGET_FDPIC" + "braf %1\\n%O3:%#" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + +(define_insn "sibcall_valuei_pcrel_fdpic" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "arith_reg_operand" "k")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (use (reg:PSI FPSCR_REG)) + (use (reg:PSI PIC_REG)) + (return)] + "TARGET_SH2 && TARGET_FDPIC" "braf %1\\n%O3:%#" [(set_attr "needs_delay_slot" "yes") (set (attr "fp_mode") @@ -7932,7 +8133,7 @@ label: (use (reg:PSI FPSCR_REG)) (clobber (match_scratch:SI 3 "=k")) (return)] - "TARGET_SH2" + "TARGET_SH2 && !TARGET_FDPIC" "#" "reload_completed" [(const_int 0)] @@ -7946,6 +8147,39 @@ label: operands[3], operands[2], copy_rtx (lab))); + + SIBLING_CALL_P (call_insn) = 1; + DONE; +}" + [(set_attr "needs_delay_slot" "yes") + (set (attr "fp_mode") + (if_then_else (eq_attr "fpu_single" "yes") + (const_string "single") (const_string "double"))) + (set_attr "type" "jump_ind")]) + +(define_insn_and_split "sibcall_value_pcrel_fdpic" + [(set (match_operand 0 "" "=rf") + (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "")) + (match_operand 2 "" ""))) + (use (reg:PSI FPSCR_REG)) + (use (reg:PSI PIC_REG)) + (clobber (match_scratch:SI 3 "=k")) + (return)] + "TARGET_SH2 && TARGET_FDPIC" + "#" + "reload_completed" + [(const_int 0)] + " +{ + rtx lab = PATTERN (gen_call_site ()); + rtx call_insn; + + emit_insn (gen_sym_label2reg (operands[3], operands[1], lab)); + call_insn = emit_call_insn (gen_sibcall_valuei_pcrel_fdpic (operands[0], + operands[3], + operands[2], + copy_rtx (lab))); + SIBLING_CALL_P (call_insn) = 1; DONE; }" @@ -7996,6 +8230,12 @@ label: "" " { + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + } + if (TARGET_SHMEDIA) { operands[1] = shmedia_prepare_call_address (operands[1], 1); @@ -8043,7 +8283,7 @@ label: operands[1] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[1] = force_reg (SImode, operands[1]); /* We don't need a return trampoline, since the callee will @@ -8070,7 +8310,7 @@ label: emit_insn (gen_symGOT2reg (reg, XEXP (operands[1], 0))); XEXP (operands[1], 0) = reg; } - if (flag_pic && TARGET_SH2 + if ((flag_pic || TARGET_FDPIC) && TARGET_SH2 && MEM_P (operands[1]) && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF /* The PLT needs the PIC register, but the epilogue would have @@ -8078,15 +8318,28 @@ label: static functions. */ && SYMBOL_REF_LOCAL_P (XEXP (operands[1], 0))) { - emit_call_insn (gen_sibcall_value_pcrel (operands[0], - XEXP (operands[1], 0), - operands[2])); + if (TARGET_FDPIC) + emit_call_insn (gen_sibcall_value_pcrel_fdpic (operands[0], + XEXP (operands[1], 0), + operands[2])); + else + emit_call_insn (gen_sibcall_value_pcrel (operands[0], + XEXP (operands[1], 0), + operands[2])); DONE; } else operands[1] = force_reg (SImode, XEXP (operands[1], 0)); - emit_call_insn (gen_sibcall_valuei (operands[0], operands[1], operands[2])); + if (TARGET_FDPIC) + { + operands[1] = sh_load_function_descriptor (operands[1]); + emit_call_insn (gen_sibcall_valuei_fdpic (operands[0], operands[1], + operands[2])); + } + else + emit_call_insn (gen_sibcall_valuei (operands[0], operands[1], + operands[2])); DONE; }") @@ -8171,7 +8424,7 @@ label: emit_insn (gen_force_mode_for_call ()); operands[1] = function_symbol (NULL, \"__GCC_shcompact_call_trampoline\", - SFUNC_GOT); + SFUNC_GOT, NULL); operands[1] = force_reg (SImode, operands[1]); emit_move_insn (r0, func); @@ -8341,6 +8594,13 @@ label: [(set_attr "in_delay_slot" "no") (set_attr "type" "arith")]) +(define_insn_and_split "use_initial_val" + [(unspec [(match_operand 0 "pseudo_register_operand" "r")] UNSPEC_INITVAL)] + "" + "#" + "reload_completed" + [(const_int 0)]) + (define_expand "GOTaddr2picreg" [(set (reg:SI R0_REG) (unspec:SI [(const:SI (unspec:SI [(match_dup 1)] UNSPEC_PIC))] @@ -8357,6 +8617,13 @@ label: DONE; } + if (TARGET_FDPIC) + { + rtx pic_reg = gen_rtx_REG (Pmode, PIC_REG); + emit_move_insn (pic_reg, OUR_FDPIC_REG); + DONE; + } + operands[0] = gen_rtx_REG (Pmode, PIC_REG); operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME); @@ -8469,8 +8736,14 @@ label: "" " { + rtx picreg; rtx mem; + if (TARGET_FDPIC) + picreg = OUR_FDPIC_REG; + else + picreg = gen_rtx_REG (Pmode, PIC_REG); + operands[2] = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode); operands[3] = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode); @@ -8479,7 +8752,7 @@ label: rtx reg = operands[2]; if (Pmode == DImode) - { + { if (flag_pic > 1) emit_insn (gen_movdi_const_32bit (reg, operands[1])); else @@ -8496,9 +8769,7 @@ label: else emit_move_insn (operands[2], operands[1]); - emit_move_insn (operands[3], gen_rtx_PLUS (Pmode, - operands[2], - gen_rtx_REG (Pmode, PIC_REG))); + emit_move_insn (operands[3], gen_rtx_PLUS (Pmode, operands[2], picreg)); /* When stack protector inserts codes after the result is set to R0, @(rX, r12) will cause a spill failure for R0. Don't schedule @@ -8544,6 +8815,27 @@ label: DONE; }") +(define_expand "sym2GOTFUNCDESC" + [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTFUNCDESC))] + "TARGET_FDPIC" + "") + +(define_expand "symGOTFUNCDESC2reg" + [(match_operand 0 "" "") (match_operand 1 "" "")] + "TARGET_FDPIC" + " +{ + rtx gotsym, insn; + + gotsym = gen_sym2GOTFUNCDESC (operands[1]); + PUT_MODE (gotsym, Pmode); + insn = emit_insn (gen_symGOT_load (operands[0], gotsym)); + + MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1; + + DONE; +}") + (define_expand "symGOTPLT2reg" [(match_operand 0 "" "") (match_operand 1 "" "")] "" @@ -8567,23 +8859,50 @@ label: "" " { + rtx picreg; rtx gotoffsym, insn; rtx t = (!can_create_pseudo_p () ? operands[0] : gen_reg_rtx (GET_MODE (operands[0]))); + if (TARGET_FDPIC) + picreg = OUR_FDPIC_REG; + else + picreg = gen_rtx_REG (Pmode, PIC_REG); + gotoffsym = gen_sym2GOTOFF (operands[1]); PUT_MODE (gotoffsym, Pmode); emit_move_insn (t, gotoffsym); - insn = emit_move_insn (operands[0], - gen_rtx_PLUS (Pmode, t, - gen_rtx_REG (Pmode, PIC_REG))); + insn = emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg)); set_unique_reg_note (insn, REG_EQUAL, operands[1]); DONE; }") +(define_expand "sym2GOTOFFFUNCDESC" + [(const (unspec [(match_operand 0 "" "")] UNSPEC_GOTOFFFUNCDESC))] + "TARGET_FDPIC" + "") + +(define_expand "symGOTOFFFUNCDESC2reg" + [(match_operand 0 "" "") (match_operand 1 "" "")] + "TARGET_FDPIC" + " +{ + rtx picreg = OUR_FDPIC_REG; + rtx gotoffsym; + rtx t = (!can_create_pseudo_p () + ? operands[0] + : gen_reg_rtx (GET_MODE (operands[0]))); + + gotoffsym = gen_sym2GOTOFFFUNCDESC (operands[1]); + PUT_MODE (gotoffsym, Pmode); + emit_move_insn (t, gotoffsym); + emit_move_insn (operands[0], gen_rtx_PLUS (Pmode, t, picreg)); + DONE; +}") + (define_expand "symPLT_label2reg" [(set (match_operand:SI 0 "" "") (const:SI @@ -9059,7 +9378,8 @@ mov.l\\t1f,r0\\n\\ { rtx reg = gen_rtx_REG (Pmode, R0_REG); - function_symbol (reg, \"__GCC_shcompact_return_trampoline\", SFUNC_STATIC); + function_symbol (reg, \"__GCC_shcompact_return_trampoline\", SFUNC_STATIC, + NULL); emit_jump_insn (gen_shcompact_return_tramp_i ()); DONE; }") @@ -9602,18 +9922,22 @@ mov.l\\t1f,r0\\n\\ (define_insn "block_move_real" [(parallel [(set (mem:BLK (reg:SI R4_REG)) (mem:BLK (reg:SI R5_REG))) - (use (match_operand:SI 0 "arith_reg_operand" "r")) + (use (match_operand:SI 0 "arith_reg_operand" "r,r")) + (use (match_operand 1 "" "Z,Ccl")) (clobber (reg:SI PR_REG)) (clobber (reg:SI R0_REG))])] "TARGET_SH1 && ! TARGET_HARD_SH4" - "jsr @%0%#" + "@ + jsr @%0%# + bsrf %0\\n%O1:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) (define_insn "block_lump_real" [(parallel [(set (mem:BLK (reg:SI R4_REG)) (mem:BLK (reg:SI R5_REG))) - (use (match_operand:SI 0 "arith_reg_operand" "r")) + (use (match_operand:SI 0 "arith_reg_operand" "r,r")) + (use (match_operand 1 "" "Z,Ccl")) (use (reg:SI R6_REG)) (clobber (reg:SI PR_REG)) (clobber (reg:SI T_REG)) @@ -9622,27 +9946,33 @@ mov.l\\t1f,r0\\n\\ (clobber (reg:SI R6_REG)) (clobber (reg:SI R0_REG))])] "TARGET_SH1 && ! TARGET_HARD_SH4" - "jsr @%0%#" + "@ + jsr @%0%# + bsrf %0\\n%O1:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) (define_insn "block_move_real_i4" [(parallel [(set (mem:BLK (reg:SI R4_REG)) (mem:BLK (reg:SI R5_REG))) - (use (match_operand:SI 0 "arith_reg_operand" "r")) + (use (match_operand:SI 0 "arith_reg_operand" "r,r")) + (use (match_operand 1 "" "Z,Ccl")) (clobber (reg:SI PR_REG)) (clobber (reg:SI R0_REG)) (clobber (reg:SI R1_REG)) (clobber (reg:SI R2_REG))])] "TARGET_HARD_SH4" - "jsr @%0%#" + "@ + jsr @%0%# + bsrf %0\\n%O1:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) (define_insn "block_lump_real_i4" [(parallel [(set (mem:BLK (reg:SI R4_REG)) (mem:BLK (reg:SI R5_REG))) - (use (match_operand:SI 0 "arith_reg_operand" "r")) + (use (match_operand:SI 0 "arith_reg_operand" "r,r")) + (use (match_operand 1 "" "Z,Ccl")) (use (reg:SI R6_REG)) (clobber (reg:SI PR_REG)) (clobber (reg:SI T_REG)) @@ -9654,7 +9984,9 @@ mov.l\\t1f,r0\\n\\ (clobber (reg:SI R2_REG)) (clobber (reg:SI R3_REG))])] "TARGET_HARD_SH4" - "jsr @%0%#" + "@ + jsr @%0%# + bsrf %0\\n%O1:%#" [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) diff --git a/src/gcc-mainline/gcc/config/sh/sh.opt b/src/gcc-mainline/gcc/config/sh/sh.opt index 95e2ca4..cae464d 100644 --- a/src/gcc-mainline/gcc/config/sh/sh.opt +++ b/src/gcc-mainline/gcc/config/sh/sh.opt @@ -248,6 +248,10 @@ mdivsi3_libfunc= Target RejectNegative Joined Var(sh_divsi3_libfunc) Init("") Specify name for 32 bit signed division function +mfdpic +Target Report Var(TARGET_FDPIC) +Generate ELF FDPIC code + mfmovd Target RejectNegative Mask(FMOVD) Enable the use of 64-bit floating point registers in fmov instructions. See -mdalign if 64-bit alignment is required. diff --git a/src/gcc-mainline/gcc/config/sh/t-uclinux b/src/gcc-mainline/gcc/config/sh/t-uclinux new file mode 100644 index 0000000..13f006a --- /dev/null +++ b/src/gcc-mainline/gcc/config/sh/t-uclinux @@ -0,0 +1,4 @@ +# Compile crtbeginS.o and crtendS.o with pic. +CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o $(OPT_EXTRA_PARTS) diff --git a/src/gcc-mainline/gcc/config/sh/uclinux.h b/src/gcc-mainline/gcc/config/sh/uclinux.h new file mode 100644 index 0000000..e02b17d --- /dev/null +++ b/src/gcc-mainline/gcc/config/sh/uclinux.h @@ -0,0 +1,96 @@ +/* Definitions for SH based uClinux system using ELF objects with + special linker post-processing to produce FLAT executables. + + Copyright (C) 2008 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{!shared:crt1.o%s} crti.o%s \ + %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" \ + FDPIC_STARTFILE_SPEC + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" + +#define LINK_EH_SPEC "%{mfdpic:%{!static:--eh-frame-hdr}} " + +#ifdef FDPIC_DEFAULT +#undef SUBTARGET_LINK_SPEC +#define SUBTARGET_LINK_SPEC \ + "%{shared:-shared} \ + %{!static: \ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} \ + %{static:-static}" +#undef SUBTARGET_LINK_EMUL_SUFFIX +#define SUBTARGET_LINK_EMUL_SUFFIX "_fd" +#undef SUBTARGET_DRIVER_SELF_SPECS +#define SUBTARGET_DRIVER_SELF_SPECS "%{!mno-fdpic:-mfdpic} " +#undef SUBTARGET_ASM_SPEC +#define SUBTARGET_ASM_SPEC "%{!mno-fdpic:--fdpic}" +#define FDPIC_STARTFILE_SPEC "%{!mno-fdpic: crtreloc.o%s}" +#else +#undef SUBTARGET_LINK_SPEC +#define SUBTARGET_LINK_SPEC "%{shared:-shared} %{static:-static} %{!elf2flt*:-elf2flt}" +#undef SUBTARGET_LINK_EMUL_SUFFIX +#define SUBTARGET_LINK_EMUL_SUFFIX "_uclinux" +#define FDPIC_STARTFILE_SPEC "%{mfdpic: crtreloc.o%s}" +#endif + +/* While the speed-optimized implementations of udivsi3_i4i / sdivsi3_i4i + in libgcc are not available for SH2, the space-optimized ones in + libgcc-Os-4-200 are. Thus, when not optimizing for space, link + libgcc-Os-4-200 after libgcc, so that -mdiv=call-table works for -m2. */ +#undef LIBGCC_SPEC +#define LIBGCC_SPEC "%{Os: -lgcc-Os-4-200} -lgcc %{!Os: -lgcc-Os-4-200}" + +/* we have init/fini section. */ +#define HAS_INIT_SECTION + +/* Bring in standard linux defines */ +#undef TARGET_OS_CPP_BUILTINS +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__gnu_linux__"); \ + builtin_define_std ("linux"); \ + builtin_define_std ("unix"); \ + builtin_assert ("system=linux"); \ + builtin_assert ("system=unix"); \ + builtin_assert ("system=posix"); \ + builtin_define ("__uClinux__"); \ + } \ + while (0) + +/* The GNU C++ standard library requires that these macros be defined. */ +#undef CPLUSPLUS_CPP_SPEC +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)" + +/* Since libgcc is compiled with -fpic for this target, we can't use + __sdivsi3_1 as the division strategy for -O0 and -Os. */ +#undef SH_DIV_STRATEGY_DEFAULT +#define SH_DIV_STRATEGY_DEFAULT SH_DIV_CALL2 +#undef SH_DIV_STR_FOR_SIZE +#define SH_DIV_STR_FOR_SIZE "call2" + +/* The uclinux binary format relies on relocations against a segment being + within that segment. Conservatively apply this rule to individual + sections. */ +#undef SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P +#define SH_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 1 diff --git a/src/gcc-mainline/gcc/doc/install.texi b/src/gcc-mainline/gcc/doc/install.texi index fc9b988..188556a 100644 --- a/src/gcc-mainline/gcc/doc/install.texi +++ b/src/gcc-mainline/gcc/doc/install.texi @@ -1545,6 +1545,10 @@ When neither of these configure options are used, the default will be 128-bit @code{long double} when built against GNU C Library 2.4 and later, 64-bit @code{long double} otherwise. +@item --enable-fdpic +On SH uClinux systems, generate ELF FDPIC code rather than code +expected to be postprocessed into the FLT binary format. + @item --with-gmp=@var{pathname} @itemx --with-gmp-include=@var{pathname} @itemx --with-gmp-lib=@var{pathname} diff --git a/src/gcc-mainline/gcc/doc/invoke.texi b/src/gcc-mainline/gcc/doc/invoke.texi index edce703..20e8290 100644 --- a/src/gcc-mainline/gcc/doc/invoke.texi +++ b/src/gcc-mainline/gcc/doc/invoke.texi @@ -16509,6 +16509,11 @@ to generate symbols that will cause ptabs / ptrel to trap. This option is only meaningful when @option{-mno-pt-fixed} is in effect. It will then prevent cross-basic-block cse, hoisting and most scheduling of symbol loads. The default is @option{-mno-invalid-symbols}. + +@item -mfdpic +@opindex fdpic +Generate code using the FDPIC ABI for uClinux, as documented at +@w{@uref{http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt}}. @end table @node SPARC Options diff --git a/src/gcc-mainline/gcc/longlong.h b/src/gcc-mainline/gcc/longlong.h index 49daa6e..aea5dec 100644 --- a/src/gcc-mainline/gcc/longlong.h +++ b/src/gcc-mainline/gcc/longlong.h @@ -988,6 +988,34 @@ UDItype __umulsidi3 (USItype, USItype); /* This is the same algorithm as __udiv_qrnnd_c. */ #define UDIV_NEEDS_NORMALIZATION 1 +#ifdef __FDPIC__ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { \ + Wtype dummy_; \ + extern UWtype __udiv_qrnnd_16 (UWtype, UWtype) \ + __attribute__ ((visibility ("hidden"))); \ + /* r0: rn r1: qn */ /* r0: n1 r4: n0 r5: d r6: d1 */ /* r2: __m */ \ + __asm__ ( \ + "mov%M5 %5,r5\n" \ +" mov r12,%2\n" \ +" swap.w %4,r4\n" \ +" swap.w r5,r6\n" \ +" mov.l @%6,r1\n" \ +" mov.l @(4,%6),r12\n" \ +" jsr @r1\n" \ +" shll16 r6\n" \ +" swap.w r4,r4\n" \ +" mov.l @%6,r1\n" \ +" mov.l @(4,%6),r12\n" \ +" jsr @r1\n" \ +" mov %2,r12\n" \ +" swap.w r1,%0\n" \ +" or r1,%0" \ + : "=r" (q), "=&z" (r), "=&r" (dummy_) \ + : "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16) \ + : "r1", "r2", "r4", "r5", "r6", "pr", "t"); \ + } while (0) +#else #define udiv_qrnnd(q, r, n1, n0, d) \ do { \ extern UWtype __udiv_qrnnd_16 (UWtype, UWtype) \ @@ -1007,7 +1035,7 @@ UDItype __umulsidi3 (USItype, USItype); : "1" (n1), "r" (n0), "rm" (d), "r" (&__udiv_qrnnd_16) \ : "r1", "r2", "r4", "r5", "r6", "pr", "t"); \ } while (0) - +#endif #define UDIV_TIME 80 #define sub_ddmmss(sh, sl, ah, al, bh, bl) \ diff --git a/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c b/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c index 54422de..f9b2da2 100644 --- a/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c +++ b/src/gcc-mainline/gcc/testsuite/gcc.target/sh/sh-relax.c @@ -1,6 +1,7 @@ /* Check that -mrelax works. */ /* { dg-do run { target { { sh-*-* sh?-*-* } && { ! { sh*-*-vxworks* && nonpic } } } } } */ /* { dg-options "-O1 -mrelax" } */ +/* { dg-xfail-if "" { "sh*-*-uclinux" } { "*" } { "" } } */ extern void abort (void); extern int qwerty (int); diff --git a/src/gcc-mainline/libgcc/config.host b/src/gcc-mainline/libgcc/config.host index 35dd250..a61ad27 100644 --- a/src/gcc-mainline/libgcc/config.host +++ b/src/gcc-mainline/libgcc/config.host @@ -519,6 +519,7 @@ score-*-elf) sh-*-elf* | sh[12346l]*-*-elf* | \ sh-*-symbianelf* | sh[12346l]*-*-symbianelf* | \ sh-*-linux* | sh[2346lbe]*-*-linux* | \ + sh-*-uclinux* | sh[2346lbe]*-*-uclinux* | \ sh-*-netbsdelf* | shl*-*-netbsdelf* | sh5-*-netbsd* | sh5l*-*-netbsd* | \ sh64-*-netbsd* | sh64l*-*-netbsd*) case ${host} in