/* Subroutines for insn-output.c for Matsushita MN10300 series
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
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 2, or (at your option)
+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,
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 COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
/* The size of the callee register save area. Right now we save everything
on entry since it costs us nothing in code size. It does cost us from a
speed standpoint, so we want to optimize this sooner or later. */
-#define REG_SAVE_BYTES (4 * regs_ever_live[2] \
- + 4 * regs_ever_live[3] \
- + 4 * regs_ever_live[6] \
- + 4 * regs_ever_live[7] \
- + 16 * (regs_ever_live[14] || regs_ever_live[15] \
- || regs_ever_live[16] || regs_ever_live[17]))
+#define REG_SAVE_BYTES (4 * df_regs_ever_live_p (2) \
+ + 4 * df_regs_ever_live_p (3) \
+ + 4 * df_regs_ever_live_p (6) \
+ + 4 * df_regs_ever_live_p (7) \
+ + 16 * (df_regs_ever_live_p (14) || df_regs_ever_live_p (15) \
+ || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)))
static bool mn10300_handle_option (size_t, const char *, int);
static int mn10300_address_cost (rtx);
static bool mn10300_rtx_costs (rtx, int, int, int *);
static void mn10300_file_start (void);
-static bool mn10300_return_in_memory (tree, tree);
+static bool mn10300_return_in_memory (const_tree, const_tree);
static rtx mn10300_builtin_saveregs (void);
+static void mn10300_va_start (tree, rtx);
static bool mn10300_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
- tree, bool);
+ const_tree, bool);
static int mn10300_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
\f
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG
+#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION mn10300_handle_option
#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info
#undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY mn10300_return_in_memory
#undef TARGET_PASS_BY_REFERENCE
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
#define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregs
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START mn10300_va_start
static void mn10300_encode_section_info (tree, rtx, int);
struct gcc_target targetm = TARGET_INITIALIZER;
fprintf (file, "ul");
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
}
fprintf (file, "cs");
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
case 'C':
else
print_operand (file, x, 0);
break;
-
+
case 'D':
switch (GET_CODE (x))
{
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
}
default:
- abort ();
+ gcc_unreachable ();
}
break;
fprintf (file, "0x%lx", val[1]);
break;;
case SFmode:
- abort ();
+ gcc_unreachable ();
case VOIDmode:
case DImode:
- print_operand_address (file,
+ print_operand_address (file,
GEN_INT (CONST_DOUBLE_HIGH (x)));
break;
default:
}
default:
- abort ();
+ gcc_unreachable ();
}
break;
break;
case 'N':
- if (INTVAL (x) < -128 || INTVAL (x) > 255)
- abort ();
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
fprintf (file, "%d", (int)((~INTVAL (x)) & 0xff));
break;
case 'U':
- if (INTVAL (x) < -128 || INTVAL (x) > 255)
- abort ();
+ gcc_assert (INTVAL (x) >= -128 && INTVAL (x) <= 255);
fprintf (file, "%d", (int)(INTVAL (x) & 0xff));
break;
print_operand_address (file, x);
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
}
&& REG_OK_FOR_BASE_P (XEXP (addr, 1)))
base = XEXP (addr, 1), index = XEXP (addr, 0);
else
- abort ();
+ gcc_unreachable ();
print_operand (file, index, 0);
fputc (',', file);
print_operand (file, base, 0);;
return 0;
for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
- if (regs_ever_live[i] && ! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! call_used_regs[i])
++n;
return n;
/* Print a set of registers in the format required by "movm" and "ret".
Register K is saved if bit K of MASK is set. The data and address
registers can be stored individually, but the extended registers cannot.
- We assume that the mask alread takes that into account. For instance,
+ We assume that the mask already takes that into account. For instance,
bits 14 to 17 must have the same value. */
void
if ((mask & 0x3c000) != 0)
{
- if ((mask & 0x3c000) != 0x3c000)
- abort();
+ gcc_assert ((mask & 0x3c000) == 0x3c000);
if (need_comma)
fputc (',', file);
fputs ("exreg1", file);
return (reload_completed
&& size == 0
- && !regs_ever_live[2]
- && !regs_ever_live[3]
- && !regs_ever_live[6]
- && !regs_ever_live[7]
- && !regs_ever_live[14]
- && !regs_ever_live[15]
- && !regs_ever_live[16]
- && !regs_ever_live[17]
+ && !df_regs_ever_live_p (2)
+ && !df_regs_ever_live_p (3)
+ && !df_regs_ever_live_p (6)
+ && !df_regs_ever_live_p (7)
+ && !df_regs_ever_live_p (14)
+ && !df_regs_ever_live_p (15)
+ && !df_regs_ever_live_p (16)
+ && !df_regs_ever_live_p (17)
&& fp_regs_to_save () == 0
&& !frame_pointer_needed);
}
mask = 0;
for (i = 0; i <= LAST_EXTENDED_REGNUM; i++)
- if (regs_ever_live[i] && ! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! call_used_regs[i])
mask |= (1 << i);
if ((mask & 0x3c000) != 0)
mask |= 0x3c000;
break;
default:
- abort ();
+ gcc_unreachable ();
}
-
+
/* Now prepare register a0, if we have decided to use it. */
switch (strategy)
{
emit_insn (gen_addsi3 (reg, reg, GEN_INT (xsize)));
reg = gen_rtx_POST_INC (SImode, reg);
break;
-
+
default:
- abort ();
+ gcc_unreachable ();
}
-
+
/* Now actually save the FP registers. */
for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
- if (regs_ever_live[i] && ! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! call_used_regs[i])
{
rtx addr;
}
else
addr = stack_pointer_rtx;
-
+
xsize += 4;
}
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (-size)));
- if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
- {
- rtx insn = get_last_insn ();
- rtx last = emit_insn (gen_GOTaddr2picreg ());
-
- /* Mark these insns as possibly dead. Sometimes, flow2 may
- delete all uses of the PIC register. In this case, let it
- delete the initialization too. */
- do
- {
- insn = NEXT_INSN (insn);
-
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
- const0_rtx,
- REG_NOTES (insn));
- }
- while (insn != last);
- }
+ if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM))
+ emit_insn (gen_GOTaddr2picreg ());
}
void
+ REG_SAVE_BYTES - 252)));
size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save;
break;
-
+
case restore_a1:
reg = gen_rtx_REG (SImode, FIRST_ADDRESS_REGNUM + 1);
emit_insn (gen_movsi (reg, stack_pointer_rtx));
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
reg = gen_rtx_POST_INC (SImode, reg);
for (i = FIRST_FP_REGNUM; i <= LAST_FP_REGNUM; ++i)
- if (regs_ever_live[i] && ! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ! call_used_regs[i])
{
rtx addr;
-
+
if (reg)
addr = reg;
else if (size)
If the stack size + register save area is more than 255 bytes,
then the stack must be cut back here since the size + register
- save size is too big for a ret/retf instruction.
+ save size is too big for a ret/retf instruction.
Else leave it alone, it will be cut back as part of the
ret/retf instruction, or there wasn't any stack to begin with.
}
/* Adjust the stack and restore callee-saved registers, if any. */
- if (size || regs_ever_live[2] || regs_ever_live[3]
- || regs_ever_live[6] || regs_ever_live[7]
- || regs_ever_live[14] || regs_ever_live[15]
- || regs_ever_live[16] || regs_ever_live[17]
+ if (size || df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+ || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+ || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+ || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
|| frame_pointer_needed)
emit_jump_insn (gen_return_internal_regs
(GEN_INT (size + REG_SAVE_BYTES)));
break;
default:
- abort ();
+ gcc_unreachable ();
}
}
}
/* What (if any) secondary registers are needed to move IN with mode
- MODE into a register in register class CLASS.
+ MODE into a register in register class CLASS.
We might be able to simplify this. */
enum reg_class
-secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
+mn10300_secondary_reload_class (enum reg_class class, enum machine_mode mode,
+ rtx in)
{
/* Memory loads less than a full word wide can't have an
address or stack pointer destination. They must use
if (GET_CODE (in) == PLUS
&& (XEXP (in, 0) == stack_pointer_rtx
|| XEXP (in, 1) == stack_pointer_rtx))
- {
- if (TARGET_AM33)
- return DATA_OR_EXTENDED_REGS;
- return DATA_REGS;
- }
-
+ return GENERAL_REGS;
+
if (TARGET_AM33_2 && class == FP_REGS
- && GET_CODE (in) == MEM && ! OK_FOR_Q (in))
+ && GET_CODE (in) == MEM
+ && ! (GET_CODE (in) == MEM && !CONSTANT_ADDRESS_P (XEXP (in, 0))))
{
if (TARGET_AM33)
return DATA_OR_EXTENDED_REGS;
is the size of the callee register save area. */
if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
{
- if (regs_ever_live[2] || regs_ever_live[3]
- || regs_ever_live[6] || regs_ever_live[7]
- || regs_ever_live[14] || regs_ever_live[15]
- || regs_ever_live[16] || regs_ever_live[17]
+ if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+ || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+ || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+ || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
|| fp_regs_to_save ()
|| frame_pointer_needed)
return REG_SAVE_BYTES
area, and the fixed stack space needed for function calls (if any). */
if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
{
- if (regs_ever_live[2] || regs_ever_live[3]
- || regs_ever_live[6] || regs_ever_live[7]
- || regs_ever_live[14] || regs_ever_live[15]
- || regs_ever_live[16] || regs_ever_live[17]
+ if (df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
+ || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
+ || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
+ || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
|| fp_regs_to_save ()
|| frame_pointer_needed)
return (get_frame_size () + REG_SAVE_BYTES
+ 4 * fp_regs_to_save ()
+ (current_function_outgoing_args_size
- ? current_function_outgoing_args_size + 4 : 0));
+ ? current_function_outgoing_args_size + 4 : 0));
else
return (get_frame_size ()
+ (current_function_outgoing_args_size
- ? current_function_outgoing_args_size + 4 : 0));
+ ? current_function_outgoing_args_size + 4 : 0));
}
/* The difference between the frame pointer and stack pointer is the sum
if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return (get_frame_size ()
+ (current_function_outgoing_args_size
- ? current_function_outgoing_args_size + 4 : 0));
+ ? current_function_outgoing_args_size + 4 : 0));
- abort ();
+ gcc_unreachable ();
}
/* Worker function for TARGET_RETURN_IN_MEMORY. */
static bool
-mn10300_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+mn10300_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
/* Return values > 8 bytes in length in memory. */
- return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;
+ return (int_size_in_bytes (type) > 8
+ || int_size_in_bytes (type) == 0
+ || TYPE_MODE (type) == BLKmode);
}
/* Flush the argument registers to the stack for a stdarg function;
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
!= void_type_node)))
? UNITS_PER_WORD : 0);
- int set = get_varargs_alias_set ();
+ alias_set_type set = get_varargs_alias_set ();
if (argadj)
offset = plus_constant (current_function_arg_offset_rtx, argadj);
offset, 0, 0, OPTAB_LIB_WIDEN));
}
-void
+static void
mn10300_va_start (tree valist, rtx nextarg)
{
nextarg = expand_builtin_saveregs ();
static bool
mn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
- enum machine_mode mode, tree type,
+ enum machine_mode mode, const_tree type,
bool named ATTRIBUTE_UNUSED)
{
unsigned HOST_WIDE_INT size;
else
size = GET_MODE_SIZE (mode);
- return size > 8;
+ return (size > 8 || size == 0);
}
/* Return an RTX to represent where a value with mode MODE will be returned
return nregs * UNITS_PER_WORD - cum->nbytes;
}
+/* Return the location of the function's value. This will be either
+ $d0 for integer functions, $a0 for pointers, or a PARALLEL of both
+ $d0 and $a0 if the -mreturn-pointer-on-do flag is set. Note that
+ we only return the PARALLEL for outgoing values; we do not want
+ callers relying on this extra copy. */
+
+rtx
+mn10300_function_value (const_tree valtype, const_tree func, int outgoing)
+{
+ rtx rv;
+ enum machine_mode mode = TYPE_MODE (valtype);
+
+ if (! POINTER_TYPE_P (valtype))
+ return gen_rtx_REG (mode, FIRST_DATA_REGNUM);
+ else if (! TARGET_PTR_A0D0 || ! outgoing
+ || current_function_returns_struct)
+ return gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM);
+
+ rv = gen_rtx_PARALLEL (mode, rtvec_alloc (2));
+ XVECEXP (rv, 0, 0)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, FIRST_ADDRESS_REGNUM),
+ GEN_INT (0));
+
+ XVECEXP (rv, 0, 1)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (mode, FIRST_DATA_REGNUM),
+ GEN_INT (0));
+ return rv;
+}
+
/* Output a tst insn. */
const char *
output_tst (rtx operand, rtx insn)
}
/* Are we setting a data register to zero (this does not win for
- address registers)?
+ address registers)?
If it's a call clobbered register, have we past a call?
== REGNO_REG_CLASS (REGNO (operand)))
&& REGNO_REG_CLASS (REGNO (SET_DEST (set))) != EXTENDED_REGS
&& REGNO (SET_DEST (set)) != REGNO (operand)
- && (!past_call
+ && (!past_call
|| !call_used_regs[REGNO (SET_DEST (set))]))
{
rtx xoperands[2];
!= REGNO_REG_CLASS (REGNO (operand)))
&& REGNO_REG_CLASS (REGNO (SET_DEST (set))) == EXTENDED_REGS
&& REGNO (SET_DEST (set)) != REGNO (operand)
- && (!past_call
+ && (!past_call
|| !call_used_regs[REGNO (SET_DEST (set))]))
{
rtx xoperands[2];
return 5;
default:
- abort ();
+ gcc_unreachable ();
}
case PLUS:
return 8;
default:
- abort ();
+ gcc_unreachable ();
}
}
val[1] = INTVAL (high);
}
break;
-
+
case CONST_DOUBLE:
if (GET_MODE (operands[1]) == DFmode)
{
val[1] = CONST_DOUBLE_HIGH (operands[1]);
}
break;
-
+
default:
return false;
}