/* 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 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Contributed by Steve Chamberlain (sac@cygnus.com).
Improved by Jim Wilson (wilson@cygnus.com).
#define GEN_ADD3 (*(TARGET_SHMEDIA64 ? gen_adddi3 : gen_addsi3))
#define GEN_SUB3 (*(TARGET_SHMEDIA64 ? gen_subdi3 : gen_subsi3))
+/* Used to simplify the logic below. Find the attributes wherever
+ they may be. */
+#define SH_ATTRIBUTES(decl) \
+ (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
+ : DECL_ATTRIBUTES (decl) \
+ ? (DECL_ATTRIBUTES (decl)) \
+ : TYPE_ATTRIBUTES (TREE_TYPE (decl))
+
/* Set to 1 by expand_prologue() when the function is an interrupt handler. */
int current_function_interrupt;
static rtx mark_constant_pool_use (rtx);
const struct attribute_spec sh_attribute_table[];
static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *);
+static tree sh_handle_resbank_handler_attribute (tree *, tree,
+ tree, int, bool *);
+static tree sh2a_handle_function_vector_handler_attribute (tree *, tree,
+ tree, int, bool *);
static tree sh_handle_sp_switch_attribute (tree *, tree, tree, int, bool *);
static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *);
static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
static bool sh_strict_argument_naming (CUMULATIVE_ARGS *);
static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
static tree sh_build_builtin_va_list (void);
+static void sh_va_start (tree, rtx);
static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
const_tree, bool);
const_tree, bool);
static int sh_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
+static bool sh_scalar_mode_supported_p (enum machine_mode);
static int sh_dwarf_calling_convention (const_tree);
+static void sh_encode_section_info (tree, rtx, int);
+static int sh2a_function_vector_p (tree);
\f
/* Initialize the GCC target structure. */
#undef TARGET_BUILD_BUILTIN_VA_LIST
#define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START sh_va_start
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
#define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P sh_scalar_mode_supported_p
#undef TARGET_VECTOR_MODE_SUPPORTED_P
#define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p
/* Return current register pressure for regmode. */
#define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO sh_encode_section_info
+
#ifdef SYMBIAN
#undef TARGET_ENCODE_SECTION_INFO
#undef TARGET_SECONDARY_RELOAD
#define TARGET_SECONDARY_RELOAD sh_secondary_reload
+/* Machine-specific symbol_ref flags. */
+#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
/* Implement TARGET_HANDLE_OPTION. */
'd' print a V2SF reg as dN instead of fpN.
'm' print a pair `base,offset' or `base,index', for LD and ST.
'U' Likewise for {LD,ST}{HI,LO}.
+ 'V' print the position of a single bit set.
+ 'W' print the position of a single bit cleared.
+ 't' print a memory address which is a register.
'u' prints the lowest 16 bits of CONST_INT, as an unsigned value.
'o' output an operator. */
fprintf (stream, "trapa #%ld",
(long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr))));
else if (sh_cfun_interrupt_handler_p ())
- fprintf (stream, "rte");
+ {
+ if (sh_cfun_resbank_handler_p ())
+ fprintf (stream, "resbank\n");
+ fprintf (stream, "rte");
+ }
else
fprintf (stream, "rts");
break;
break;
}
break;
+
+ case 't':
+ gcc_assert (GET_CODE (x) == MEM);
+ x = XEXP (x, 0);
+ switch (GET_CODE (x))
+ {
+ case REG:
+ case SUBREG:
+ print_operand (stream, x, 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
case 'o':
switch (GET_CODE (x))
{
}
break;
+ case 'V':
+ {
+ int num = exact_log2 (INTVAL (x));
+ gcc_assert (num >= 0);
+ fprintf (stream, "#%d", num);
+ }
+ break;
+
+ case 'W':
+ {
+ int num = exact_log2 (~INTVAL (x));
+ gcc_assert (num >= 0);
+ fprintf (stream, "#%d", num);
+ }
+ break;
+
case 'd':
gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == V2SFmode);
}
}
\f
+
+/* Encode symbol attributes of a SYMBOL_REF into its
+ SYMBOL_REF_FLAGS. */
+static void
+sh_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && sh2a_function_vector_p (decl) && TARGET_SH2A)
+ SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FUNCVEC_FUNCTION;
+}
+
/* Like force_operand, but guarantees that VALUE ends up in TARGET. */
static void
force_into (rtx value, rtx target)
&& CONST_OK_FOR_K08 (INTVAL (x)))
*total = 1;
/* prepare_cmp_insn will force costly constants int registers before
- the cbrach[sd]i4 patterns can see them, so preserve potentially
+ the cbranch[sd]i4 patterns can see them, so preserve potentially
interesting ones not covered by I08 above. */
else if (outer_code == COMPARE
&& ((unsigned HOST_WIDE_INT) INTVAL (x)
if (TARGET_SHMEDIA)
*total = COSTS_N_INSNS (4);
/* prepare_cmp_insn will force costly constants int registers before
- the cbrachdi4 pattern can see them, so preserve potentially
+ the cbranchdi4 pattern can see them, so preserve potentially
interesting ones. */
else if (outer_code == COMPARE && GET_MODE (x) == DImode)
*total = 1;
&& FP_REGISTER_P (REGNO (SET_DEST (pat))))
&& ! (TARGET_SH2A
&& GET_MODE (SET_DEST (pat)) == SImode
- && satisfies_constraint_I20 (SET_SRC (pat)))
+ && (satisfies_constraint_I20 (SET_SRC (pat))
+ || satisfies_constraint_I28 (SET_SRC (pat))))
&& ! satisfies_constraint_I08 (SET_SRC (pat)))
return 1;
}
rtx barrier_before_mova = 0, found_barrier = 0, good_barrier = 0;
int si_limit;
int hi_limit;
+ rtx orig = from;
/* For HImode: range is 510, add 4 because pc counts from address of
second instruction after this one, subtract 2 for the jump instruction
if (GET_CODE (from) == BARRIER)
{
+ rtx next;
found_barrier = from;
this kind of barrier. */
if (barrier_align (from) > 2)
good_barrier = from;
+
+ /* If we are at the end of a hot/cold block, dump the constants
+ here. */
+ next = NEXT_INSN (from);
+ if (next
+ && NOTE_P (next)
+ && NOTE_KIND (next) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+ break;
}
if (broken_move (from))
/* If we exceeded the range, then we must back up over the last
instruction we looked at. Otherwise, we just need to undo the
NEXT_INSN at the end of the loop. */
- if (count_hi > hi_limit || count_si > si_limit)
+ if (PREV_INSN (from) != orig
+ && (count_hi > hi_limit || count_si > si_limit))
from = PREV_INSN (PREV_INSN (from));
else
from = PREV_INSN (from);
mdep_reorg_phase = SH_INSERT_USES_LABELS;
if (TARGET_RELAX)
{
- /* Remove all REG_LABEL notes. We want to use them for our own
- purposes. This works because none of the remaining passes
+ /* Remove all REG_LABEL_OPERAND notes. We want to use them for our
+ own purposes. This works because none of the remaining passes
need to look at them.
??? But it may break in the future. We should use a machine
{
rtx note;
- while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
+ while ((note = find_reg_note (insn, REG_LABEL_OPERAND,
+ NULL_RTX)) != 0)
remove_note (insn, note);
}
}
continue;
}
- /* Create a code label, and put it in a REG_LABEL note on
- the insn which sets the register, and on each call insn
- which uses the register. In final_prescan_insn we look
- for the REG_LABEL notes, and output the appropriate label
+ /* Create a code label, and put it in a REG_LABEL_OPERAND note
+ on the insn which sets the register, and on each call insn
+ which uses the register. In final_prescan_insn we look for
+ the REG_LABEL_OPERAND notes, and output the appropriate label
or pseudo-op. */
label = gen_label_rtx ();
- REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
+ REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (link));
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (insn));
if (rescan)
{
|| ((reg2 = sfunc_uses_reg (scan))
&& REGNO (reg2) == REGNO (reg))))
REG_NOTES (scan)
- = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+ = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
+ REG_NOTES (scan));
}
while (scan != dies);
}
bp->insert_place = insn;
bp->address = addr;
}
- ok = redirect_jump (insn, label, 1);
+ ok = redirect_jump (insn, label, 0);
gcc_assert (ok);
}
else
{
rtx note;
- note = find_reg_note (insn, REG_LABEL, NULL_RTX);
+ note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
if (note)
{
rtx pattern;
if (i != PR_REG
&& (i != FPSCR_REG || ! skip_fpscr)
&& TEST_HARD_REG_BIT (*mask, i))
- push (i);
+ {
+ /* If the ISR has RESBANK attribute assigned, don't push any of
+ the following registers - R0-R14, MACH, MACL and GBR. */
+ if (! (sh_cfun_resbank_handler_p ()
+ && ((i >= FIRST_GENERAL_REG && i < LAST_GENERAL_REG)
+ || i == MACH_REG
+ || i == MACL_REG
+ || i == GBR_REG)))
+ push (i);
+ }
}
/* Push banked registers last to improve delay slot opportunities. */
if (TEST_HARD_REG_BIT (*mask, i))
push (i);
- if (TEST_HARD_REG_BIT (*mask, PR_REG))
+ /* Don't push PR register for an ISR with RESBANK attribute assigned. */
+ if (TEST_HARD_REG_BIT (*mask, PR_REG) && !sh_cfun_resbank_handler_p ())
push (PR_REG);
}
if (TARGET_SHCOMPACT
&& ((current_function_args_info.call_cookie
& ~ CALL_COOKIE_RET_TRAMP (1))
- || current_function_has_nonlocal_label))
+ || current_function_saves_all_registers))
pr_live = 1;
has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live;
for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; )
int last_reg;
save_size = 0;
- if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
+ /* For an ISR with RESBANK attribute assigned, don't pop PR
+ register. */
+ if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG)
+ && !sh_cfun_resbank_handler_p ())
{
if (!frame_pointer_needed)
emit_insn (gen_blockage ());
&& hard_reg_set_intersect_p (live_regs_mask,
reg_class_contents[DF_REGS]))
fpscr_deferred = 1;
- else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
+ /* For an ISR with RESBANK attribute assigned, don't pop
+ following registers, R0-R14, MACH, MACL and GBR. */
+ else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j)
+ && ! (sh_cfun_resbank_handler_p ()
+ && ((j >= FIRST_GENERAL_REG
+ && j < LAST_GENERAL_REG)
+ || j == MACH_REG
+ || j == MACL_REG
+ || j == GBR_REG)))
pop (j);
if (j == FIRST_FP_REG && fpscr_deferred)
/* Implement `va_start' for varargs and stdarg. */
-void
+static void
sh_va_start (tree valist, rtx nextarg)
{
tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
java frontend. */
attrs
= tree_cons (get_identifier("interrupt_handler"), NULL_TREE, attrs);
- /* However, for sp_switch, trap_exit and nosave_low_regs, if the
- interrupt attribute is missing, we ignore the attribute and warn. */
+ /* However, for sp_switch, trap_exit, nosave_low_regs and resbank,
+ if the interrupt attribute is missing, we ignore the attribute
+ and warn. */
else if (lookup_attribute ("sp_switch", attrs)
|| lookup_attribute ("trap_exit", attrs)
- || lookup_attribute ("nosave_low_regs", attrs))
+ || lookup_attribute ("nosave_low_regs", attrs)
+ || lookup_attribute ("resbank", attrs))
{
tree *tail;
{
if (is_attribute_p ("sp_switch", TREE_PURPOSE (attrs))
|| is_attribute_p ("trap_exit", TREE_PURPOSE (attrs))
- || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs)))
+ || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs))
+ || is_attribute_p ("resbank", TREE_PURPOSE (attrs)))
warning (OPT_Wattributes,
"%qs attribute only applies to interrupt functions",
IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
renesas -- use Renesas calling/layout conventions (functions and
structures).
+ resbank -- In case of an ISR, use a register bank to save registers
+ R0-R14, MACH, MACL, GBR and PR. This is useful only on SH2A targets.
*/
const struct attribute_spec sh_attribute_table[] =
{ "renesas", 0, 0, false, true, false, sh_handle_renesas_attribute },
{ "trapa_handler", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute },
{ "nosave_low_regs", 0, 0, true, false, false, sh_handle_interrupt_handler_attribute },
+ { "resbank", 0, 0, true, false, false, sh_handle_resbank_handler_attribute },
+ { "function_vector", 1, 1, true, false, false, sh2a_handle_function_vector_handler_attribute },
#ifdef SYMBIAN
/* Symbian support adds three new attributes:
dllexport - for exporting a function/variable that will live in a dll
{ NULL, 0, 0, false, false, false, NULL }
};
+/* Handle a 'resbank' attribute. */
+static tree
+sh_handle_resbank_handler_attribute (tree * node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ if (!TARGET_SH2A)
+ {
+ warning (OPT_Wattributes, "%qs attribute is supported only for SH2A",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle an "interrupt_handler" attribute; arguments as in
struct attribute_spec.handler. */
static tree
sh_handle_interrupt_handler_attribute (tree *node, tree name,
- tree args ATTRIBUTE_UNUSED,
- int flags ATTRIBUTE_UNUSED,
- bool *no_add_attrs)
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
warning (OPT_Wattributes, "%qs attribute only applies to functions",
- IDENTIFIER_POINTER (name));
+ IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else if (TARGET_SHCOMPACT)
return NULL_TREE;
}
+/* Handle an 'function_vector' attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+sh2a_handle_function_vector_handler_attribute (tree * node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool * no_add_attrs)
+{
+ if (!TARGET_SH2A)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to SH2A",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qs attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+ {
+ /* The argument must be a constant integer. */
+ warning (OPT_Wattributes,
+ "`%s' attribute argument not an integer constant",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255)
+ {
+ /* The argument value must be between 0 to 255. */
+ warning (OPT_Wattributes,
+ "`%s' attribute argument should be between 0 to 255",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ return NULL_TREE;
+}
+
+/* Returns 1 if current function has been assigned the attribute
+ 'function_vector'. */
+int
+sh2a_is_function_vector_call (rtx x)
+{
+ if (GET_CODE (x) == SYMBOL_REF
+ && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+ {
+ tree tr = SYMBOL_REF_DECL (x);
+
+ if (sh2a_function_vector_p (tr))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns the function vector number, if the the attribute
+ 'function_vector' is assigned, otherwise returns zero. */
+int
+sh2a_get_function_vector_number (rtx x)
+{
+ int num;
+ tree list, t;
+
+ if ((GET_CODE (x) == SYMBOL_REF)
+ && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
+ {
+ t = SYMBOL_REF_DECL (x);
+
+ if (TREE_CODE (t) != FUNCTION_DECL)
+ return 0;
+
+ list = SH_ATTRIBUTES (t);
+ while (list)
+ {
+ if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+ {
+ num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list)));
+ return num;
+ }
+
+ list = TREE_CHAIN (list);
+ }
+
+ return 0;
+ }
+ else
+ return 0;
+}
+
/* Handle an "sp_switch" attribute; arguments as in
struct attribute_spec.handler. */
static tree
!= NULL_TREE);
}
+/* Returns 1 if FUNC has been assigned the attribute
+ "function_vector". */
+int
+sh2a_function_vector_p (tree func)
+{
+ tree list;
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ list = SH_ATTRIBUTES (func);
+ while (list)
+ {
+ if (is_attribute_p ("function_vector", TREE_PURPOSE (list)))
+ return 1;
+
+ list = TREE_CHAIN (list);
+ }
+ return 0;
+}
+
+/* Returns TRUE if given tree has the "resbank" attribute. */
+
+int
+sh_cfun_resbank_handler_p (void)
+{
+ return ((lookup_attribute ("resbank",
+ DECL_ATTRIBUTES (current_function_decl))
+ != NULL_TREE)
+ && (lookup_attribute ("interrupt_handler",
+ DECL_ATTRIBUTES (current_function_decl))
+ != NULL_TREE) && TARGET_SH2A);
+}
+
/* Implement TARGET_CHECK_PCH_TARGET_FLAGS. */
static const char *
/* Is the given character a logical line separator for the assembler? */
#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR
-#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
+#define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';')
#endif
int
else if ((c == 'r' || c == 'R')
&& ! strncasecmp ("epeat", template, 5))
ppi_adjust = 4;
- while (c && c != '\n' && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c))
+ while (c && c != '\n'
+ && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, template))
{
/* If this is a label, it is obviously not a ppi insn. */
if (c == ':' && maybe_label)
&& ! (TARGET_SHCOMPACT
&& ((current_function_args_info.call_cookie
& ~ CALL_COOKIE_RET_TRAMP (1))
- || current_function_has_nonlocal_label)))
+ || current_function_saves_all_registers)))
x = hard_reg;
else
x = gen_frame_mem (Pmode, return_address_pointer_rtx);
}
}
+/* The scalar modes supported differs from the default version in TImode
+ for 32-bit SHMEDIA. */
+static bool
+sh_scalar_mode_supported_p (enum machine_mode mode)
+{
+ if (TARGET_SHMEDIA32 && mode == TImode)
+ return false;
+
+ return default_scalar_mode_supported_p (mode);
+}
+
/* Cache the can_issue_more so that we can return it from reorder2. Also,
keep count of register pressures on SImode and SFmode. */
static int
void
sh_expand_binop_v2sf (enum rtx_code code, rtx op0, rtx op1, rtx op2)
{
- rtx sel0 = const0_rtx;
- rtx sel1 = const1_rtx;
- rtx (*fn) (rtx, rtx, rtx, rtx, rtx, rtx, rtx, rtx)
- = gen_binary_sf_op;
rtx op = gen_rtx_fmt_ee (code, SFmode, op1, op2);
- emit_insn ((*fn) (op0, op1, op2, op, sel0, sel0, sel0, sel1));
- emit_insn ((*fn) (op0, op1, op2, op, sel1, sel1, sel1, sel0));
+ emit_insn (gen_binary_sf_op0 (op0, op1, op2, op));
+ emit_insn (gen_binary_sf_op1 (op0, op1, op2, op));
}
/* Return the class of registers for which a mode change from FROM to TO
final_start_function (insns, file, 1);
final (insns, file, 1);
final_end_function ();
+ free_after_compilation (cfun);
reload_completed = 0;
epilogue_completed = 0;
if (TARGET_SHCOMPACT
&& ((current_function_args_info.call_cookie
& ~ CALL_COOKIE_RET_TRAMP (1))
- || current_function_has_nonlocal_label))
+ || current_function_saves_all_registers))
return gen_frame_mem (SImode, return_address_pointer_rtx);
/* If we haven't finished rtl generation, there might be a nonlocal label
val = INTVAL (sh_compare_op1);
if ((code == EQ && val == 1) || (code == NE && val == 0))
emit_insn (gen_movt (result));
+ else if (TARGET_SH2A && ((code == EQ && val == 0)
+ || (code == NE && val == 1)))
+ emit_insn (gen_movrt (result));
else if ((code == EQ && val == 0) || (code == NE && val == 1))
{
emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
return GENERAL_REGS;
if (class == FPUL_REGS && immediate_operand (x, mode))
{
- if (satisfies_constraint_I08 (x))
+ if (satisfies_constraint_I08 (x) || fp_zero_operand (x))
return GENERAL_REGS;
+ else if (mode == SFmode)
+ return FP_REGS;
sri->icode = CODE_FOR_reload_insi__i_fpul;
return NO_REGS;
}