@@ -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"
@@ -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")
@@ -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
@@ -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
@@ -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
@@ -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"
@@ -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__
@@ -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")])
@@ -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.
new file mode 100644
@@ -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)
new file mode 100644
@@ -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
+<http://www.gnu.org/licenses/>. */
+
+#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
@@ -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}
@@ -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
@@ -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) \
@@ -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);
@@ -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