/* Output routines for GCC for Renesas / SuperH SH.
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
#include "insn-attr.h"
#include "toplev.h"
#include "recog.h"
-#include "c-pragma.h"
#include "integrate.h"
#include "dwarf2.h"
#include "tm_p.h"
static bool sh_function_ok_for_sibcall (tree, tree);
static bool sh_cannot_modify_jumps_p (void);
-static int sh_target_reg_class (void);
+static enum reg_class sh_target_reg_class (void);
static bool sh_optimize_target_register_callee_saved (bool);
static bool sh_ms_bitfield_layout_p (const_tree);
static int sh_address_cost (rtx, bool);
static int sh_pr_n_sets (void);
static rtx sh_allocate_initial_value (rtx);
+static rtx sh_legitimize_address (rtx, rtx, enum machine_mode);
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 *);
#undef TARGET_SCHED_INIT
#define TARGET_SCHED_INIT sh_md_init
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address
+
#undef TARGET_CANNOT_MODIFY_JUMPS_P
#define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p
#undef TARGET_BRANCH_TARGET_REGISTER_CLASS
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG sh_reorg
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN sh_dwarf_register_span
+
#ifdef HAVE_AS_TLS
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS true
if ((mode == SImode || mode == DImode)
&& flag_pic
&& ! ((mode == Pmode || mode == ptr_mode)
- && tls_symbolic_operand (operands[1], Pmode) != 0))
+ && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE))
{
rtx temp;
if (SYMBOLIC_CONST_P (operands[1]))
op1 = operands[1];
if (GET_CODE (op1) == CONST
&& GET_CODE (XEXP (op1, 0)) == PLUS
- && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
+ && (tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode)
+ != TLS_MODEL_NONE))
{
opc = XEXP (XEXP (op1, 0), 1);
op1 = XEXP (XEXP (op1, 0), 0);
else
opc = NULL_RTX;
- if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
+ if ((tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE)
{
rtx tga_op1, tga_ret, tmp, tmp2;
rtx op1;
rtx scratch = NULL_RTX;
- if (comparison == CODE_FOR_nothing)
+ if (comparison == LAST_AND_UNUSED_RTX_CODE)
comparison = GET_CODE (operands[0]);
else
scratch = operands[4];
operands[1], operands[2])));
jump = emit_jump_insn (branch_expander (operands[3]));
if (probability >= 0)
- REG_NOTES (jump)
- = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (probability),
- REG_NOTES (jump));
+ add_reg_note (jump, REG_BR_PROB, GEN_INT (probability));
}
op2h = gen_highpart_mode (SImode, DImode, operands[2]);
op1l = gen_lowpart (SImode, operands[1]);
op2l = gen_lowpart (SImode, operands[2]);
- msw_taken = msw_skip = lsw_taken = CODE_FOR_nothing;
+ msw_taken = msw_skip = lsw_taken = LAST_AND_UNUSED_RTX_CODE;
prob = split_branch_probability;
rev_prob = REG_BR_PROB_BASE - prob;
switch (comparison)
break;
default: return false;
}
- num_branches = ((msw_taken != CODE_FOR_nothing)
- + (msw_skip != CODE_FOR_nothing)
- + (lsw_taken != CODE_FOR_nothing));
+ num_branches = ((msw_taken != LAST_AND_UNUSED_RTX_CODE)
+ + (msw_skip != LAST_AND_UNUSED_RTX_CODE)
+ + (lsw_taken != LAST_AND_UNUSED_RTX_CODE));
if (comparison != EQ && comparison != NE && num_branches > 1)
{
if (!CONSTANT_P (operands[2])
operands[4] = NULL_RTX;
if (reload_completed
&& ! arith_reg_or_0_operand (op2h, SImode) && true_regnum (op1h)
- && (msw_taken != CODE_FOR_nothing || msw_skip != CODE_FOR_nothing))
+ && (msw_taken != LAST_AND_UNUSED_RTX_CODE
+ || msw_skip != LAST_AND_UNUSED_RTX_CODE))
{
emit_move_insn (scratch, operands[2]);
operands[2] = scratch;
}
- if (msw_taken != CODE_FOR_nothing)
+ if (msw_taken != LAST_AND_UNUSED_RTX_CODE)
expand_cbranchsi4 (operands, msw_taken, msw_taken_prob);
- if (msw_skip != CODE_FOR_nothing)
+ if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
{
rtx taken_label = operands[3];
/* Operands were possibly modified, but msw_skip doesn't expect this.
Always use the original ones. */
- if (msw_taken != CODE_FOR_nothing)
+ if (msw_taken != LAST_AND_UNUSED_RTX_CODE)
{
operands[1] = op1h;
operands[2] = op2h;
}
operands[1] = op1l;
operands[2] = op2l;
- if (lsw_taken != CODE_FOR_nothing)
+ if (lsw_taken != LAST_AND_UNUSED_RTX_CODE)
{
if (reload_completed
&& ! arith_reg_or_0_operand (op2l, SImode) && true_regnum (op1l))
operands[4] = scratch;
expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob);
}
- if (msw_skip != CODE_FOR_nothing)
+ if (msw_skip != LAST_AND_UNUSED_RTX_CODE)
emit_label (skip_label);
return true;
}
else
insn = gen_rtx_SET (VOIDmode,
gen_rtx_REG (SImode, T_REG),
- gen_rtx_fmt_ee (code, SImode,
+ gen_rtx_fmt_ee ((enum rtx_code) code, SImode,
sh_compare_op0, sh_compare_op1));
if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
{
shift_insns_rtx (rtx insn)
{
rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
- int shift_count = INTVAL (XEXP (set_src, 1));
+ int shift_count = INTVAL (XEXP (set_src, 1)) & 31;
enum rtx_code shift_code = GET_CODE (set_src);
switch (shift_code)
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
return SH_DYNAMIC_SHIFT_COST;
- value = INTVAL (XEXP (x, 1));
+ /* Otherwise, return the true cost in instructions. Cope with out of range
+ shift counts more or less arbitrarily. */
+ value = INTVAL (XEXP (x, 1)) & 31;
- /* Otherwise, return the true cost in instructions. */
if (GET_CODE (x) == ASHIFTRT)
{
int cost = ashiftrt_insns[value];
int max, i;
/* Truncate the shift count in case it is out of bounds. */
- value = value & 0x1f;
+ value = value & 31;
if (value == 31)
{
int
sh_dynamicalize_shift_p (rtx count)
{
- return shift_insns[INTVAL (count)] > 1 + SH_DYNAMIC_SHIFT_COST;
+ return shift_insns[INTVAL (count) & 31] > 1 + SH_DYNAMIC_SHIFT_COST;
}
/* Try to find a good way to implement the combiner pattern
shl_and_scr_length (rtx insn)
{
rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
- int len = shift_insns[INTVAL (XEXP (set_src, 1))];
+ int len = shift_insns[INTVAL (XEXP (set_src, 1)) & 31];
rtx op = XEXP (set_src, 0);
- len += shift_insns[INTVAL (XEXP (op, 1))] + 1;
+ len += shift_insns[INTVAL (XEXP (op, 1)) & 31] + 1;
op = XEXP (XEXP (op, 0), 0);
- return len + shift_insns[INTVAL (XEXP (op, 1))];
+ return len + shift_insns[INTVAL (XEXP (op, 1)) & 31];
}
/* Generate rtl for instructions for which shl_and_kind advised a particular
if (optimize)
{
+ /* If NEW_MOVA has no address yet, it will be handled later. */
+ if (INSN_ADDRESSES_SIZE() <= (unsigned) INSN_UID (new_mova))
+ return -1;
+
n_addr = INSN_ADDRESSES (INSN_UID (new_mova));
n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0)));
if (n_addr > n_target || n_addr + 1022 < n_target)
/* If we are not optimizing, then there may not be
a note. */
if (note)
- PUT_MODE (note, REG_INC);
+ PUT_REG_NOTE_KIND (note, REG_INC);
*last_float_addr = r0_inc_rtx;
}
insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
}
if (! epilogue_p)
- REG_NOTES (insn)
- = (gen_rtx_EXPR_LIST
- (REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (VOIDmode, reg,
- gen_rtx_PLUS (SImode, reg, GEN_INT (size))),
- REG_NOTES (insn)));
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_PLUS (SImode, reg,
+ GEN_INT (size))));
}
}
}
x = gen_push (gen_rtx_REG (SImode, rn));
x = frame_insn (x);
- REG_NOTES (x)
- = gen_rtx_EXPR_LIST (REG_INC,
- gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
+ add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM));
return x;
}
x = gen_pop (gen_rtx_REG (SImode, rn));
x = emit_insn (x);
- REG_NOTES (x)
- = gen_rtx_EXPR_LIST (REG_INC,
- gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
+ add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM));
}
/* Generate code to push the regs specified in the mask. */
&& crtl->args.info.call_cookie
&& reg == PIC_OFFSET_TABLE_REGNUM)
|| (df_regs_ever_live_p (reg)
- && (!call_really_used_regs[reg]
+ && ((!call_really_used_regs[reg]
+ && !(reg != PIC_OFFSET_TABLE_REGNUM
+ && fixed_regs[reg] && call_used_regs[reg]))
|| (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
|| (crtl->calls_eh_return
&& (reg == EH_RETURN_DATA_REGNO (0)
tmp_pnt = schedule.temps;
for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++)
{
- enum machine_mode mode = entry->mode;
+ enum machine_mode mode = (enum machine_mode) entry->mode;
unsigned int reg = entry->reg;
rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX;
rtx orig_reg_rtx;
stack_pointer_rtx,
GEN_INT (offset)));
- GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
-
- gcc_assert (r0);
- mem_rtx = NULL_RTX;
-
- try_pre_dec:
- do
- if (HAVE_PRE_DECREMENT
- && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
- || mem_rtx == NULL_RTX
- || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
- {
- pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
+ if (!memory_address_p (mode, XEXP (mem_rtx, 0)))
+ {
+ gcc_assert (r0);
+ mem_rtx = NULL_RTX;
+ }
- GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
- pre_dec_ok);
+ if (HAVE_PRE_DECREMENT
+ && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
+ || mem_rtx == NULL_RTX
+ || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+ {
+ pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
+ if (!memory_address_p (mode, XEXP (pre_dec, 0)))
pre_dec = NULL_RTX;
-
- break;
-
- pre_dec_ok:
- mem_rtx = NULL_RTX;
- offset += GET_MODE_SIZE (mode);
- }
- while (0);
+ else
+ {
+ mem_rtx = NULL_RTX;
+ offset += GET_MODE_SIZE (mode);
+ }
+ }
if (mem_rtx != NULL_RTX)
goto addr_ok;
a direct save from the to-be-saved register. */
if (REGNO (reg_rtx) != reg)
{
- rtx set, note_rtx;
+ rtx set;
set = gen_rtx_SET (VOIDmode, mem_rtx, orig_reg_rtx);
- note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
- REG_NOTES (insn));
- REG_NOTES (insn) = note_rtx;
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
}
if (TARGET_SHCOMPACT && (offset_in_r0 != -1))
{
rtx reg_rtx = gen_rtx_REG (mode, reg);
- rtx set, note_rtx;
+ rtx set;
rtx mem_rtx = gen_frame_mem (mode,
gen_rtx_PLUS (Pmode,
stack_pointer_rtx,
GEN_INT (offset)));
set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx);
- note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
- REG_NOTES (insn));
- REG_NOTES (insn) = note_rtx;
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
}
}
}
tmp_pnt = schedule.temps;
for (; entry->mode != VOIDmode; entry--)
{
- enum machine_mode mode = entry->mode;
+ enum machine_mode mode = (enum machine_mode) entry->mode;
int reg = entry->reg;
rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
stack_pointer_rtx,
GEN_INT (offset)));
- GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
-
- mem_rtx = NULL_RTX;
+ if (!memory_address_p (mode, XEXP (mem_rtx, 0)))
+ mem_rtx = NULL_RTX;
- try_post_inc:
- do
- if (HAVE_POST_INCREMENT
- && (offset == offset_in_r0
- || (offset + GET_MODE_SIZE (mode) != d + d_rounding
- && mem_rtx == NULL_RTX)
- || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
- {
- post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
-
- GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
- post_inc_ok);
+ if (HAVE_POST_INCREMENT
+ && (offset == offset_in_r0
+ || (offset + GET_MODE_SIZE (mode) != d + d_rounding
+ && mem_rtx == NULL_RTX)
+ || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
+ {
+ post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
+ if (!memory_address_p (mode, XEXP (post_inc, 0)))
post_inc = NULL_RTX;
-
- break;
-
- post_inc_ok:
+ else
mem_rtx = NULL_RTX;
- }
- while (0);
+ }
if (mem_rtx != NULL_RTX)
goto addr_ok;
return result;
}
+/* 64 bit floating points memory transfers are paired single precision loads
+ or store. So DWARF information needs fixing in little endian (unless
+ PR=SZ=1 in FPSCR). */
+rtx
+sh_dwarf_register_span (rtx reg)
+{
+ unsigned regno = REGNO (reg);
+
+ if (WORDS_BIG_ENDIAN || GET_MODE (reg) != DFmode)
+ return NULL_RTX;
+
+ return
+ gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_REG (SFmode,
+ DBX_REGISTER_NUMBER (regno+1)),
+ gen_rtx_REG (SFmode,
+ DBX_REGISTER_NUMBER (regno))));
+}
+
bool
sh_promote_prototypes (const_tree type)
{
}
/* Return the TLS type for TLS symbols, 0 for otherwise. */
-int
+enum tls_model
tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != SYMBOL_REF)
- return 0;
+ return TLS_MODEL_NONE;
return SYMBOL_REF_TLS_MODEL (op);
}
\f
void
fpscr_set_from_mem (int mode, HARD_REG_SET regs_live)
{
- enum attr_fp_mode fp_mode = mode;
+ enum attr_fp_mode fp_mode = (enum attr_fp_mode) mode;
enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE);
rtx addr_reg;
/* SH2e has a bug that prevents the use of annulled branches, so if
the delay slot is not filled, we'll have to put a NOP in it. */
- if (sh_cpu == CPU_SH2E
+ if (sh_cpu_attr == CPU_SH2E
&& GET_CODE (insn) == JUMP_INSN
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_VEC
legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
rtx reg)
{
- if (tls_symbolic_operand (orig, Pmode))
+ if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE)
return orig;
if (GET_CODE (orig) == LABEL_REF
return orig;
}
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ Otherwise, return X.
+
+ For the SH, if X is almost suitable for indexing, but the offset is
+ out of range, convert it into a normal form so that CSE has a chance
+ of reducing the number of address registers used. */
+
+static rtx
+sh_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
+{
+ if (flag_pic)
+ x = legitimize_pic_address (oldx, mode, NULL_RTX);
+
+ if (GET_CODE (x) == PLUS
+ && (GET_MODE_SIZE (mode) == 4
+ || GET_MODE_SIZE (mode) == 8)
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && BASE_REGISTER_RTX_P (XEXP (x, 0))
+ && ! TARGET_SHMEDIA
+ && ! ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
+ && ! (TARGET_SH2E && mode == SFmode))
+ {
+ rtx index_rtx = XEXP (x, 1);
+ HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base;
+ rtx sum;
+
+ /* On rare occasions, we might get an unaligned pointer
+ that is indexed in a way to give an aligned address.
+ Therefore, keep the lower two bits in offset_base. */
+ /* Instead of offset_base 128..131 use 124..127, so that
+ simple add suffices. */
+ if (offset > 127)
+ offset_base = ((offset + 4) & ~60) - 4;
+ else
+ offset_base = offset & ~60;
+
+ /* Sometimes the normal form does not suit DImode. We
+ could avoid that by using smaller ranges, but that
+ would give less optimized code when SImode is
+ prevalent. */
+ if (GET_MODE_SIZE (mode) + offset - offset_base <= 64)
+ {
+ sum = expand_binop (Pmode, add_optab, XEXP (x, 0),
+ GEN_INT (offset_base), NULL_RTX, 0,
+ OPTAB_LIB_WIDEN);
+
+ return gen_rtx_PLUS (Pmode, sum, GEN_INT (offset - offset_base));
+ }
+ }
+
+ return x;
+}
+
/* Mark the use of a constant in the literal table. If the constant
has multiple labels, make it unique. */
static rtx
return (TARGET_SHMEDIA && (reload_in_progress || reload_completed));
}
-static int
+static enum reg_class
sh_target_reg_class (void)
{
return TARGET_SHMEDIA ? TARGET_REGS : NO_REGS;
|| (!(TARGET_SH4A_ARCH || TARGET_SH4_300) && TARGET_USERMODE))
emit_library_call (function_symbol (NULL, "__ic_invalidate",
FUNCTION_ORDINARY),
- 0, VOIDmode, 1, tramp, SImode);
+ LCT_NORMAL, VOIDmode, 1, tramp, SImode);
else
emit_insn (gen_ic_invalidate_line (tramp));
}
argmode = TYPE_MODE (TREE_TYPE (arg));
if (argmode != opmode)
arg = build1 (NOP_EXPR, optype, arg);
- op[nop] = expand_expr (arg, NULL_RTX, opmode, 0);
+ op[nop] = expand_expr (arg, NULL_RTX, opmode, EXPAND_NORMAL);
if (! (*insn_data[icode].operand[nop].predicate) (op[nop], opmode))
op[nop] = copy_to_mode_reg (opmode, op[nop]);
}
emit_insn (gen_binary_sf_op1 (op0, op1, op2, op));
}
+/* Return true if hard register REGNO can hold a value of machine-mode MODE.
+ We can allow any mode in any general register. The special registers
+ only allow SImode. Don't allow any mode in the PR.
+
+ We cannot hold DCmode values in the XD registers because alter_reg
+ handles subregs of them incorrectly. We could work around this by
+ spacing the XD registers like the DR registers, but this would require
+ additional memory in every compilation to hold larger register vectors.
+ We could hold SFmode / SCmode values in XD registers, but that
+ would require a tertiary reload when reloading from / to memory,
+ and a secondary reload to reload from / to general regs; that
+ seems to be a loosing proposition.
+
+ We want to allow TImode FP regs so that when V4SFmode is loaded as TImode,
+ it won't be ferried through GP registers first. */
+
+bool
+sh_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
+{
+ if (SPECIAL_REGISTER_P (regno))
+ return mode == SImode;
+
+ if (regno == FPUL_REG)
+ return (mode == SImode || mode == SFmode);
+
+ if (FP_REGISTER_P (regno) && mode == SFmode)
+ return true;
+
+ if (mode == V2SFmode)
+ {
+ if (((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 2 == 0)
+ || GENERAL_REGISTER_P (regno)))
+ return true;
+ else
+ return false;
+ }
+
+ if (mode == V4SFmode)
+ {
+ if ((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 4 == 0)
+ || GENERAL_REGISTER_P (regno))
+ return true;
+ else
+ return false;
+ }
+
+ if (mode == V16SFmode)
+ {
+ if (TARGET_SHMEDIA)
+ {
+ if (FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 16 == 0)
+ return true;
+ else
+ return false;
+ }
+ else
+ return regno == FIRST_XD_REG;
+ }
+
+ if (FP_REGISTER_P (regno))
+ {
+ if (mode == SFmode
+ || mode == SImode
+ || ((TARGET_SH2E || TARGET_SHMEDIA) && mode == SCmode)
+ || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode)
+ || mode == DCmode
+ || (TARGET_SHMEDIA
+ && (mode == DFmode || mode == DImode
+ || mode == V2SFmode || mode == TImode)))
+ && ((regno - FIRST_FP_REG) & 1) == 0)
+ || ((TARGET_SH4 || TARGET_SHMEDIA) && mode == TImode
+ && ((regno - FIRST_FP_REG) & 3) == 0))
+ return true;
+ else
+ return false;
+ }
+
+ if (XD_REGISTER_P (regno))
+ return mode == DFmode;
+
+ if (TARGET_REGISTER_P (regno))
+ return (mode == DImode || mode == SImode || mode == PDImode);
+
+ if (regno == PR_REG)
+ return mode == SImode;
+
+ if (regno == FPSCR_REG)
+ return mode == PSImode;
+
+ /* FIXME. This works around PR target/37633 for -O0. */
+ if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4)
+ {
+ unsigned int n = GET_MODE_SIZE (mode) / 8;
+
+ if (regno >= FIRST_GENERAL_REG + 10 - n + 1
+ && regno <= FIRST_GENERAL_REG + 14)
+ return false;
+ }
+
+ return true;
+}
+
/* Return the class of registers for which a mode change from FROM to TO
is invalid. */
bool
insn_locators_alloc ();
insns = get_insns ();
-#if 0
- if (optimize > 0)
- {
- /* Initialize the bitmap obstacks. */
- bitmap_obstack_initialize (NULL);
- bitmap_obstack_initialize (®_obstack);
- if (! cfun->cfg)
- init_flow ();
- rtl_register_cfg_hooks ();
- init_rtl_bb_info (ENTRY_BLOCK_PTR);
- init_rtl_bb_info (EXIT_BLOCK_PTR);
- ENTRY_BLOCK_PTR->flags |= BB_RTL;
- EXIT_BLOCK_PTR->flags |= BB_RTL;
- find_basic_blocks (insns);
-
- if (flag_schedule_insns_after_reload)
- {
- life_analysis (PROP_FINAL);
-
- split_all_insns (1);
-
- schedule_insns ();
- }
- /* We must split jmp insn in PIC case. */
- else if (flag_pic)
- split_all_insns_noflow ();
- }
-#else
if (optimize > 0)
{
if (! cfun->cfg)
init_flow (cfun);
split_all_insns_noflow ();
}
-#endif
sh_reorg ();