/* Definitions for GCC. Part of the machine description for CRIS.
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Axis Communications. Written by Hans-Peter Nilsson.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "output.h"
#include "target.h"
#include "target-def.h"
+#include "ggc.h"
+#include "optabs.h"
/* Usable when we have an amount to add or subtract, and want the
optimal size of the insn. */
abort (); \
} while (0)
+#define LOSE_AND_RETURN(msgid, x) \
+ do \
+ { \
+ cris_operand_lossage (msgid, x); \
+ return; \
+ } while (0)
+
/* Per-function machine data. */
-struct machine_function
+struct machine_function GTY(())
{
int needs_return_address_on_stack;
};
-/* Fix for reg_overlap_mentioned_p. */
-static int cris_reg_overlap_mentioned_p PARAMS ((rtx, rtx));
-
/* This little fix suppresses the 'u' or 's' when '%e' in assembly
pattern. */
static char cris_output_insn_is_bound = 0;
just the "sym:GOTOFF" part. */
static int cris_pic_sympart_only = 0;
-static void
-cris_print_base PARAMS ((rtx, FILE *));
+/* In code for output macros, this is how we know whether e.g. constant
+ goes in code or in a static initializer. */
+static int in_code = 0;
-static void
-cris_print_index PARAMS ((rtx, FILE *));
+/* Fix for reg_overlap_mentioned_p. */
+static int cris_reg_overlap_mentioned_p (rtx, rtx);
-static void
-cris_init_machine_status PARAMS ((struct function *));
+static void cris_print_base (rtx, FILE *);
-static int
-cris_initial_frame_pointer_offset PARAMS ((void));
+static void cris_print_index (rtx, FILE *);
-static int
-saved_regs_mentioned PARAMS ((rtx));
+static void cris_output_addr_const (FILE *, rtx);
+
+static struct machine_function * cris_init_machine_status (void);
+
+static rtx cris_struct_value_rtx (tree, int);
+
+static void cris_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+ tree type, int *, int);
+
+static int cris_initial_frame_pointer_offset (void);
+
+static int saved_regs_mentioned (rtx);
-static void cris_target_asm_function_prologue
- PARAMS ((FILE *, HOST_WIDE_INT));
-static void cris_target_asm_function_epilogue
- PARAMS ((FILE *, HOST_WIDE_INT));
+static void cris_target_asm_function_prologue (FILE *, HOST_WIDE_INT);
+
+static void cris_target_asm_function_epilogue (FILE *, HOST_WIDE_INT);
+
+static void cris_operand_lossage (const char *, rtx);
+
+static void cris_asm_output_mi_thunk
+ (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
+
+static void cris_file_start (void);
+static void cris_init_libfuncs (void);
+
+static bool cris_rtx_costs (rtx, int, int, int *);
+static int cris_address_cost (rtx);
+static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
+static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
/* The function cris_target_asm_function_epilogue puts the last insn to
- output here. Used in delay_slots_for_epilogue and function_epilogue. */
+ output here. It always fits; there won't be a symbol operand. Used in
+ delay_slots_for_epilogue and function_epilogue. */
static char save_last[80];
/* This is the argument from the "-max-stack-stackframe=" option. */
/* This is the parsed result of the "-march=" option, if given. */
int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.dword\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* We need to define these, since the 2byte, 4byte, 8byte op:s are only
+ available in ELF. These "normal" pseudos do not have any alignment
+ constraints or side-effects. */
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
+
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
+
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
+
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE cris_target_asm_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE cris_target_asm_function_epilogue
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK cris_asm_output_mi_thunk
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START cris_file_start
+
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS cris_init_libfuncs
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS cris_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST cris_address_cost
+
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS cris_setup_incoming_varargs
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE cris_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES cris_arg_partial_bytes
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Predicate functions. */
c) a [r] or [r+] in SImode, or sign-extend from HI or QI. */
int
-cris_bdap_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_bdap_operand (rtx op, enum machine_mode mode)
{
register enum rtx_code code = GET_CODE (op);
d) a [r] or [r+] in SImode, or sign-extend from HI or QI. */
int
-cris_bdap_biap_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_bdap_biap_operand (rtx op, enum machine_mode mode)
{
register enum rtx_code code = GET_CODE (op);
rtx reg;
AND or UMIN. */
int
-cris_orthogonal_operator (x, mode)
- rtx x;
- enum machine_mode mode;
+cris_orthogonal_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
UMIN. */
int
-cris_commutative_orth_op (x, mode)
- rtx x;
- enum machine_mode mode;
+cris_commutative_orth_op (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
|| code == IOR || code == AND || code == UMIN));
}
-/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN. */
+/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.
+ By the name, you might think we should include MULT. We don't because
+ it doesn't accept the same addressing modes as the others (ony
+ registers) and there's also the problem of handling TARGET_MUL_BUG. */
int
-cris_operand_extend_operator (x, mode)
- rtx x;
- enum machine_mode mode;
+cris_operand_extend_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
&& (code == PLUS || code == MINUS || code == UMIN));
}
+/* Check if MODE is same as mode for X, and X is PLUS or MINUS. */
+
+int
+cris_additive_operand_extend_operator (rtx x, enum machine_mode mode)
+{
+ enum rtx_code code = GET_CODE (x);
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (x);
+
+ return (GET_MODE (x) == mode
+ && (code == PLUS || code == MINUS));
+}
+
/* Check to see if MODE is same as mode for X, and X is SIGN_EXTEND or
ZERO_EXTEND. */
int
-cris_extend_operator (x, mode)
- rtx x;
- enum machine_mode mode;
+cris_extend_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
/* Check to see if MODE is same as mode for X, and X is PLUS or BOUND. */
int
-cris_plus_or_bound_operator (x, mode)
- rtx x;
- enum machine_mode mode;
+cris_plus_or_bound_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
(GET_MODE (x) == mode && (code == UMIN || code == PLUS));
}
+/* Used as an operator to get a handle on a already-known-valid MEM rtx:es
+ (no need to validate the address), where some address expression parts
+ have their own match_operand. */
+
+int
+cris_mem_op (rtx x, enum machine_mode mode)
+{
+ if (mode == VOIDmode)
+ mode = GET_MODE (x);
+
+ return GET_MODE (x) == mode && GET_CODE (x) == MEM;
+}
+
/* Since with -fPIC, not all symbols are valid PIC symbols or indeed
general_operands, we have to have a predicate that matches it for the
"movsi" expander. */
int
-cris_general_operand_or_symbol (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_general_operand_or_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (CONSTANT_P (op) && cris_symbol (op));
"movsi" anonymous pattern for PIC symbols. */
int
-cris_general_operand_or_gotless_symbol (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_general_operand_or_gotless_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (CONSTANT_P (op) && cris_gotless_symbol (op));
"call" and "call_value" anonymous patterns. */
int
-cris_general_operand_or_plt_symbol (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_general_operand_or_plt_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (GET_CODE (op) == CONST
UNSPEC 0). */
int
-cris_mem_call_operand (op, mode)
- rtx op;
- enum machine_mode mode;
+cris_mem_call_operand (rtx op, enum machine_mode mode)
{
rtx xmem;
return cris_general_operand_or_symbol (xmem, GET_MODE (op));
}
-/* The CONDITIONAL_REGISTER_USAGE worker. */
+/* The CONDITIONAL_REGISTER_USAGE worker. */
void
-cris_conditional_register_usage ()
+cris_conditional_register_usage (void)
{
/* FIXME: This isn't nice. We should be able to use that register for
something else if the PIC table isn't needed. */
since some generated files do not include function.h. */
int
-cris_cfun_uses_pic_table ()
+cris_cfun_uses_pic_table (void)
{
return current_function_uses_pic_offset_table;
}
define_insn. */
const char *
-cris_op_str (x)
- rtx x;
+cris_op_str (rtx x)
{
cris_output_insn_is_bound = 0;
switch (GET_CODE (x))
break;
case MULT:
- return "mul";
+ /* This function is for retrieving a part of an instruction name for
+ an operator, for immediate output. If that ever happens for
+ MULT, we need to apply TARGET_MUL_BUG in the caller. Make sure
+ we notice. */
+ abort ();
break;
case DIV:
}
}
+/* Emit an error message when we're in an asm, and a fatal error for
+ "normal" insns. Formatted output isn't easily implemented, since we
+ use output_operand_lossage to output the actual message and handle the
+ categorization of the error. */
+
+static void
+cris_operand_lossage (const char *msgid, rtx op)
+{
+ debug_rtx (op);
+ output_operand_lossage ("%s", msgid);
+}
+
/* Print an index part of an address to file. */
static void
-cris_print_index (index, file)
- rtx index;
- FILE * file;
+cris_print_index (rtx index, FILE *file)
{
rtx inner = XEXP (index, 0);
fprintf (file, "[$%s].d", reg_names[REGNO (inner)]);
}
else
- fatal_insn ("Unexpected index-type in cris_print_index", index);
+ cris_operand_lossage ("unexpected index-type in cris_print_index",
+ index);
}
/* Print a base rtx of an address to file. */
static void
-cris_print_base (base, file)
- rtx base;
- FILE *file;
+cris_print_base (rtx base, FILE *file)
{
if (REG_P (base))
fprintf (file, "$%s", reg_names[REGNO (base)]);
else if (GET_CODE (base) == POST_INC)
fprintf (file, "$%s+", reg_names[REGNO (XEXP (base, 0))]);
else
- fatal_insn ("Unexpected base-type in cris_print_base", base);
+ cris_operand_lossage ("unexpected base-type in cris_print_base",
+ base);
}
/* Usable as a guard in expressions. */
int
-cris_fatal (arg)
- char *arg;
+cris_fatal (char *arg)
{
internal_error (arg);
return 0;
}
+/* This variable belongs to cris_target_asm_function_prologue but must
+ be located outside it for GTY reasons. */
+static GTY(()) unsigned long cfa_label_num = 0;
+
/* Textual function prologue. */
static void
-cris_target_asm_function_prologue (file, size)
- FILE *file;
- HOST_WIDE_INT size;
+cris_target_asm_function_prologue (FILE *file, HOST_WIDE_INT size)
{
int regno;
int framesize;
int faked_args_size = 0;
int cfa_write_offset = 0;
- char *cfa_label = NULL;
+ static char cfa_label[30];
int return_address_on_stack
= regs_ever_live[CRIS_SRP_REGNUM]
|| cfun->machine->needs_return_address_on_stack != 0;
cfa_offset += cris_initial_frame_pointer_offset ();
}
- cfa_label = dwarf2out_cfi_label ();
+ ASM_GENERATE_INTERNAL_LABEL (cfa_label, "LCFIT",
+ cfa_label_num++);
dwarf2out_def_cfa (cfa_label, cfa_reg, cfa_offset);
cfa_write_offset = - faked_args_size - 4;
{
if ((((regs_ever_live[regno]
&& !call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM
+ || (regno == (int) PIC_OFFSET_TABLE_REGNUM
&& (current_function_uses_pic_offset_table
/* It is saved anyway, if there would be a gap. */
|| (flag_pic
&& (last_movem_reg + 1) * 4 + size <= 128
&& cris_cpu_version >= CRIS_CPU_SVINTO
&& TARGET_SIDE_EFFECT_PREFIXES)
- fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+ fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
reg_names[last_movem_reg],
(last_movem_reg + 1) * 4 + size);
else
{
/* Avoid printing multiple subsequent sub:s for sp. */
- fprintf (file, "\tsub%s %d,$sp\n",
+ fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1)
* 4 + size),
(last_movem_reg + 1) * 4 + size);
framesize += (last_movem_reg + 1) * 4 + size;
if (TARGET_PDEBUG)
- fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+ fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
+ ", #regs %d, bytes %d args %d\n",
size,
last_movem_reg + 1,
(last_movem_reg + 1) * 4,
{
/* Local vars on stack, but there are no movem:s.
Just allocate space. */
- fprintf (file, "\tSub%s %d,$sp\n",
+ fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
ADDITIVE_SIZE_MODIFIER (size),
size);
framesize += size;
&& (last_movem_reg + 1) * 4 + size <= 128
&& cris_cpu_version >= CRIS_CPU_SVINTO
&& TARGET_SIDE_EFFECT_PREFIXES)
- fprintf (file, "\tmovem $%s,[$sp=$sp-%d]\n",
+ fprintf (file, "\tmovem $%s,[$sp=$sp-"HOST_WIDE_INT_PRINT_DEC"]\n",
reg_names[last_movem_reg],
(last_movem_reg+1) * 4 + size);
else
{
/* Avoid printing multiple subsequent sub:s for sp. FIXME:
Clean up the conditional expression. */
- fprintf (file, "\tsub%s %d,$sp\n",
+ fprintf (file, "\tsub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
ADDITIVE_SIZE_MODIFIER ((last_movem_reg + 1) * 4 + size),
(last_movem_reg + 1) * 4 + size);
/* To be compatible with v0..v3 means we do not use an assignment
framesize += (last_movem_reg + 1) * 4 + size;
if (TARGET_PDEBUG)
- fprintf (file, "; frame %d, #regs %d, bytes %d args %d\n",
+ fprintf (file, "; frame "HOST_WIDE_INT_PRINT_DEC
+ ", #regs %d, bytes %d args %d\n",
size,
last_movem_reg + 1,
(last_movem_reg + 1) * 4,
/* This does not need to be accounted for, for unwind. */
/* Local vars on stack, and we could not use movem. Add a sub here. */
- fprintf (file, "\tSub%s %d,$sp\n",
+ fprintf (file, "\tSub%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
ADDITIVE_SIZE_MODIFIER (size + cfoa_size),
cfoa_size + size);
framesize += size + cfoa_size;
/* Set up the PIC register. */
if (current_function_uses_pic_offset_table)
- asm_fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
- reg_names[PIC_OFFSET_TABLE_REGNUM],
- reg_names[PIC_OFFSET_TABLE_REGNUM]);
+ fprintf (file, "\tmove.d $pc,$%s\n\tsub.d .:GOTOFF,$%s\n",
+ reg_names[PIC_OFFSET_TABLE_REGNUM],
+ reg_names[PIC_OFFSET_TABLE_REGNUM]);
+
+ if (doing_dwarf)
+ ASM_OUTPUT_LABEL (file, cfa_label);
if (TARGET_PDEBUG)
fprintf (file,
- "; parm #%d @ %d; frame %d, FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
+ "; parm #%d @ %d; frame " HOST_WIDE_INT_PRINT_DEC
+ ", FP-SP is %d; leaf: %s%s; fp %s, outg: %d arg %d\n",
CRIS_MAX_ARGS_IN_REGS + 1, FIRST_PARM_OFFSET (0),
get_frame_size (),
cris_initial_frame_pointer_offset (),
cfoa_size, current_function_args_size);
if (cris_max_stackframe && framesize > cris_max_stackframe)
- warning ("Stackframe too big: %d bytes", framesize);
+ warning ("stackframe too big: %d bytes", framesize);
}
/* Return nonzero if there are regs mentioned in the insn that are not all
can be put in the epilogue. */
static int
-saved_regs_mentioned (x)
- rtx x;
+saved_regs_mentioned (rtx x)
{
int i;
const char *fmt;
/* Figure out if the insn may be put in the epilogue. */
int
-cris_eligible_for_epilogue_delay (insn)
- rtx insn;
+cris_eligible_for_epilogue_delay (rtx insn)
{
/* First of all, it must be as slottable as for a delayed branch insn. */
if (get_attr_slottable (insn) != SLOTTABLE_YES)
contains "ret", else 0. */
int
-cris_delay_slots_for_epilogue ()
+cris_delay_slots_for_epilogue (void)
{
/* Check if we use a return insn, which we only do for leaf functions.
Else there is no slot to fill. */
itself by storing the delay insn in save_last. */
static void
-cris_target_asm_function_epilogue (file, size)
- FILE *file;
- HOST_WIDE_INT size;
+cris_target_asm_function_epilogue (FILE *file, HOST_WIDE_INT size)
{
int regno;
int last_movem_reg = -1;
regno++)
if ((((regs_ever_live[regno]
&& !call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM
+ || (regno == (int) PIC_OFFSET_TABLE_REGNUM
&& (current_function_uses_pic_offset_table
/* It is saved anyway, if there would be a gap. */
|| (flag_pic
regno--)
if ((((regs_ever_live[regno]
&& !call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM
+ || (regno == (int) PIC_OFFSET_TABLE_REGNUM
&& (current_function_uses_pic_offset_table
/* It is saved anyway, if there would be a gap. */
|| (flag_pic
fprintf (file, save_last);
*save_last = 0;
}
-
+
if (file)
fprintf (file, "\tAdd%s %d,$sp\n",
ADDITIVE_SIZE_MODIFIER (argspace_offset),
if (*save_last && file)
fprintf (file, save_last);
- sprintf (save_last, "\tadd%s %d,$sp\n",
+ sprintf (save_last, "\tadd%s "HOST_WIDE_INT_PRINT_DEC",$sp\n",
ADDITIVE_SIZE_MODIFIER (size), size);
}
/* Do a sanity check to avoid generating invalid code. */
if (current_function_epilogue_delay_list)
- internal_error ("Allocated but unused delay list in epilogue");
+ internal_error ("allocated but unused delay list in epilogue");
}
return;
}
thoroughly), assert the assumption that all usage of
__builtin_eh_return are handled above. */
if (current_function_calls_eh_return)
- internal_error ("Unexpected function type needing stack adjustment for\
+ internal_error ("unexpected function type needing stack adjustment for\
__builtin_eh_return");
/* If we pushed some register parameters, then adjust the stack for
/* Output the delay-slot-insn the mandated way. */
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
- file, 1, -2, 1);
+ file, 1, -2, 1, NULL);
}
else if (file)
{
/* The PRINT_OPERAND worker. */
void
-cris_print_operand (file, x, code)
- FILE *file;
- rtx x;
- int code;
+cris_print_operand (FILE *file, rtx x, int code)
{
rtx operand = x;
/* Size-strings corresponding to MULT expressions. */
- static const char *mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
+ static const char *const mults[] = { "BAD:0", ".b", ".w", "BAD:3", ".d" };
/* New code entries should just be added to the switch below. If
handling is finished, just return. If handling was just a
switch (code)
{
case 'b':
- /* Print the unsigned supplied integer as if it was signed
+ /* Print the unsigned supplied integer as if it were signed
and < 0, i.e print 255 or 65535 as -1, 254, 65534 as -2, etc. */
if (GET_CODE (x) != CONST_INT
|| ! CONST_OK_FOR_LETTER_P (INTVAL (x), 'O'))
- fatal_insn ("Internal: Invalid operand with 'b'", x);
- fprintf (file, "%d", INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
+ LOSE_AND_RETURN ("invalid operand for 'b' modifier", x);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ INTVAL (x)| (INTVAL (x) <= 255 ? ~255 : ~65535));
return;
case 'x':
case 'v':
/* Print the operand without the PIC register. */
- if (! flag_pic || ! cris_gotless_symbol (x))
- fatal_insn ("Internal: Invalid operand with 'v'", x);
+ if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
+ LOSE_AND_RETURN ("invalid operand for 'v' modifier", x);
cris_pic_sympart_only++;
cris_output_addr_const (file, x);
cris_pic_sympart_only--;
case 'P':
/* Print the PIC register. Applied to a GOT-less PIC symbol for
sanity. */
- if (! flag_pic || ! cris_gotless_symbol (x))
- fatal_insn ("Internal: Invalid operand with 'P'", x);
+ if (! flag_pic || ! CONSTANT_P (x) || ! cris_gotless_symbol (x))
+ LOSE_AND_RETURN ("invalid operand for 'P' modifier", x);
fprintf (file, "$%s", reg_names [PIC_OFFSET_TABLE_REGNUM]);
return;
case 'p':
/* Adjust a power of two to its log2. */
if (GET_CODE (x) != CONST_INT || exact_log2 (INTVAL (x)) < 0 )
- fatal_insn ("Internal: Invalid operand with 'p'", x);
+ LOSE_AND_RETURN ("invalid operand for 'p' modifier", x);
fprintf (file, "%d", exact_log2 (INTVAL (x)));
return;
w for -32768 <= x <= 65535, else abort. */
if (GET_CODE (x) != CONST_INT
|| INTVAL (x) < -32768 || INTVAL (x) > 65535)
- fatal_insn ("Internal: Invalid operand with 'z'", x);
+ LOSE_AND_RETURN ("invalid operand for 'z' modifier", x);
putc (INTVAL (x) >= -128 && INTVAL (x) <= 255 ? 'b' : 'w', file);
return;
fputs ("\n\tnop", file);
return;
+ case '!':
+ /* Output directive for alignment padded with "nop" insns.
+ Optimizing for size, it's plain 4-byte alignment, otherwise we
+ align the section to a cache-line (32 bytes) and skip at max 2
+ bytes, i.e. we skip if it's the last insn on a cache-line. The
+ latter is faster by a small amount (for two test-programs 99.6%
+ and 99.9%) and larger by a small amount (ditto 100.1% and
+ 100.2%). This is supposed to be the simplest yet performance-
+ wise least intrusive way to make sure the immediately following
+ (supposed) muls/mulu insn isn't located at the end of a
+ cache-line. */
+ if (TARGET_MUL_BUG)
+ fputs (optimize_size
+ ? ".p2alignw 2,0x050f\n\t"
+ : ".p2alignw 5,0x050f,2\n\t", file);
+ return;
+
case 'H':
/* Print high (most significant) part of something. */
switch (GET_CODE (operand))
{
case CONST_INT:
- /* Sign-extension from a normal int to a long long. */
- fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+ if (HOST_BITS_PER_WIDE_INT == 32)
+ /* Sign-extension from a normal int to a long long. */
+ fprintf (file, INTVAL (operand) < 0 ? "-1" : "0");
+ else
+ fprintf (file, "0x%x", (unsigned int)(INTVAL (x) >> 31 >> 1));
return;
case CONST_DOUBLE:
/* High part of a long long constant. */
if (GET_MODE (operand) == VOIDmode)
{
- fprintf (file, "0x%x", CONST_DOUBLE_HIGH (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_HIGH (x));
return;
}
else
- fatal_insn ("Internal: Invalid operand with 'H'", x);
+ LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);
case REG:
/* Print reg + 1. Check that there's not an attempt to print
high-parts of registers like stack-pointer or higher. */
if (REGNO (operand) > STACK_POINTER_REGNUM - 2)
- internal_error ("Internal: Bad register: %d", REGNO (operand));
+ LOSE_AND_RETURN ("bad register", operand);
fprintf (file, "$%s", reg_names[REGNO (operand) + 1]);
return;
}
default:
- fatal_insn ("Internal: Invalid operand for 'H'", x);
+ LOSE_AND_RETURN ("invalid operand for 'H' modifier", x);
}
case 'L':
if (GET_CODE (operand) != SIGN_EXTEND
&& GET_CODE (operand) != ZERO_EXTEND
&& GET_CODE (operand) != CONST_INT)
- fatal_insn ("Internal: Invalid operand with 'e'", x);
+ LOSE_AND_RETURN ("invalid operand for 'e' modifier", x);
if (cris_output_insn_is_bound)
{
/* Print the size letter of the inner element. We can do it by
calling ourselves with the 's' modifier. */
if (GET_CODE (operand) != SIGN_EXTEND && GET_CODE (operand) != ZERO_EXTEND)
- fatal_insn ("Internal: Invalid operand with 'm'", x);
+ LOSE_AND_RETURN ("invalid operand for 'm' modifier", x);
cris_print_operand (file, XEXP (operand, 0), 's');
return;
/* Print the least significant part of operand. */
if (GET_CODE (operand) == CONST_DOUBLE)
{
- fprintf (file, "0x%x", CONST_DOUBLE_LOW (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+ return;
+ }
+ else if (HOST_BITS_PER_WIDE_INT > 32 && GET_CODE (operand) == CONST_INT)
+ {
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX,
+ INTVAL (x) & ((unsigned int) 0x7fffffff * 2 + 1));
return;
}
- /* If not a CONST_DOUBLE, the least significant part equals the
- normal part, so handle it normally. */
+ /* Otherwise the least significant part equals the normal part,
+ so handle it normally. */
break;
case 'A':
/* When emitting an add for the high part of a DImode constant, we
want to use addq for 0 and adds.w for -1. */
if (GET_CODE (operand) != CONST_INT)
- fatal_insn ("Internal: Invalid operand with 'A' output modifier", x);
+ LOSE_AND_RETURN ("invalid operand for 'A' modifier", x);
fprintf (file, INTVAL (operand) < 0 ? "adds.w" : "addq");
return;
/* When emitting an sub for the high part of a DImode constant, we
want to use subq for 0 and subs.w for -1. */
if (GET_CODE (operand) != CONST_INT)
- fatal_insn ("Internal: Invalid operand with 'D' output modifier", x);
+ LOSE_AND_RETURN ("invalid operand for 'D' modifier", x);
fprintf (file, INTVAL (operand) < 0 ? "subs.w" : "subq");
return;
/* Print the size letter for an operand to a MULT, which must be a
const_int with a suitable value. */
if (GET_CODE (operand) != CONST_INT || INTVAL (operand) > 4)
- fatal_insn ("Internal: Invalid operand with 'T'", x);
-
+ LOSE_AND_RETURN ("invalid operand for 'T' modifier", x);
fprintf (file, "%s", mults[INTVAL (operand)]);
return;
break;
default:
- {
-#define BADFORMAT "Internal: Invalid operand for '%c'"
- char s[sizeof BADFORMAT];
- sprintf (s, BADFORMAT, code);
- fatal_insn (s, x);
- }
+ LOSE_AND_RETURN ("invalid operand modifier letter", x);
}
/* Print an operand as without a modifier letter. */
{
case REG:
if (REGNO (operand) > 15)
- internal_error ("Internal: Bad register: %d", REGNO (operand));
+ internal_error ("internal error: bad register: %d", REGNO (operand));
fprintf (file, "$%s", reg_names[REGNO (operand)]);
return;
if (GET_CODE (reg) != REG
|| (GET_CODE (XEXP (operand, 0)) != CONST_INT
&& GET_CODE (XEXP (operand, 1)) != CONST_INT))
- fatal_insn ("Can't print operand", x);
+ LOSE_AND_RETURN ("unexpected multiplicative operand", x);
cris_print_base (reg, file);
fprintf (file, ".%c",
return;
}
- fatal_insn ("Internal: Cannot decode operand", x);
+ LOSE_AND_RETURN ("unexpected operand", x);
}
}
/* The PRINT_OPERAND_ADDRESS worker. */
void
-cris_print_operand_address (file, x)
- FILE *file;
- rtx x;
+cris_print_operand_address (FILE *file, rtx x)
{
/* All these were inside MEM:s so output indirection characters. */
putc ('[', file);
cris_print_index (x1, file);
}
else
- fatal_insn ("Internal: This is not a recognized address", x);
+ LOSE_AND_RETURN ("unrecognized address", x);
}
else if (GET_CODE (x) == MEM)
{
putc (']', file);
}
else
- fatal_insn ("Internal: This is not a recognized address", x);
+ LOSE_AND_RETURN ("unrecognized address", x);
putc (']', file);
}
initial-value machinery. */
rtx
-cris_return_addr_rtx (count, frameaddr)
- int count;
- rtx frameaddr ATTRIBUTE_UNUSED;
+cris_return_addr_rtx (int count, rtx frameaddr ATTRIBUTE_UNUSED)
{
cfun->machine->needs_return_address_on_stack = 1;
: NULL_RTX;
}
+/* Accessor used in cris.md:return because cfun->machine isn't available
+ there. */
+
+int
+cris_return_address_on_stack ()
+{
+ return cfun->machine->needs_return_address_on_stack;
+}
+
/* This used to be the INITIAL_FRAME_POINTER_OFFSET worker; now only
handles FP -> SP elimination offset. */
static int
-cris_initial_frame_pointer_offset ()
+cris_initial_frame_pointer_offset (void)
{
int regno;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((((regs_ever_live[regno]
&& !call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM
+ || (regno == (int) PIC_OFFSET_TABLE_REGNUM
&& (current_function_uses_pic_offset_table
/* It is saved anyway, if there would be a gap. */
|| (flag_pic
and imaginary arg pointer. */
int
-cris_initial_elimination_offset (fromreg, toreg)
- int fromreg;
- int toreg;
+cris_initial_elimination_offset (int fromreg, int toreg)
{
int fp_sp_offset
= cris_initial_frame_pointer_offset ();
= regs_ever_live[CRIS_SRP_REGNUM]
|| cfun->machine->needs_return_address_on_stack != 0;
- /* Here we act as if the frame-pointer is needed. */
+ /* Here we act as if the frame-pointer were needed. */
int ap_fp_offset = 4 + (return_address_on_stack ? 4 : 0);
if (fromreg == ARG_POINTER_REGNUM
check-cc-attribute methods. */
void
-cris_notice_update_cc (exp, insn)
- rtx exp;
- rtx insn;
+cris_notice_update_cc (rtx exp, rtx insn)
{
/* Check if user specified "-mcc-init" as a bug-workaround. FIXME:
TARGET_CCINIT does not work; we must set CC_REVERSED as below.
- Several test-cases will otherwise fail, for example
+ Several testcases will otherwise fail, for example
gcc.c-torture/execute/20000217-1.c -O0 and -O1. */
if (TARGET_CCINIT)
{
if (GET_CODE (exp) == SET)
{
if (cc_status.value1
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value1))
+ && modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
if (cc_status.value2
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value2))
+ && modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
}
return;
{
/* There's no CC0 change when clearing a register or
memory. Just check for overlap. */
- if ((cc_status.value1
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value1)))
+ if (cc_status.value1
+ && modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
- if ((cc_status.value2
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value2)))
+ if (cc_status.value2
+ && modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
return;
{
/* When SET to MEM, then CC is not changed (except for
overlap). */
- if ((cc_status.value1
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value1)))
+ if (cc_status.value1
+ && modified_in_p (cc_status.value1, insn))
cc_status.value1 = 0;
- if ((cc_status.value2
- && cris_reg_overlap_mentioned_p (SET_DEST (exp),
- cc_status.value2)))
+ if (cc_status.value2
+ && modified_in_p (cc_status.value2, insn))
cc_status.value2 = 0;
return;
value1=rz and value2=[rx] */
cc_status.value1 = XEXP (XVECEXP (exp, 0, 0), 0);
cc_status.value2
- = gen_rtx_MEM (GET_MODE (XEXP (XVECEXP (exp, 0, 0), 0)),
- XEXP (XVECEXP (exp, 0, 1), 0));
+ = replace_equiv_address (XEXP (XVECEXP (exp, 0, 0), 1),
+ XEXP (XVECEXP (exp, 0, 1), 0));
cc_status.flags = 0;
/* Huh? A side-effect cannot change the destination
register. */
if (cris_reg_overlap_mentioned_p (cc_status.value1,
cc_status.value2))
- internal_error ("Internal: sideeffect-insn affecting main effect");
+ internal_error ("internal error: sideeffect-insn affecting main effect");
return;
}
else if ((REG_P (XEXP (XVECEXP (exp, 0, 0), 1))
{
/* For "move.S rz,[rx=ry+o]" and "clear.S [rx=ry+o]",
say flags are not changed, except for overlap. */
- if ((cc_status.value1
- && cris_reg_overlap_mentioned_p (XEXP
- (XVECEXP
- (exp, 0, 0), 0),
- cc_status.value1))
- || (cc_status.value2
- && cris_reg_overlap_mentioned_p (XEXP
- (XVECEXP
- (exp, 0, 1), 0),
- cc_status.value2)))
- CC_STATUS_INIT;
+ if (cc_status.value1
+ && modified_in_p (cc_status.value1, insn))
+ cc_status.value1 = 0;
+
+ if (cc_status.value2
+ && modified_in_p (cc_status.value2, insn))
+ cc_status.value2 = 0;
+
return;
}
}
many registers must be saved, so return 0 then. */
int
-cris_simple_epilogue ()
+cris_simple_epilogue (void)
{
int regno;
int reglimit = STACK_POINTER_REGNUM;
in the delay-slot of the "ret". */
for (regno = 0; regno < reglimit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
- || (regno == PIC_OFFSET_TABLE_REGNUM
+ || (regno == (int) PIC_OFFSET_TABLE_REGNUM
&& (current_function_uses_pic_offset_table
/* It is saved anyway, if there would be a gap. */
|| (flag_pic
return 1;
}
+/* 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
+cris_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+ switch (code)
+ {
+ case CONST_INT:
+ {
+ HOST_WIDE_INT val = INTVAL (x);
+ if (val == 0)
+ *total = 0;
+ else if (val < 32 && val >= -32)
+ *total = 1;
+ /* Eight or 16 bits are a word and cycle more expensive. */
+ else if (val <= 32767 && val >= -32768)
+ *total = 2;
+ /* A 32 bit constant (or very seldom, unsigned 16 bits) costs
+ another word. FIXME: This isn't linear to 16 bits. */
+ else
+ *total = 4;
+ return true;
+ }
+
+ case LABEL_REF:
+ *total = 6;
+ return true;
+
+ case CONST:
+ case SYMBOL_REF:
+ /* For PIC, we need a prefix (if it isn't already there),
+ and the PIC register. For a global PIC symbol, we also
+ need a read of the GOT. */
+ if (flag_pic)
+ {
+ if (cris_got_symbol (x))
+ *total = 2 + 4 + 6;
+ else
+ *total = 2 + 6;
+ }
+ else
+ *total = 6;
+ return true;
+
+ case CONST_DOUBLE:
+ if (x != CONST0_RTX (GET_MODE (x) == VOIDmode ? DImode : GET_MODE (x)))
+ *total = 12;
+ else
+ /* Make 0.0 cheap, else test-insns will not be used. */
+ *total = 0;
+ return true;
+
+ case MULT:
+ /* Identify values that are no powers of two. Powers of 2 are
+ taken care of already and those values should not be changed. */
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT
+ || exact_log2 (INTVAL (XEXP (x, 1)) < 0))
+ {
+ /* If we have a multiply insn, then the cost is between
+ 1 and 2 "fast" instructions. */
+ if (TARGET_HAS_MUL_INSNS)
+ {
+ *total = COSTS_N_INSNS (1) + COSTS_N_INSNS (1) / 2;
+ return true;
+ }
+
+ /* Estimate as 4 + 4 * #ofbits. */
+ *total = COSTS_N_INSNS (132);
+ return true;
+ }
+ return false;
+
+ case UDIV:
+ case MOD:
+ case UMOD:
+ case DIV:
+ if (GET_CODE (XEXP (x, 1)) != CONST_INT
+ || exact_log2 (INTVAL (XEXP (x, 1)) < 0))
+ {
+ /* Estimate this as 4 + 8 * #of bits. */
+ *total = COSTS_N_INSNS (260);
+ return true;
+ }
+ return false;
+
+ case AND:
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ /* Two constants may actually happen before optimization. */
+ && GET_CODE (XEXP (x, 0)) != CONST_INT
+ && !CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I'))
+ {
+ *total = (rtx_cost (XEXP (x, 0), outer_code) + 2
+ + 2 * GET_MODE_NUNITS (GET_MODE (XEXP (x, 0))));
+ return true;
+ }
+ return false;
+
+ case ZERO_EXTEND: case SIGN_EXTEND:
+ *total = rtx_cost (XEXP (x, 0), outer_code);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/* The ADDRESS_COST worker. */
-int
-cris_address_cost (x)
- rtx x;
+static int
+cris_address_cost (rtx x)
{
/* The metric to use for the cost-macros is unclear.
The metric used here is (the number of cycles needed) / 2,
whose mode we must consider. */
int
-cris_side_effect_mode_ok (code, ops, lreg, rreg, rval, multop, other_op)
- enum rtx_code code;
- rtx *ops;
- int lreg, rreg, rval, multop, other_op;
+cris_side_effect_mode_ok (enum rtx_code code, rtx *ops,
+ int lreg, int rreg, int rval,
+ int multop, int other_op)
{
/* Find what value to multiply with, for rx =ry + rz * n. */
int mult = multop < 0 ? 1 : INTVAL (ops[multop]);
}
/* If we get here, the caller got its initial tests wrong. */
- internal_error ("Internal: cris_side_effect_mode_ok with bad operands");
+ internal_error ("internal error: cris_side_effect_mode_ok with bad operands");
}
/* The function reg_overlap_mentioned_p in CVS (still as of 2001-05-16)
anyway. */
static int
-cris_reg_overlap_mentioned_p (x, in)
- rtx x, in;
+cris_reg_overlap_mentioned_p (rtx x, rtx in)
{
/* The function reg_overlap_mentioned now handles when X is
strict_low_part, but not when IN is a STRICT_LOW_PART. */
We just dispatch to the functions for ELF and a.out. */
void
-cris_target_asm_named_section (name, flags)
- const char *name;
- unsigned int flags;
+cris_target_asm_named_section (const char *name, unsigned int flags,
+ tree decl)
{
if (! TARGET_ELF)
- default_no_named_section (name, flags);
+ default_no_named_section (name, flags, decl);
else
- default_elf_asm_named_section (name, flags);
+ default_elf_asm_named_section (name, flags, decl);
}
/* The LEGITIMATE_PIC_OPERAND_P worker. */
int
-cris_legitimate_pic_operand (x)
- rtx x;
+cris_legitimate_pic_operand (rtx x)
{
/* The PIC representation of a symbol with a GOT entry will be (for
example; relocations differ):
return ! cris_symbol (x) || cris_got_symbol (x);
}
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
CONSTANT_P. */
int
-cris_symbol (x)
- rtx x;
+cris_symbol (rtx x)
{
switch (GET_CODE (x))
{
case CONST_INT:
case CONST_DOUBLE:
- case CONSTANT_P_RTX:
return 0;
default:
- fatal_insn ("Unrecognized supposed constant", x);
+ fatal_insn ("unrecognized supposed constant", x);
}
return 1;
}
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
CONSTANT_P, and the symbol does not need a GOT entry. Also set
current_function_uses_pic_offset_table if we're generating PIC and ever
see something that would need one. */
int
-cris_gotless_symbol (x)
- rtx x;
+cris_gotless_symbol (rtx x)
{
+#ifdef ENABLE_CHECKING
+ if (!flag_pic)
+ abort ();
+#endif
+
switch (GET_CODE (x))
{
case UNSPEC:
return 1;
case SYMBOL_REF:
- if (flag_pic && cfun != NULL)
+ if (cfun != NULL)
current_function_uses_pic_offset_table = 1;
- return SYMBOL_REF_FLAG (x);
+ return SYMBOL_REF_LOCAL_P (x);
case LABEL_REF:
/* We don't set current_function_uses_pic_offset_table for
case CONST_INT:
case CONST_DOUBLE:
- case CONSTANT_P_RTX:
return 0;
default:
- fatal_insn ("Unrecognized supposed constant", x);
+ fatal_insn ("unrecognized supposed constant", x);
}
return 1;
}
-/* Return non-zero if there's a SYMBOL_REF or LABEL_REF hiding inside this
+/* Return nonzero if there's a SYMBOL_REF or LABEL_REF hiding inside this
CONSTANT_P, and the symbol needs a GOT entry. */
int
-cris_got_symbol (x)
- rtx x;
+cris_got_symbol (rtx x)
{
+#ifdef ENABLE_CHECKING
+ if (!flag_pic)
+ abort ();
+#endif
+
switch (GET_CODE (x))
{
case UNSPEC:
return 0;
case SYMBOL_REF:
- if (flag_pic && cfun != NULL)
+ if (cfun != NULL)
current_function_uses_pic_offset_table = 1;
- return ! SYMBOL_REF_FLAG (x);
+ return ! SYMBOL_REF_LOCAL_P (x);
case CONST:
return cris_got_symbol (XEXP (x, 0));
case CONST_INT:
case CONST_DOUBLE:
- case CONSTANT_P_RTX:
return 0;
default:
- fatal_insn ("Unrecognized supposed constant in cris_global_pic_symbol",
+ fatal_insn ("unrecognized supposed constant in cris_global_pic_symbol",
x);
}
As is the norm, this also parses -mfoo=bar type parameters. */
void
-cris_override_options ()
+cris_override_options (void)
{
if (cris_max_stackframe_str)
{
cris_cpu_version = 10;
if (cris_cpu_version < 0 || cris_cpu_version > 10)
- error ("Unknown CRIS version specification in -march= or -mcpu= : %s",
+ error ("unknown CRIS version specification in -march= or -mcpu= : %s",
cris_cpu_str);
/* Set the target flags. */
cris_tune = 10;
if (cris_tune < 0 || cris_tune > 10)
- error ("Unknown CRIS cpu version specification in -mtune= : %s",
+ error ("unknown CRIS cpu version specification in -mtune= : %s",
cris_tune_str);
if (cris_tune >= CRIS_CPU_SVINTO)
further errors. */
if (! TARGET_LINUX)
{
- error ("-fPIC not supported in this configuration");
+ error ("-fPIC and -fpic are not supported in this configuration");
flag_pic = 0;
}
flag_no_function_cse = 1;
}
- if ((write_symbols == DWARF_DEBUG
- || write_symbols == DWARF2_DEBUG) && ! TARGET_ELF)
+ if (write_symbols == DWARF2_DEBUG && ! TARGET_ELF)
{
- warning ("Specified -g option is invalid with -maout and -melinux");
+ warning ("that particular -g option is invalid with -maout and -melinux");
write_symbols = DBX_DEBUG;
}
init_machine_status = cris_init_machine_status;
}
-/* The ASM_OUTPUT_MI_THUNK worker. */
+/* The TARGET_ASM_OUTPUT_MI_THUNK worker. */
-void
-cris_asm_output_mi_thunk (stream, thunkdecl, delta, funcdecl)
- FILE *stream;
- tree thunkdecl ATTRIBUTE_UNUSED;
- int delta;
- tree funcdecl;
+static void
+cris_asm_output_mi_thunk (FILE *stream,
+ tree thunkdecl ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT delta,
+ HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+ tree funcdecl)
{
if (delta > 0)
- asm_fprintf (stream, "\tadd%s %d,$%s\n",
- ADDITIVE_SIZE_MODIFIER (delta), delta,
- reg_names[CRIS_FIRST_ARG_REG]);
+ fprintf (stream, "\tadd%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
+ ADDITIVE_SIZE_MODIFIER (delta), delta,
+ reg_names[CRIS_FIRST_ARG_REG]);
else if (delta < 0)
- asm_fprintf (stream, "\tsub%s %d,$%s\n",
- ADDITIVE_SIZE_MODIFIER (-delta), -delta,
- reg_names[CRIS_FIRST_ARG_REG]);
+ fprintf (stream, "\tsub%s " HOST_WIDE_INT_PRINT_DEC ",$%s\n",
+ ADDITIVE_SIZE_MODIFIER (-delta), -delta,
+ reg_names[CRIS_FIRST_ARG_REG]);
if (flag_pic)
{
const char *name = XSTR (XEXP (DECL_RTL (funcdecl), 0), 0);
- STRIP_NAME_ENCODING (name, name);
+ name = (* targetm.strip_name_encoding) (name);
fprintf (stream, "add.d ");
assemble_name (stream, name);
fprintf (stream, "%s,$pc\n", CRIS_PLT_PCOFFSET_SUFFIX);
}
}
-/* The EXPAND_BUILTIN_VA_ARG worker. This is modified from the
- "standard" implementation of va_arg: read the value from the current
- address and increment by the size of one or two registers. The
- important difference for CRIS is that if the type is
- pass-by-reference, then perform an indirection. */
-
-rtx
-cris_expand_builtin_va_arg (valist, type)
- tree valist;
- tree type;
-{
- tree addr_tree, t;
- rtx addr;
- enum machine_mode mode = TYPE_MODE (type);
- int passed_size;
+/* Boilerplate emitted at start of file.
- /* Get AP. */
- addr_tree = valist;
+ NO_APP *only at file start* means faster assembly. It also means
+ comments are not allowed. In some cases comments will be output
+ for debugging purposes. Make sure they are allowed then.
- /* Check if the type is passed by value or by reference. */
- if (MUST_PASS_IN_STACK (mode, type)
- || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8)
- {
- tree type_ptr = build_pointer_type (type);
- addr_tree = build1 (INDIRECT_REF, type_ptr, addr_tree);
- passed_size = 4;
- }
- else
- passed_size = (CRIS_FUNCTION_ARG_SIZE (mode, type) > 4) ? 8 : 4;
-
- addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = copy_to_reg (addr);
+ We want a .file directive only if TARGET_ELF. */
+static void
+cris_file_start (void)
+{
+ /* These expressions can vary at run time, so we cannot put
+ them into TARGET_INITIALIZER. */
+ targetm.file_start_app_off = !(TARGET_PDEBUG || flag_print_asm_name);
+ targetm.file_start_file_directive = TARGET_ELF;
- /* Compute new value for AP. */
- t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build (PLUS_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (passed_size, 0)));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ default_file_start ();
+}
- return addr;
+/* Rename the function calls for integer multiply and divide. */
+static void
+cris_init_libfuncs (void)
+{
+ set_optab_libfunc (smul_optab, SImode, "__Mul");
+ set_optab_libfunc (sdiv_optab, SImode, "__Div");
+ set_optab_libfunc (udiv_optab, SImode, "__Udiv");
+ set_optab_libfunc (smod_optab, SImode, "__Mod");
+ set_optab_libfunc (umod_optab, SImode, "__Umod");
}
/* The INIT_EXPANDERS worker sets the per-function-data initializer and
mark functions. */
void
-cris_init_expanders ()
+cris_init_expanders (void)
{
/* Nothing here at the moment. */
}
/* Zero initialization is OK for all current fields. */
-static void
-cris_init_machine_status (p)
- struct function *p;
+static struct machine_function *
+cris_init_machine_status (void)
{
- p->machine = xcalloc (1, sizeof (struct machine_function));
+ return ggc_alloc_cleared (sizeof (struct machine_function));
}
/* Split a 2 word move (DI or presumably DF) into component parts.
Originally a copy of gen_split_move_double in m32r.c. */
rtx
-cris_split_movdx (operands)
- rtx *operands;
+cris_split_movdx (rtx *operands)
{
enum machine_mode mode = GET_MODE (operands[0]);
rtx dest = operands[0];
rtx src = operands[1];
rtx val;
- /* We might have (SUBREG (MEM)) here, so just get rid of the
- subregs to make this code simpler. It is safe to call
- alter_subreg any time after reload. */
- if (GET_CODE (dest) == SUBREG)
- dest = alter_subreg (dest);
- if (GET_CODE (src) == SUBREG)
- src = alter_subreg (src);
+ /* We used to have to handle (SUBREG (MEM)) here, but that should no
+ longer happen; after reload there are no SUBREGs any more, and we're
+ only called after reload. */
+ if (GET_CODE (dest) == SUBREG || GET_CODE (src) == SUBREG)
+ abort ();
start_sequence ();
if (GET_CODE (dest) == REG)
int reverse
= (refers_to_regno_p (dregno, dregno + 1, addr, NULL) != 0);
- /* The original code imples that we can't do
+ /* The original code implies that we can't do
move.x [rN+],rM move.x [rN],rM+1
when rN is dead, because of REG_NOTES damage. That is
consistent with what I've seen, so don't try it.
if (GET_CODE (addr) == POST_INC)
{
- emit_insn (gen_rtx_SET (VOIDmode,
+ emit_insn (gen_rtx_SET (VOIDmode,
operand_subword (dest, 0, TRUE, mode),
change_address (src, SImode, addr)));
emit_insn (gen_rtx_SET (VOIDmode,
- operand_subword (dest, 1, TRUE, mode),
+ operand_subword (dest, 1, TRUE, mode),
change_address (src, SImode, addr)));
}
else
GO_IF_LEGITIMATE_ADDRESS, but we're here for your
safety. */
if (side_effects_p (addr))
- fatal_insn ("Unexpected side-effects in address", addr);
+ fatal_insn ("unexpected side-effects in address", addr);
emit_insn (gen_rtx_SET
(VOIDmode,
postincrements. They should be stopped in
GO_IF_LEGITIMATE_ADDRESS, but we're here for your safety. */
if (side_effects_p (addr))
- fatal_insn ("Unexpected side-effects in address", addr);
+ fatal_insn ("unexpected side-effects in address", addr);
emit_insn (gen_rtx_SET
(VOIDmode,
else
abort ();
- val = gen_sequence ();
+ val = get_insns ();
end_sequence ();
return val;
}
-/* This is in essence a copy of output_addr_const altered to output
- symbolic operands as PIC.
+/* Use from within code, from e.g. PRINT_OPERAND and
+ PRINT_OPERAND_ADDRESS. Macros used in output_addr_const need to emit
+ different things depending on whether code operand or constant is
+ emitted. */
- FIXME: Add hooks similar to ASM_OUTPUT_SYMBOL_REF to get this effect in
- the "real" output_addr_const. All we need is one for LABEL_REF (and
- one for CODE_LABEL?). */
+static void
+cris_output_addr_const (FILE *file, rtx x)
+{
+ in_code++;
+ output_addr_const (file, x);
+ in_code--;
+}
+
+/* Worker function for ASM_OUTPUT_SYMBOL_REF. */
void
-cris_output_addr_const (file, x)
- FILE *file;
- rtx x;
+cris_asm_output_symbol_ref (FILE *file, rtx x)
{
- int is_plt = 0;
-
-restart:
- switch (GET_CODE (x))
+ if (flag_pic && in_code > 0)
{
- case UNSPEC:
- ASSERT_PLT_UNSPEC (x);
- x = XVECEXP (x, 0, 0);
- is_plt = 1;
+ const char *origstr = XSTR (x, 0);
+ const char *str;
- /* Fall through. */
- case SYMBOL_REF:
- if (flag_pic)
- {
- const char *origstr = XSTR (x, 0);
- const char *str;
-
- STRIP_NAME_ENCODING (str, origstr);
+ str = (* targetm.strip_name_encoding) (origstr);
- if (is_plt)
- {
- if (cris_pic_sympart_only)
- {
- assemble_name (file, str);
- fprintf (file, ":PLTG");
- }
- else
- {
- if (TARGET_AVOID_GOTPLT)
- /* We shouldn't get here. */
- abort ();
-
- fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
- assemble_name (file, XSTR (x, 0));
-
- if (flag_pic == 1)
- fprintf (file, ":GOTPLT16]");
- else
- fprintf (file, ":GOTPLT]");
- }
- }
- else if (cris_gotless_symbol (x))
- {
- if (! cris_pic_sympart_only)
- fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
- assemble_name (file, str);
- fprintf (file, ":GOTOFF");
- }
- else if (cris_got_symbol (x))
- {
- if (cris_pic_sympart_only)
- abort ();
- fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
- assemble_name (file, XSTR (x, 0));
+ if (cris_gotless_symbol (x))
+ {
+ if (! cris_pic_sympart_only)
+ fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ assemble_name (file, str);
+ fprintf (file, ":GOTOFF");
+ }
+ else if (cris_got_symbol (x))
+ {
+ if (cris_pic_sympart_only)
+ abort ();
+ fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ assemble_name (file, XSTR (x, 0));
- if (flag_pic == 1)
- fprintf (file, ":GOT16]");
- else
- fprintf (file, ":GOT]");
- }
+ if (flag_pic == 1)
+ fprintf (file, ":GOT16]");
else
- fatal_insn ("Unexpected PIC symbol", x);
-
- /* Sanity check. */
- if (! current_function_uses_pic_offset_table)
- internal_error ("Emitting PIC operand, but PIC register isn't set up");
+ fprintf (file, ":GOT]");
}
else
- assemble_name (file, XSTR (x, 0));
- break;
+ LOSE_AND_RETURN ("unexpected PIC symbol", x);
- case LABEL_REF:
- /* If we get one of those here, it should be dressed as PIC. Branch
- labels are normally output with the 'l' specifier, which means it
- will go directly to output_asm_label and not end up here. */
- if (GET_CODE (XEXP (x, 0)) != CODE_LABEL
- && (GET_CODE (XEXP (x, 0)) != NOTE
- || NOTE_LINE_NUMBER (XEXP (x, 0)) != NOTE_INSN_DELETED_LABEL))
- fatal_insn ("Unexpected address expression", x);
+ /* Sanity check. */
+ if (! current_function_uses_pic_offset_table)
+ output_operand_lossage ("PIC register isn't set up");
+ }
+ else
+ assemble_name (file, XSTR (x, 0));
+}
- if (flag_pic)
- {
- if (cris_gotless_symbol (x))
- {
- if (! cris_pic_sympart_only)
- fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
- cris_output_addr_const (file, XEXP (x, 0));
+/* Worker function for ASM_OUTPUT_LABEL_REF. */
- fprintf (file, ":GOTOFF");
- }
- else
- /* Labels are never marked as global symbols. */
- fatal_insn ("Unexpected PIC symbol", x);
+void
+cris_asm_output_label_ref (FILE *file, char *buf)
+{
+ if (flag_pic && in_code > 0)
+ {
+ if (! cris_pic_sympart_only)
+ fprintf (file, "$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ assemble_name (file, buf);
- /* Sanity check. */
- if (! current_function_uses_pic_offset_table)
- internal_error ("Emitting PIC operand, but PIC register isn't set up");
- break;
- }
+ fprintf (file, ":GOTOFF");
- output_addr_const (file, x);
- break;
+ /* Sanity check. */
+ if (! current_function_uses_pic_offset_table)
+ internal_error ("emitting PIC operand, but PIC register isn't set up");
+ }
+ else
+ assemble_name (file, buf);
+}
- case NOTE:
- if (NOTE_LINE_NUMBER (x) != NOTE_INSN_DELETED_LABEL)
- fatal_insn ("Unexpected NOTE as addr_const:", x);
- case CODE_LABEL:
- case CONST_INT:
- case CONST_DOUBLE:
- case ZERO_EXTEND:
- case SIGN_EXTEND:
- output_addr_const (file, x);
- break;
+/* Worker function for OUTPUT_ADDR_CONST_EXTRA. */
- case CONST:
- /* This used to output parentheses around the expression,
- but that does not work on the 386 (either ATT or BSD assembler). */
- cris_output_addr_const (file, XEXP (x, 0));
- break;
+bool
+cris_output_addr_const_extra (FILE *file, rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ const char *origstr;
+ const char *str;
- case PLUS:
- /* Some assemblers need integer constants to appear last (eg masm). */
- if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ case UNSPEC:
+ ASSERT_PLT_UNSPEC (x);
+ x = XVECEXP (x, 0, 0);
+ origstr = XSTR (x, 0);
+ str = (* targetm.strip_name_encoding) (origstr);
+ if (cris_pic_sympart_only)
{
- cris_output_addr_const (file, XEXP (x, 1));
- if (INTVAL (XEXP (x, 0)) >= 0)
- fprintf (file, "+");
- output_addr_const (file, XEXP (x, 0));
+ assemble_name (file, str);
+ fprintf (file, ":PLTG");
}
else
{
- cris_output_addr_const (file, XEXP (x, 0));
- if (GET_CODE (XEXP (x, 1)) != CONST_INT
- || INTVAL (XEXP (x, 1)) >= 0)
- fprintf (file, "+");
- cris_output_addr_const (file, XEXP (x, 1));
- }
- break;
+ if (TARGET_AVOID_GOTPLT)
+ /* We shouldn't get here. */
+ abort ();
- case MINUS:
- /* Avoid outputting things like x-x or x+5-x,
- since some assemblers can't handle that. */
- x = simplify_subtraction (x);
- if (GET_CODE (x) != MINUS)
- goto restart;
-
- cris_output_addr_const (file, XEXP (x, 0));
- fprintf (file, "-");
- if ((GET_CODE (XEXP (x, 1)) == CONST_INT
- && INTVAL (XEXP (x, 1)) < 0)
- || GET_CODE (XEXP (x, 1)) != CONST_INT)
- {
- fprintf (file, "%s", targetm.asm_out.open_paren);
- cris_output_addr_const (file, XEXP (x, 1));
- fprintf (file, "%s", targetm.asm_out.close_paren);
+ fprintf (file, "[$%s+", reg_names [PIC_OFFSET_TABLE_REGNUM]);
+ assemble_name (file, XSTR (x, 0));
+
+ if (flag_pic == 1)
+ fprintf (file, ":GOTPLT16]");
+ else
+ fprintf (file, ":GOTPLT]");
}
- else
- output_addr_const (file, XEXP (x, 1));
- break;
+ return true;
default:
- fatal_insn ("Unexpected address expression", x);
+ return false;
}
}
-/* The ENCODE_SECTION_INFO worker. Code-in whether we can get away
- without a GOT entry (needed for externally visible objects but not for
- functions) into SYMBOL_REF_FLAG and add the PLT suffix for global
- functions. */
+/* Worker function for TARGET_STRUCT_VALUE_RTX. */
-void
-cris_encode_section_info (exp)
- tree exp;
+static rtx
+cris_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+ int incoming ATTRIBUTE_UNUSED)
{
- if (flag_pic)
+ return gen_rtx_REG (Pmode, CRIS_STRUCT_VALUE_REGNUM);
+}
+
+/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
+
+static void
+cris_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ tree type ATTRIBUTE_UNUSED,
+ int *pretend_arg_size,
+ int second_time)
+{
+ if (ca->regs < CRIS_MAX_ARGS_IN_REGS)
+ *pretend_arg_size = (CRIS_MAX_ARGS_IN_REGS - ca->regs) * 4;
+ if (TARGET_PDEBUG)
{
- if (DECL_P (exp))
- {
- if (TREE_CODE (exp) == FUNCTION_DECL
- && (TREE_PUBLIC (exp) || DECL_WEAK (exp)))
- SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0)) = 0;
- else
- SYMBOL_REF_FLAG (XEXP (DECL_RTL (exp), 0))
- = ! TREE_PUBLIC (exp) && ! DECL_WEAK (exp);
- }
- else
- /* Others are local entities. */
- SYMBOL_REF_FLAG (XEXP (TREE_CST_RTL (exp), 0)) = 1;
+ fprintf (asm_out_file,
+ "\n; VA:: ANSI: %d args before, anon @ #%d, %dtime\n",
+ ca->regs, *pretend_arg_size, second_time);
}
}
+/* Return true if TYPE must be passed by invisible reference.
+ For cris, we pass <= 8 bytes by value, others by reference. */
+
+static bool
+cris_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
+ enum machine_mode mode, tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ return (targetm.calls.must_pass_in_stack (mode, type)
+ || CRIS_FUNCTION_ARG_SIZE (mode, type) > 8);
+}
+
+
+static int
+cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ if (ca->regs == CRIS_MAX_ARGS_IN_REGS - 1
+ && !targetm.calls.must_pass_in_stack (mode, type)
+ && CRIS_FUNCTION_ARG_SIZE (mode, type) > 4
+ && CRIS_FUNCTION_ARG_SIZE (mode, type) <= 8)
+ return UNITS_PER_WORD;
+ else
+ return 0;
+}
+
+
#if 0
/* Various small functions to replace macros. Only called from a
debugger. They might collide with gcc functions or system functions,
so only emit them when '#if 1' above. */
-enum rtx_code Get_code PARAMS ((rtx));
+enum rtx_code Get_code (rtx);
enum rtx_code
-Get_code (x)
- rtx x;
+Get_code (rtx x)
{
return GET_CODE (x);
}
-const char *Get_mode PARAMS ((rtx));
+const char *Get_mode (rtx);
const char *
-Get_mode (x)
- rtx x;
+Get_mode (rtx x)
{
return GET_MODE_NAME (GET_MODE (x));
}
-rtx Xexp PARAMS ((rtx, int));
+rtx Xexp (rtx, int);
rtx
-Xexp (x, n)
- rtx x;
- int n;
+Xexp (rtx x, int n)
{
return XEXP (x, n);
}
-rtx Xvecexp PARAMS ((rtx, int, int));
+rtx Xvecexp (rtx, int, int);
rtx
-Xvecexp (x, n, m)
- rtx x;
- int n;
-{
+Xvecexp (rtx x, int n, int m)
+{
return XVECEXP (x, n, m);
}
-int Get_rtx_len PARAMS ((rtx));
+int Get_rtx_len (rtx);
int
-Get_rtx_len (x)
- rtx x;
+Get_rtx_len (rtx x)
{
return GET_RTX_LENGTH (GET_CODE (x));
}
/* Use upper-case to distinguish from local variables that are sometimes
called next_insn and prev_insn. */
-rtx Next_insn PARAMS ((rtx));
+rtx Next_insn (rtx);
rtx
-Next_insn (insn)
- rtx insn;
+Next_insn (rtx insn)
{
return NEXT_INSN (insn);
}
-rtx Prev_insn PARAMS ((rtx));
+rtx Prev_insn (rtx);
rtx
-Prev_insn (insn)
- rtx insn;
+Prev_insn (rtx insn)
{
return PREV_INSN (insn);
}
#endif
+#include "gt-cris.h"
+
/*
* Local variables:
* eval: (c-set-style "gnu")