/* Subroutines used for code generation on the Argonaut ARC cpu.
- Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
- Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC is free software; you can redistribute it and/or modify
+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.
-GNU CC is distributed in the hope that it will be useful,
+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 GNU CC; 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/>. */
/* ??? This is an old port, and is undoubtedly suffering from bit rot. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "target.h"
#include "target-def.h"
-/* Which cpu we're compiling for (NULL(=base), ???). */
-const char *arc_cpu_string;
+/* Which cpu we're compiling for. */
int arc_cpu_type;
/* Name of mangle string to add to symbols to separate code compiled for each
generate a scc or bcc insn. */
rtx arc_compare_op0, arc_compare_op1;
-/* Name of text, data, and rodata sections, as specified on command line.
- Selected by -m{text,data,rodata} flags. */
-const char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;
-const char *arc_data_string = ARC_DEFAULT_DATA_SECTION;
-const char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;
-
/* Name of text, data, and rodata sections used in varasm.c. */
const char *arc_text_section;
const char *arc_data_section;
arc_print_operand. */
static int last_insn_set_cc_p;
static int current_insn_set_cc_p;
-static void record_cc_ref PARAMS ((rtx));
-static void arc_init_reg_tables PARAMS ((void));
-static int get_arc_condition_code PARAMS ((rtx));
+static bool arc_handle_option (size_t, const char *, int);
+static void record_cc_ref (rtx);
+static void arc_init_reg_tables (void);
+static int get_arc_condition_code (rtx);
const struct attribute_spec arc_attribute_table[];
-static tree arc_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
-static bool arc_assemble_integer PARAMS ((rtx, unsigned int, int));
-static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static tree arc_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
+static bool arc_assemble_integer (rtx, unsigned int, int);
+static void arc_output_function_prologue (FILE *, HOST_WIDE_INT);
+static void arc_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static void arc_file_start (void);
+static void arc_internal_label (FILE *, const char *, unsigned long);
+static void arc_va_start (tree, rtx);
+static void arc_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, int *, int);
+static bool arc_rtx_costs (rtx, int, int, int *, bool);
+static int arc_address_cost (rtx, bool);
+static void arc_external_libcall (rtx);
+static bool arc_return_in_memory (const_tree, const_tree);
+static bool arc_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+ const_tree, bool);
\f
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START arc_file_start
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE arc_attribute_table
+#undef TARGET_ASM_INTERNAL_LABEL
+#define TARGET_ASM_INTERNAL_LABEL arc_internal_label
+#undef TARGET_ASM_EXTERNAL_LIBCALL
+#define TARGET_ASM_EXTERNAL_LIBCALL arc_external_libcall
+
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION arc_handle_option
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS arc_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST arc_address_cost
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY arc_return_in_memory
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE arc_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS arc_setup_incoming_varargs
+
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START arc_va_start
struct gcc_target targetm = TARGET_INITIALIZER;
\f
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+arc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_mcpu_:
+ return strcmp (arg, "base") == 0 || ARC_EXTENSION_CPU (arg);
+
+ default:
+ return true;
+ }
+}
+
/* Called by OVERRIDE_OPTIONS to initialize various things. */
void
{
char *tmp;
- if (arc_cpu_string == 0
- || !strcmp (arc_cpu_string, "base"))
- {
- /* Ensure we have a printable value for the .cpu pseudo-op. */
- arc_cpu_string = "base";
- arc_cpu_type = 0;
- arc_mangle_cpu = NULL;
- }
- else if (ARC_EXTENSION_CPU (arc_cpu_string))
- ; /* nothing to do */
- else
- {
- error ("bad value (%s) for -mcpu switch", arc_cpu_string);
- arc_cpu_string = "base";
- arc_cpu_type = 0;
- arc_mangle_cpu = NULL;
- }
-
/* Set the pseudo-ops for the various standard sections. */
- arc_text_section = tmp = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+ arc_text_section = tmp = XNEWVEC (char, strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string);
- arc_data_section = tmp = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+ arc_data_section = tmp = XNEWVEC (char, strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string);
- arc_rodata_section = tmp = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+ arc_rodata_section = tmp = XNEWVEC (char, strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string);
arc_init_reg_tables ();
`(eq (...) (...))'. */
static int
-get_arc_condition_code (comparison)
- rtx comparison;
+get_arc_condition_code (rtx comparison)
{
switch (GET_CODE (comparison))
{
case LEU : return 15;
case LTU : return 6;
case GEU : return 7;
- default : abort ();
+ default : gcc_unreachable ();
}
/*NOTREACHED*/
return (42);
return the mode to be used for the comparison. */
enum machine_mode
-arc_select_cc_mode (op, x, y)
- enum rtx_code op;
- rtx x, y ATTRIBUTE_UNUSED;
+arc_select_cc_mode (enum rtx_code op,
+ rtx x ATTRIBUTE_UNUSED,
+ rtx y ATTRIBUTE_UNUSED)
{
switch (op)
{
indexed by hard register number, and one indexed by mode. */
/* The purpose of arc_mode_class is to shrink the range of modes so that
- they all fit (as bit numbers) in a 32 bit word (again). Each real mode is
+ they all fit (as bit numbers) in a 32-bit word (again). Each real mode is
mapped into one arc_mode_class mode. */
enum arc_mode_class {
enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER];
static void
-arc_init_reg_tables ()
+arc_init_reg_tables (void)
{
int i;
arc_mode_class[i] = 0;
break;
case MODE_CC:
+ arc_mode_class[i] = 1 << (int) C_MODE;
+ break;
default:
- /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so
- we must explicitly check for them here. */
- if (i == (int) CCmode || i == (int) CCZNmode || i == (int) CCZNCmode)
- arc_mode_class[i] = 1 << (int) C_MODE;
- else
- arc_mode_class[i] = 0;
+ arc_mode_class[i] = 0;
break;
}
}
/* Handle an "interrupt" attribute; arguments as in
struct attribute_spec.handler. */
static tree
-arc_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
- tree *node ATTRIBUTE_UNUSED;
- tree name;
- tree args;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
+arc_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
+ tree name,
+ tree args,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
{
tree value = TREE_VALUE (args);
if (TREE_CODE (value) != STRING_CST)
{
- warning ("argument of `%s' attribute is not a string constant",
+ warning (OPT_Wattributes,
+ "argument of %qs attribute is not a string constant",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else if (strcmp (TREE_STRING_POINTER (value), "ilink1")
&& strcmp (TREE_STRING_POINTER (value), "ilink2"))
{
- warning ("argument of `%s' attribute is not \"ilink1\" or \"ilink2\"",
+ warning (OPT_Wattributes,
+ "argument of %qs attribute is not \"ilink1\" or \"ilink2\"",
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
/* Acceptable arguments to the call insn. */
int
-call_address_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+call_address_operand (rtx op, enum machine_mode mode)
{
return (symbolic_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && LEGITIMATE_CONSTANT_P (op))
}
int
-call_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+call_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
/* Returns 1 if OP is a symbol reference. */
int
-symbolic_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
operand of mode MODE. */
int
-symbolic_memory_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
/* Return true if OP is a short immediate (shimm) value. */
int
-short_immediate_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+short_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return 0;
This is currently only used when calculating length attributes. */
int
-long_immediate_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+long_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case CONST_INT :
return !SMALL_INT (INTVAL (op));
case CONST_DOUBLE :
- /* These can happen because large unsigned 32 bit constants are
+ /* These can happen because large unsigned 32-bit constants are
represented this way (the multiplication patterns can cause these
to be generated). They also occur for SFmode values. */
return 1;
This is currently only used when calculating length attributes. */
int
-long_immediate_loadstore_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+long_immediate_loadstore_operand (rtx op,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != MEM)
return 0;
assume that it does. */
return 1;
case CONST_DOUBLE :
- /* These can happen because large unsigned 32 bit constants are
+ /* These can happen because large unsigned 32-bit constants are
represented this way (the multiplication patterns can cause these
to be generated). They also occur for SFmode values. */
return 1;
move source. */
int
-move_src_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+move_src_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
case CONST_DOUBLE :
/* We can handle DImode integer constants in SImode if the value
(signed or unsigned) will fit in 32 bits. This is needed because
- large unsigned 32 bit constants are represented as CONST_DOUBLEs. */
+ large unsigned 32-bit constants are represented as CONST_DOUBLEs. */
if (mode == SImode)
return arc_double_limm_p (op);
- /* We can handle 32 bit floating point constants. */
+ /* We can handle 32-bit floating point constants. */
if (mode == SFmode)
return GET_MODE (op) == SFmode;
return 0;
move source. */
int
-move_double_src_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+move_double_src_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
/* Return true if OP is an acceptable argument for a move destination. */
int
-move_dest_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+move_dest_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
/* Return true if OP is valid load with update operand. */
int
-load_update_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+load_update_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM
|| GET_MODE (op) != mode)
/* Return true if OP is valid store with update operand. */
int
-store_update_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+store_update_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM
|| GET_MODE (op) != mode)
and only the standard movXX patterns are set up to handle them. */
int
-nonvol_nonimm_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+nonvol_nonimm_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
return 0;
contexts. */
int
-const_sint32_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+const_sint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
/* All allowed constants will fit a CONST_INT. */
return (GET_CODE (op) == CONST_INT
need some extra crud to make it work when hosted on 64-bit machines. */
int
-const_uint32_operand (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+const_uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if HOST_BITS_PER_WIDE_INT > 32
/* All allowed constants will fit a CONST_INT. */
comparisons that use the bits that are valid. */
int
-proper_comparison_operator (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+proper_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
- enum rtx_code code = GET_CODE (op);
-
- if (GET_RTX_CLASS (code) != '<')
+ enum rtx_code code;
+ if (!COMPARISON_P (op))
return 0;
+ code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CCZNmode)
return (code == EQ || code == NE);
if (GET_MODE (XEXP (op, 0)) == CCZNCmode)
return the rtx for the cc reg in the proper mode. */
rtx
-gen_compare_reg (code, x, y)
- enum rtx_code code;
- rtx x, y;
+gen_compare_reg (enum rtx_code code, rtx x, rtx y)
{
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
rtx cc_reg;
We assume the value can be either signed or unsigned. */
int
-arc_double_limm_p (value)
- rtx value;
+arc_double_limm_p (rtx value)
{
HOST_WIDE_INT low, high;
- if (GET_CODE (value) != CONST_DOUBLE)
- abort ();
+ gcc_assert (GET_CODE (value) == CONST_DOUBLE);
low = CONST_DOUBLE_LOW (value);
high = CONST_DOUBLE_HIGH (value);
aligned. So we round the space up if necessary, and leave it to va_start
to compensate. */
-void
-arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
- CUMULATIVE_ARGS *cum;
- enum machine_mode mode;
- tree type ATTRIBUTE_UNUSED;
- int *pretend_size;
- int no_rtl;
+static void
+arc_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
+ enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED,
+ int *pretend_size,
+ int no_rtl)
{
int first_anon_arg;
/* All BLKmode values are passed by reference. */
- if (mode == BLKmode)
- abort ();
+ gcc_assert (mode != BLKmode);
- /* We must treat `__builtin_va_alist' as an anonymous arg. */
- if (current_function_varargs)
- first_anon_arg = *cum;
- else
- first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
- / UNITS_PER_WORD);
+ first_anon_arg = *cum + ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD);
if (first_anon_arg < MAX_ARC_PARM_REGS && !no_rtl)
{
set_mem_alias_set (regblock, get_varargs_alias_set ());
set_mem_align (regblock, BITS_PER_WORD);
move_block_from_reg (first_reg_offset, regblock,
- MAX_ARC_PARM_REGS - first_reg_offset,
- ((MAX_ARC_PARM_REGS - first_reg_offset)
- * UNITS_PER_WORD));
+ MAX_ARC_PARM_REGS - first_reg_offset);
*pretend_size = ((MAX_ARC_PARM_REGS - first_reg_offset + align_slop)
* UNITS_PER_WORD);
\f
/* Cost functions. */
+/* Compute a (partial) cost for rtx X. Return true if the complete
+ cost has been computed, and false if subexpressions should be
+ scanned. In either case, *TOTAL contains the cost result. */
+
+static bool
+arc_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ /* Small integers are as cheap as registers. 4 byte values can
+ be fetched as immediate constants - let's give that the cost
+ of an extra insn. */
+ case CONST_INT:
+ if (SMALL_INT (INTVAL (x)))
+ {
+ *total = 0;
+ return true;
+ }
+ /* FALLTHRU */
+
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (1);
+ return true;
+
+ case CONST_DOUBLE:
+ {
+ rtx high, low;
+ split_double (x, &high, &low);
+ *total = COSTS_N_INSNS (!SMALL_INT (INTVAL (high))
+ + !SMALL_INT (INTVAL (low)));
+ return true;
+ }
+
+ /* Encourage synth_mult to find a synthetic multiply when reasonable.
+ If we need more than 12 insns to do a multiply, then go out-of-line,
+ since the call overhead will be < 10% of the cost of the multiply. */
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ if (TARGET_SHIFTER)
+ *total = COSTS_N_INSNS (1);
+ else if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ *total = COSTS_N_INSNS (16);
+ else
+ *total = COSTS_N_INSNS (INTVAL (XEXP ((x), 1)));
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+
/* Provide the costs of an addressing mode that contains ADDR.
If ADDR is not a valid address, its cost is irrelevant. */
-int
-arc_address_cost (addr)
- rtx addr;
+static int
+arc_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
{
switch (GET_CODE (addr))
{
case REG :
- /* This is handled in the macro that calls us.
- It's here for documentation. */
return 1;
case LABEL_REF :
call with DECL = NULL_TREE. */
enum arc_function_type
-arc_compute_function_type (decl)
- tree decl;
+arc_compute_function_type (tree decl)
{
tree a;
/* Cached value. */
else if (!strcmp (TREE_STRING_POINTER (value), "ilink2"))
fn_type = ARC_FUNCTION_ILINK2;
else
- abort ();
+ gcc_unreachable ();
break;
}
}
Don't consider them here. */
#define MUST_SAVE_REGISTER(regno, interrupt_p) \
((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
- && (regs_ever_live[regno] && (!call_used_regs[regno] || interrupt_p)))
+ && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p)))
-#define MUST_SAVE_RETURN_ADDR (regs_ever_live[RETURN_ADDR_REGNUM])
+#define MUST_SAVE_RETURN_ADDR (df_regs_ever_live_p (RETURN_ADDR_REGNUM))
/* Return the bytes needed to compute the frame pointer from the current
stack pointer.
SIZE is the size needed for local variables. */
unsigned int
-arc_compute_frame_size (size)
- int size; /* # of var. bytes allocated. */
+arc_compute_frame_size (int size /* # of var. bytes allocated. */)
{
int regno;
unsigned int total_size, var_size, args_size, pretend_size, extra_size;
int interrupt_p;
var_size = size;
- args_size = current_function_outgoing_args_size;
- pretend_size = current_function_pretend_args_size;
+ args_size = crtl->outgoing_args_size;
+ pretend_size = crtl->args.pretend_args_size;
extra_size = FIRST_PARM_OFFSET (0);
total_size = extra_size + pretend_size + args_size + var_size;
- reg_offset = FIRST_PARM_OFFSET(0) + current_function_outgoing_args_size;
+ reg_offset = FIRST_PARM_OFFSET(0) + crtl->outgoing_args_size;
reg_size = 0;
gmask = 0;
/* Common code to save/restore registers. */
void
-arc_save_restore (file, base_reg, offset, gmask, op)
- FILE *file;
- const char *base_reg;
- unsigned int offset;
- unsigned int gmask;
- const char *op;
+arc_save_restore (FILE *file,
+ const char *base_reg,
+ unsigned int offset,
+ unsigned int gmask,
+ const char *op)
{
int regno;
symbols. */
static bool
-arc_assemble_integer (x, size, aligned_p)
- rtx x;
- unsigned int size;
- int aligned_p;
+arc_assemble_integer (rtx x, unsigned int size, int aligned_p)
{
if (size == UNITS_PER_WORD && aligned_p
- && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
+ && ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
|| GET_CODE (x) == LABEL_REF))
{
fputs ("\t.word\t%st(", asm_out_file);
/* Set up the stack and frame pointer (if desired) for the function. */
static void
-arc_output_function_prologue (file, size)
- FILE *file;
- HOST_WIDE_INT size;
+arc_output_function_prologue (FILE *file, HOST_WIDE_INT size)
{
const char *sp_str = reg_names[STACK_POINTER_REGNUM];
const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
: current_frame_info.total_size);
/* These cases shouldn't happen. Catch them now. */
- if (size == 0 && gmask)
- abort ();
+ gcc_assert (size || !gmask);
/* Allocate space for register arguments if this is a variadic function. */
if (current_frame_info.pretend_size != 0)
/* Allocate the stack frame. */
if (size - current_frame_info.pretend_size > 0)
- fprintf (file, "\tsub %s,%s,%d\n",
+ fprintf (file, "\tsub %s,%s," HOST_WIDE_INT_PRINT_DEC "\n",
sp_str, sp_str, size - current_frame_info.pretend_size);
/* Save any needed call-saved regs (and call-used if this is an
and regs. */
static void
-arc_output_function_epilogue (file, size)
- FILE *file;
- HOST_WIDE_INT size;
+arc_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
{
- rtx epilogue_delay = current_function_epilogue_delay_list;
+ rtx epilogue_delay = crtl->epilogue_delay_list;
int noepilogue = FALSE;
enum arc_function_type fn_type = arc_compute_function_type (current_function_decl);
unsigned int pretend_size = current_frame_info.pretend_size;
unsigned int frame_size = size - pretend_size;
int restored, fp_restored_p;
- int can_trust_sp_p = !current_function_calls_alloca;
+ int can_trust_sp_p = !cfun->calls_alloca;
const char *sp_str = reg_names[STACK_POINTER_REGNUM];
const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
if (!can_trust_sp_p)
{
- if (!frame_pointer_needed)
- abort ();
+ gcc_assert (frame_pointer_needed);
fprintf (file,"\tsub %s,%s,%d\t\t%s sp not trusted here\n",
sp_str, fp_str, frame_size, ASM_COMMENT_START);
}
/* ??? If stack intactness is important, always emit now. */
if (MUST_SAVE_RETURN_ADDR && epilogue_delay != NULL_RTX)
{
- final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
+ final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
epilogue_delay = NULL_RTX;
}
{
if (epilogue_delay)
{
- final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
+ final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
}
}
static const int regs[4] = {
0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM
};
- fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]);
- }
+
+ /* Update the flags, if returning from an interrupt handler. */
+ if (ARC_INTERRUPT_P (fn_type))
+ fprintf (file, "\tj.d.f %s\n", reg_names[regs[fn_type]]);
+ else
+ fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]);
+ }
/* If the only register saved is the return address, we need a
nop, unless we have an instruction to put into it. Otherwise
fprintf (file, "\tadd %s,%s,16\n", sp_str, sp_str);
else if (epilogue_delay != NULL_RTX)
{
- if (frame_pointer_needed && !fp_restored_p)
- abort ();
- if (restored < size)
- abort ();
- final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
+ gcc_assert (!frame_pointer_needed || fp_restored_p);
+ gcc_assert (restored >= size);
+ final_scan_insn (XEXP (epilogue_delay, 0), file, 1, 1, NULL);
}
else if (frame_pointer_needed && !fp_restored_p)
{
- if (!SMALL_INT (frame_size))
- abort ();
+ gcc_assert (SMALL_INT (frame_size));
/* Note that we restore fp and sp here! */
fprintf (file, "\tld.a %s,[%s,%d]\n", fp_str, sp_str, frame_size);
}
else if (restored < size)
{
- if (!SMALL_INT (size - restored))
- abort ();
- fprintf (file, "\tadd %s,%s,%d\n",
+ gcc_assert (SMALL_INT (size - restored));
+ fprintf (file, "\tadd %s,%s," HOST_WIDE_INT_PRINT_DEC "\n",
sp_str, sp_str, size - restored);
}
else
delay slot so for now we only consider functions with empty frames. */
int
-arc_delay_slots_for_epilogue ()
+arc_delay_slots_for_epilogue (void)
{
if (arc_compute_function_type (current_function_decl) != ARC_FUNCTION_NORMAL)
return 0;
pointer or any call-saved register is OK. SLOT will always be 0. */
int
-arc_eligible_for_epilogue_delay (trial, slot)
- rtx trial;
- int slot;
+arc_eligible_for_epilogue_delay (rtx trial, int slot)
{
- if (slot != 0)
- abort ();
+ gcc_assert (!slot);
if (get_attr_length (trial) == 1
/* If registers where saved, presumably there's more than enough
return 0;
}
\f
-/* PIC */
-
-/* Emit special PIC prologues and epilogues. */
-
-void
-arc_finalize_pic ()
-{
- /* nothing to do */
-}
-\f
/* Return true if OP is a shift operator. */
int
-shift_operator (op, mode)
- rtx op;
- enum machine_mode mode ATTRIBUTE_UNUSED;
+shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
using it here will give us a chance to play with it. */
const char *
-output_shift (operands)
- rtx *operands;
+output_shift (rtx *operands)
{
rtx shift = operands[3];
enum machine_mode mode = GET_MODE (shift);
enum rtx_code code = GET_CODE (shift);
const char *shift_one;
- if (mode != SImode)
- abort ();
+ gcc_assert (mode == SImode);
switch (code)
{
case ASHIFT: shift_one = "asl %0,%0"; break;
case ASHIFTRT: shift_one = "asr %0,%0"; break;
case LSHIFTRT: shift_one = "lsr %0,%0"; break;
- default: abort ();
+ default: gcc_unreachable ();
}
if (GET_CODE (operands[2]) != CONST_INT)
{
if (optimize)
- output_asm_insn ("mov lp_count,%2", operands);
+ {
+ output_asm_insn ("sub.f 0,%2,0", operands);
+ output_asm_insn ("mov lp_count,%2", operands);
+ output_asm_insn ("bz 2f", operands);
+ }
else
output_asm_insn ("mov %4,%2", operands);
goto shiftloop;
output_asm_insn ("sr %4,[lp_end]", operands);
output_asm_insn ("nop\n\tnop", operands);
if (flag_pic)
- asm_fprintf (asm_out_file, "\t%s single insn loop\n",
- ASM_COMMENT_START);
+ fprintf (asm_out_file, "\t%s single insn loop\n",
+ ASM_COMMENT_START);
else
- asm_fprintf (asm_out_file, "1:\t%s single insn loop\n",
- ASM_COMMENT_START);
+ fprintf (asm_out_file, "1:\t%s single insn loop\n",
+ ASM_COMMENT_START);
output_asm_insn (shift_one, operands);
+ fprintf (asm_out_file, "2:\t%s end single insn loop\n",
+ ASM_COMMENT_START);
}
else
{
- asm_fprintf (asm_out_file, "1:\t%s begin shift loop\n",
- ASM_COMMENT_START);
+ fprintf (asm_out_file, "1:\t%s begin shift loop\n",
+ ASM_COMMENT_START);
output_asm_insn ("sub.f %4,%4,1", operands);
output_asm_insn ("nop", operands);
output_asm_insn ("bn.nd 2f", operands);
output_asm_insn (shift_one, operands);
output_asm_insn ("b.nd 1b", operands);
- asm_fprintf (asm_out_file, "2:\t%s end shift loop\n",
- ASM_COMMENT_START);
+ fprintf (asm_out_file, "2:\t%s end shift loop\n",
+ ASM_COMMENT_START);
}
}
}
CXT is an RTX for the static chain value for the function. */
void
-arc_initialize_trampoline (tramp, fnaddr, cxt)
- rtx tramp ATTRIBUTE_UNUSED, fnaddr ATTRIBUTE_UNUSED, cxt ATTRIBUTE_UNUSED;
+arc_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED,
+ rtx fnaddr ATTRIBUTE_UNUSED,
+ rtx cxt ATTRIBUTE_UNUSED)
{
}
\f
/* Set the cpu type and print out other fancy things,
at the top of the file. */
-void
-arc_asm_file_start (file)
- FILE *file;
+static void
+arc_file_start (void)
{
- fprintf (file, "\t.cpu %s\n", arc_cpu_string);
+ default_file_start ();
+ fprintf (asm_out_file, "\t.cpu %s\n", arc_cpu_string);
}
\f
/* Print operand X (an rtx) in assembler syntax to file FILE.
For `%' followed by punctuation, CODE is the punctuation and X is null. */
void
-arc_print_operand (file, x, code)
- FILE *file;
- rtx x;
- int code;
+arc_print_operand (FILE *file, rtx x, int code)
{
switch (code)
{
output_operand_lossage ("invalid operand to %%R code");
return;
case 'S' :
- if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
+ if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (x))
|| GET_CODE (x) == LABEL_REF)
{
fprintf (file, "%%st(");
return;
case 'A' :
{
- REAL_VALUE_TYPE d;
char str[30];
- if (GET_CODE (x) != CONST_DOUBLE
- || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
- abort ();
- REAL_VALUE_FROM_CONST_DOUBLE (d, x);
- REAL_VALUE_TO_DECIMAL (d, "%.20e", str);
+ gcc_assert (GET_CODE (x) == CONST_DOUBLE
+ && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
+
+ real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1);
fprintf (file, "%s", str);
return;
}
/* Print a memory address as an operand to reference that memory location. */
void
-arc_print_operand_address (file, addr)
- FILE *file;
- rtx addr;
+arc_print_operand_address (FILE *file, rtx addr)
{
register rtx base, index = 0;
int offset = 0;
fputs (reg_names[REGNO (addr)], file);
break;
case SYMBOL_REF :
- if (/*???*/ 0 && SYMBOL_REF_FLAG (addr))
+ if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
{
fprintf (file, "%%st(");
output_addr_const (file, addr);
offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
else
base = XEXP (addr, 0), index = XEXP (addr, 1);
- if (GET_CODE (base) != REG)
- abort ();
+ gcc_assert (GET_CODE (base) == REG);
fputs (reg_names[REGNO (base)], file);
if (index == 0)
{
if (offset != 0)
fprintf (file, ",%d", offset);
}
- else if (GET_CODE (index) == REG)
- fprintf (file, ",%s", reg_names[REGNO (index)]);
- else if (GET_CODE (index) == SYMBOL_REF)
- fputc (',', file), output_addr_const (file, index);
else
- abort ();
+ {
+ switch (GET_CODE (index))
+ {
+ case REG:
+ fprintf (file, ",%s", reg_names[REGNO (index)]);
+ break;
+ case SYMBOL_REF:
+ fputc (',', file), output_addr_const (file, index);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
break;
case PRE_INC :
case PRE_DEC :
/* We shouldn't get here as we've lost the mode of the memory object
(which says how much to inc/dec by. */
- abort ();
+ gcc_unreachable ();
break;
default :
output_addr_const (file, addr);
/* Update compare/branch separation marker. */
static void
-record_cc_ref (insn)
- rtx insn;
+record_cc_ref (rtx insn)
{
last_insn_set_cc_p = current_insn_set_cc_p;
0 -> 2 final_prescan_insn, if the `target' is an unconditional branch
1 -> 3 branch patterns, after having not output the conditional branch
2 -> 4 branch patterns, after having not output the conditional branch
- 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL, if the `target' label is reached
+ 3 -> 0 (*targetm.asm_out.internal_label), if the `target' label is reached
(the target label has CODE_LABEL_NUMBER equal to
arc_ccfsm_target_label).
4 -> 0 final_prescan_insn, if `target' unconditional branch is reached
we may not be outputting the branch. */
void
-arc_final_prescan_insn (insn, opvec, noperands)
- rtx insn;
- rtx *opvec ATTRIBUTE_UNUSED;
- int noperands ATTRIBUTE_UNUSED;
+arc_final_prescan_insn (rtx insn,
+ rtx *opvec ATTRIBUTE_UNUSED,
+ int noperands ATTRIBUTE_UNUSED)
{
/* BODY will hold the body of INSN. */
register rtx body = PATTERN (insn);
- /* This will be 1 if trying to repeat the trick (ie: do the `else' part of
+ /* This will be 1 if trying to repeat the trick (i.e.: do the `else' part of
an if/then/else), and things need to be reversed. */
int reverse = 0;
then_not_else = FALSE;
}
else
- abort ();
+ gcc_unreachable ();
/* See how many insns this branch skips, and what kind of insns. If all
insns are okay, and the label or unconditional branch to the same
{
if ((!seeking_return) && (arc_ccfsm_state == 1 || reverse))
arc_ccfsm_target_label = CODE_LABEL_NUMBER (label);
- else if (seeking_return || arc_ccfsm_state == 2)
+ else
{
+ gcc_assert (seeking_return || arc_ccfsm_state == 2);
while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
{
this_insn = next_nonnote_insn (this_insn);
- if (this_insn && (GET_CODE (this_insn) == BARRIER
- || GET_CODE (this_insn) == CODE_LABEL))
- abort ();
+ gcc_assert (!this_insn
+ || (GET_CODE (this_insn) != BARRIER
+ && GET_CODE (this_insn) != CODE_LABEL));
}
if (!this_insn)
{
}
arc_ccfsm_target_insn = this_insn;
}
- else
- abort ();
/* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from
what it was. */
/* Record that we are currently outputting label NUM with prefix PREFIX.
It it's the label we're looking for, reset the ccfsm machinery.
- Called from ASM_OUTPUT_INTERNAL_LABEL. */
+ Called from (*targetm.asm_out.internal_label). */
void
-arc_ccfsm_at_label (prefix, num)
- const char *prefix;
- int num;
+arc_ccfsm_at_label (const char *prefix, int num)
{
if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num
&& !strcmp (prefix, "L"))
deleted. */
int
-arc_ccfsm_branch_deleted_p ()
+arc_ccfsm_branch_deleted_p (void)
{
if (arc_ccfsm_state == 1 || arc_ccfsm_state == 2)
return 1;
conditionalized. */
void
-arc_ccfsm_record_branch_deleted ()
+arc_ccfsm_record_branch_deleted (void)
{
/* Indicate we're conditionalizing insns now. */
arc_ccfsm_state += 2;
current_insn_set_cc_p = last_insn_set_cc_p;
}
\f
-void
-arc_va_start (stdarg_p, valist, nextarg)
- int stdarg_p;
- tree valist;
- rtx nextarg;
+static void
+arc_va_start (tree valist, rtx nextarg)
{
/* See arc_setup_incoming_varargs for reasons for this oddity. */
- if (current_function_args_info < 8
- && (current_function_args_info & 1))
+ if (crtl->args.info < 8
+ && (crtl->args.info & 1))
nextarg = plus_constant (nextarg, UNITS_PER_WORD);
- std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+ std_expand_builtin_va_start (valist, nextarg);
}
-rtx
-arc_va_arg (valist, type)
- tree valist, type;
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+static void
+arc_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
{
- rtx addr_rtx;
- tree addr, incr;
- tree type_ptr = build_pointer_type (type);
+ arc_ccfsm_at_label (prefix, labelno);
+ default_internal_label (stream, prefix, labelno);
+}
- /* All aggregates are passed by reference. All scalar types larger
- than 8 bytes are passed by reference. */
+/* Worker function for TARGET_ASM_EXTERNAL_LIBCALL. */
- if (AGGREGATE_TYPE_P (type) || int_size_in_bytes (type) > 8)
+static void
+arc_external_libcall (rtx fun ATTRIBUTE_UNUSED)
+{
+#if 0
+/* On the ARC we want to have libgcc's for multiple cpus in one binary.
+ We can't use `assemble_name' here as that will call ASM_OUTPUT_LABELREF
+ and we'll get another suffix added on if -mmangle-cpu. */
+ if (TARGET_MANGLE_CPU_LIBGCC)
{
- tree type_ptr_ptr = build_pointer_type (type_ptr);
+ fprintf (FILE, "\t.rename\t_%s, _%s%s\n",
+ XSTR (SYMREF, 0), XSTR (SYMREF, 0),
+ arc_mangle_suffix);
+ }
+#endif
+}
- addr = build (INDIRECT_REF, type_ptr,
- build (NOP_EXPR, type_ptr_ptr, valist));
+/* Worker function for TARGET_RETURN_IN_MEMORY. */
- incr = build (PLUS_EXPR, TREE_TYPE (valist),
- valist, build_int_2 (UNITS_PER_WORD, 0));
- }
+static bool
+arc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ if (AGGREGATE_TYPE_P (type))
+ return true;
else
{
- HOST_WIDE_INT align, rounded_size;
-
- /* Compute the rounded size of the type. */
- align = PARM_BOUNDARY / BITS_PER_UNIT;
- rounded_size = (((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT
- + align - 1) / align) * align);
-
- /* Align 8 byte operands. */
- addr = valist;
- if (TYPE_ALIGN (type) > BITS_PER_WORD)
- {
- /* AP = (TYPE *)(((int)AP + 7) & -8) */
-
- addr = build (NOP_EXPR, integer_type_node, valist);
- addr = fold (build (PLUS_EXPR, integer_type_node, addr,
- build_int_2 (7, 0)));
- addr = fold (build (BIT_AND_EXPR, integer_type_node, addr,
- build_int_2 (-8, 0)));
- addr = fold (build (NOP_EXPR, TREE_TYPE (valist), addr));
- }
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ return (size == -1 || size > 8);
+ }
+}
- /* The increment is always rounded_size past the aligned pointer. */
- incr = fold (build (PLUS_EXPR, TREE_TYPE (addr), addr,
- build_int_2 (rounded_size, 0)));
+/* For ARC, All aggregates and arguments greater than 8 bytes are
+ passed by reference. */
- /* Adjust the pointer in big-endian mode. */
- if (BYTES_BIG_ENDIAN)
- {
- HOST_WIDE_INT adj;
- adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
- if (rounded_size > align)
- adj = rounded_size;
+static bool
+arc_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+ enum machine_mode mode, const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ unsigned HOST_WIDE_INT size;
- addr = fold (build (PLUS_EXPR, TREE_TYPE (addr), addr,
- build_int_2 (rounded_size - adj, 0)));
- }
+ if (type)
+ {
+ if (AGGREGATE_TYPE_P (type))
+ return true;
+ size = int_size_in_bytes (type);
}
+ else
+ size = GET_MODE_SIZE (mode);
- /* Evaluate the data address. */
- addr_rtx = expand_expr (addr, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr_rtx = copy_to_reg (addr_rtx);
-
- /* Compute new value for AP. */
- incr = build (MODIFY_EXPR, TREE_TYPE (valist), valist, incr);
- TREE_SIDE_EFFECTS (incr) = 1;
- expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- return addr_rtx;
+ return size > 8;
}