/* Subroutines used for code generation on the Argonaut ARC cpu.
- Copyright (C) 1994, 1995, 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
This file is part of GNU CC.
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
#include "recog.h"
+#include "toplev.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
/* Which cpu we're compiling for (NULL(=base), ???). */
-char *arc_cpu_string;
+const char *arc_cpu_string;
int arc_cpu_type;
/* Name of mangle string to add to symbols to separate code compiled for each
cpu (or NULL). */
-char *arc_mangle_cpu;
+const char *arc_mangle_cpu;
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
/* Name of text, data, and rodata sections, as specified on command line.
Selected by -m{text,data,rodata} flags. */
-char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;
-char *arc_data_string = ARC_DEFAULT_DATA_SECTION;
-char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;
+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. */
-char *arc_text_section;
-char *arc_data_section;
-char *arc_rodata_section;
+const char *arc_text_section;
+const char *arc_data_section;
+const char *arc_rodata_section;
/* Array of valid operand punctuation characters. */
char arc_punct_chars[256];
arc_print_operand. */
static int last_insn_set_cc_p;
static int current_insn_set_cc_p;
-static void record_cc_ref ();
-
-void arc_init_reg_tables ();
-
+static void record_cc_ref PARAMS ((rtx));
+static void arc_init_reg_tables PARAMS ((void));
+static int get_arc_condition_code PARAMS ((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 void arc_encode_section_info PARAMS ((tree, int));
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER arc_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#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_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE arc_attribute_table
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO arc_encode_section_info
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
/* Called by OVERRIDE_OPTIONS to initialize various things. */
void
arc_init (void)
{
+ char *tmp;
+
if (arc_cpu_string == 0
|| !strcmp (arc_cpu_string, "base"))
{
}
/* Set the pseudo-ops for the various standard sections. */
- arc_text_section = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1);
- sprintf (arc_text_section, ARC_SECTION_FORMAT, arc_text_string);
- arc_data_section = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1);
- sprintf (arc_data_section, ARC_SECTION_FORMAT, arc_data_string);
- arc_rodata_section = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
- sprintf (arc_rodata_section, ARC_SECTION_FORMAT, arc_rodata_string);
+ arc_text_section = tmp = xmalloc (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);
+ sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string);
+ arc_rodata_section = tmp = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1);
+ sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string);
arc_init_reg_tables ();
}
\f
/* The condition codes of the ARC, and the inverse function. */
-static char *arc_condition_codes[] =
+static const char *const arc_condition_codes[] =
{
"al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv",
"gt", "le", "ge", "lt", "hi", "ls", "pnz", 0
enum machine_mode
arc_select_cc_mode (op, x, y)
enum rtx_code op;
- rtx x, y;
+ rtx x, y ATTRIBUTE_UNUSED;
{
switch (op)
{
case ASHIFTRT :
case LSHIFTRT :
return CCZNCmode;
+ default:
+ break;
}
}
return CCmode;
/* Value is 1 if register/mode pair is acceptable on arc. */
-unsigned int arc_hard_regno_mode_ok[] = {
+const unsigned int arc_hard_regno_mode_ok[] = {
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES,
enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER];
-void
+static void
arc_init_reg_tables ()
{
int i;
interrupt - for interrupt functions
*/
-/* Return nonzero if IDENTIFIER is a valid decl attribute. */
+const struct attribute_spec arc_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
-int
-arc_valid_machine_decl_attribute (type, attributes, identifier, args)
- tree type;
- tree attributes;
- tree identifier;
+/* 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;
{
- if (identifier == get_identifier ("__interrupt__")
- && list_length (args) == 1
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
- {
- tree value = TREE_VALUE (args);
+ tree value = TREE_VALUE (args);
- if (!strcmp (TREE_STRING_POINTER (value), "ilink1")
- || !strcmp (TREE_STRING_POINTER (value), "ilink2"))
- return 1;
+ if (TREE_CODE (value) != STRING_CST)
+ {
+ warning ("argument of `%s' 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\"",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
}
- return 0;
-}
-
-/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible,
- and two if they are nearly compatible (which causes a warning to be
- generated). */
-int
-arc_comp_type_attributes (type1, type2)
- tree type1, type2;
-{
- return 1;
+ return NULL_TREE;
}
-/* Set the default attributes for TYPE. */
-
-void
-arc_set_default_type_attributes (type)
- tree type;
-{
-}
\f
/* Acceptable arguments to the call insn. */
int
symbolic_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
int
symbolic_memory_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
int
short_immediate_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT)
return 0;
int
long_immediate_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
represented this way (the multiplication patterns can cause these
to be generated). They also occur for SFmode values. */
return 1;
+ default:
+ break;
}
return 0;
}
int
long_immediate_loadstore_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != MEM)
return 0;
&& !SMALL_INT (INTVAL (XEXP (op, 1))))
return 1;
return 0;
+ default:
+ break;
}
return 0;
}
int
const_sint32_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
/* All allowed constants will fit a CONST_INT. */
return (GET_CODE (op) == CONST_INT
int
const_uint32_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
#if HOST_BITS_PER_WIDE_INT > 32
/* All allowed constants will fit a CONST_INT. */
int
proper_comparison_operator (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
arc_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
- tree type;
+ tree type ATTRIBUTE_UNUSED;
int *pretend_size;
int no_rtl;
{
if (mode == BLKmode)
abort ();
- /* 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)
{
plus_constant (arg_pointer_rtx,
FIRST_PARM_OFFSET (0)
+ align_slop * UNITS_PER_WORD));
- MEM_ALIAS_SET (regblock) = get_varargs_alias_set ();
+ 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)
}
break;
}
+ default:
+ break;
}
return 4;
fn_type = ARC_FUNCTION_NORMAL;
/* Now see if this is an interrupt handler. */
- for (a = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+ for (a = DECL_ATTRIBUTES (current_function_decl);
a;
a = TREE_CHAIN (a))
{
void
arc_save_restore (file, base_reg, offset, gmask, op)
FILE *file;
- char *base_reg;
+ const char *base_reg;
unsigned int offset;
unsigned int gmask;
- char *op;
+ const char *op;
{
int regno;
}
}
\f
+/* Target hook to assemble an integer object. The ARC version needs to
+ emit a special directive for references to labels and function
+ symbols. */
+
+static bool
+arc_assemble_integer (x, size, aligned_p)
+ 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) == LABEL_REF))
+ {
+ fputs ("\t.word\t%st(", asm_out_file);
+ output_addr_const (asm_out_file, x);
+ fputs (")\n", asm_out_file);
+ return true;
+ }
+ return default_assemble_integer (x, size, aligned_p);
+}
+\f
/* Set up the stack and frame pointer (if desired) for the function. */
-void
+static void
arc_output_function_prologue (file, size)
FILE *file;
- int size;
+ HOST_WIDE_INT size;
{
- char *sp_str = reg_names[STACK_POINTER_REGNUM];
- char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+ const char *sp_str = reg_names[STACK_POINTER_REGNUM];
+ const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
unsigned int gmask = current_frame_info.gmask;
enum arc_function_type fn_type = arc_compute_function_type (current_function_decl);
}
\f
/* Do any necessary cleanup after a function to restore stack, frame,
- and regs. */
+ and regs. */
-void
+static void
arc_output_function_epilogue (file, size)
FILE *file;
- int size;
+ HOST_WIDE_INT size;
{
rtx epilogue_delay = current_function_epilogue_delay_list;
int noepilogue = FALSE;
unsigned int frame_size = size - pretend_size;
int restored, fp_restored_p;
int can_trust_sp_p = !current_function_calls_alloca;
- char *sp_str = reg_names[STACK_POINTER_REGNUM];
- char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+ const char *sp_str = reg_names[STACK_POINTER_REGNUM];
+ const char *fp_str = reg_names[FRAME_POINTER_REGNUM];
/* ??? There are lots of optimizations that can be done here.
EG: Use fp to restore regs if it's closer.
/* Emit the return instruction. */
{
- static int regs[4] = {
+ static const int regs[4] = {
0, RETURN_ADDR_REGNUM, ILINK1_REGNUM, ILINK2_REGNUM
};
fprintf (file, "\tj.d %s\n", reg_names[regs[fn_type]]);
int
shift_operator (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
/* ??? We use the loop register here. We don't use it elsewhere (yet) and
using it here will give us a chance to play with it. */
-char *
+const char *
output_shift (operands)
rtx *operands;
{
- static int loopend_lab;
rtx shift = operands[3];
enum machine_mode mode = GET_MODE (shift);
enum rtx_code code = GET_CODE (shift);
- char *shift_one;
+ const char *shift_one;
if (mode != SImode)
abort ();
/* The ARC doesn't have a rol insn. Use something else. */
output_asm_insn ("asl.f 0,%0\n\tadc %0,0,0", operands);
break;
+ default:
+ break;
}
}
/* Must loop. */
if (optimize)
{
if (flag_pic)
- sprintf ("lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start",
+ sprintf (buf, "lr %%4,[status]\n\tadd %%4,%%4,6\t%s single insn loop start",
ASM_COMMENT_START);
else
sprintf (buf, "mov %%4,%%%%st(1f)\t%s (single insn loop start) >> 2",
void
arc_initialize_trampoline (tramp, fnaddr, cxt)
- rtx tramp, fnaddr, cxt;
+ rtx tramp ATTRIBUTE_UNUSED, fnaddr ATTRIBUTE_UNUSED, cxt ATTRIBUTE_UNUSED;
{
}
\f
arc_condition_codes[arc_ccfsm_current_cc]);
}
else
- /* This insn is executed for either path, so don't
- conditionalize it at all. */
- ; /* nothing to do */
+ {
+ /* This insn is executed for either path, so don't
+ conditionalize it at all. */
+ ; /* nothing to do */
+ }
}
else
{
fputc (']', file);
}
else
- output_operand_lossage ("invalid operand to %R code");
+ output_operand_lossage ("invalid operand to %%R code");
return;
case 'S' :
if ((GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_FLAG (x))
split_double (x, &first, &second);
fprintf (file, "0x%08lx",
- code == 'L' ? INTVAL (first) : INTVAL (second));
+ (long)(code == 'L' ? INTVAL (first) : INTVAL (second)));
}
else
- output_operand_lossage ("invalid operand to %H/%L code");
+ output_operand_lossage ("invalid operand to %%H/%%L code");
return;
case 'A' :
{
fputs (".a", file);
}
else
- output_operand_lossage ("invalid operand to %U code");
+ output_operand_lossage ("invalid operand to %%U code");
return;
case 'V' :
/* Output cache bypass indicator for a load/store insn. Volatile memory
fputs (".di", file);
}
else
- output_operand_lossage ("invalid operand to %V code");
+ output_operand_lossage ("invalid operand to %%V code");
return;
case 0 :
/* Do nothing special. */
void
arc_final_prescan_insn (insn, opvec, noperands)
rtx insn;
- rtx *opvec;
- int noperands;
+ rtx *opvec ATTRIBUTE_UNUSED;
+ int noperands ATTRIBUTE_UNUSED;
{
/* BODY will hold the body of INSN. */
register rtx body = PATTERN (insn);
an if/then/else), and things need to be reversed. */
int reverse = 0;
- /* If we start with a return insn, we only succeed if we find another one. */
+ /* If we start with a return insn, we only succeed if we find another one. */
int seeking_return = 0;
/* START_INSN will hold the insn from where we start looking. This is the
/* Succeed if the following insn is the target label.
Otherwise fail.
If return insns are used then the last insn in a function
- will be a barrier. */
+ will be a barrier. */
next_must_be_target_label_p = TRUE;
break;
/* If this is an unconditional branch to the same label, succeed.
If it is to another label, do nothing. If it is conditional,
fail. */
- /* ??? Probably, the test for the SET and the PC are unnecessary. */
+ /* ??? Probably, the test for the SET and the PC are unnecessary. */
if (GET_CODE (scanbody) == SET
&& GET_CODE (SET_DEST (scanbody)) == PC)
if (!this_insn)
{
/* Oh dear! we ran off the end, give up. */
- insn_extract (insn);
+ extract_insn_cached (insn);
arc_ccfsm_state = 0;
arc_ccfsm_target_insn = NULL;
return;
arc_ccfsm_current_cc = ARC_INVERSE_CONDITION_CODE (arc_ccfsm_current_cc);
}
- /* Restore recog_operand. Getting the attributes of other insns can
+ /* Restore recog_data. Getting the attributes of other insns can
destroy this array, but final.c assumes that it remains intact
- across this call; since the insn has been recognized already we
- call insn_extract direct. */
- insn_extract (insn);
+ across this call. */
+ extract_insn_cached (insn);
}
}
void
arc_ccfsm_at_label (prefix, num)
- char *prefix;
+ const char *prefix;
int num;
{
if (arc_ccfsm_state == 3 && arc_ccfsm_target_label == num
}
\f
void
-arc_va_start (stdarg_p, valist, nextarg)
- int stdarg_p;
+arc_va_start (valist, nextarg)
tree valist;
rtx nextarg;
{
&& (current_function_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
return addr_rtx;
}
+
+/* On the ARC, function addresses are not the same as normal addresses.
+ Branch to absolute address insns take an address that is right-shifted
+ by 2. We encode the fact that we have a function here, and then emit a
+ special assembler op when outputting the address. */
+
+static void
+arc_encode_section_info (decl, first)
+ tree decl;
+ int first ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+}