Index: gcc/gcc/config/cris/cris.c |
diff --git a/gcc/gcc/config/cris/cris.c b/gcc/gcc/config/cris/cris.c |
index 9bae9cdb44ed42e025c6073d0791ea996ac44bf1..225ad403dda7eb657188a5883f1c583217ec589b 100644 |
--- a/gcc/gcc/config/cris/cris.c |
+++ b/gcc/gcc/config/cris/cris.c |
@@ -1,6 +1,6 @@ |
/* Definitions for GCC. Part of the machine description for CRIS. |
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, |
- 2008 Free Software Foundation, Inc. |
+ 2008, 2009 Free Software Foundation, Inc. |
Contributed by Axis Communications. Written by Hans-Peter Nilsson. |
This file is part of GCC. |
@@ -63,7 +63,7 @@ enum cris_retinsn_type |
{ CRIS_RETINSN_UNKNOWN = 0, CRIS_RETINSN_RET, CRIS_RETINSN_JUMP }; |
/* Per-function machine data. */ |
-struct machine_function GTY(()) |
+struct GTY(()) machine_function |
{ |
int needs_return_address_on_stack; |
@@ -85,6 +85,9 @@ static int in_code = 0; |
/* Fix for reg_overlap_mentioned_p. */ |
static int cris_reg_overlap_mentioned_p (rtx, rtx); |
+static enum machine_mode cris_promote_function_mode (const_tree, enum machine_mode, |
+ int *, const_tree, int); |
+ |
static void cris_print_base (rtx, FILE *); |
static void cris_print_index (rtx, FILE *); |
@@ -122,6 +125,14 @@ static tree cris_md_asm_clobbers (tree, tree, tree); |
static bool cris_handle_option (size_t, const char *, int); |
+static bool cris_frame_pointer_required (void); |
+ |
+static void cris_asm_trampoline_template (FILE *); |
+static void cris_trampoline_init (rtx, tree, rtx); |
+ |
+static rtx cris_function_value(const_tree, const_tree, bool); |
+static rtx cris_libcall_value (enum machine_mode, const_rtx); |
+ |
/* This is the parsed result of the "-max-stack-stackframe=" option. If |
it (still) is zero, then there was no such option given. */ |
int cris_max_stackframe = 0; |
@@ -164,8 +175,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; |
#undef TARGET_ADDRESS_COST |
#define TARGET_ADDRESS_COST cris_address_cost |
-#undef TARGET_PROMOTE_FUNCTION_ARGS |
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true |
+#undef TARGET_PROMOTE_FUNCTION_MODE |
+#define TARGET_PROMOTE_FUNCTION_MODE cris_promote_function_mode |
+ |
#undef TARGET_STRUCT_VALUE_RTX |
#define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx |
#undef TARGET_SETUP_INCOMING_VARARGS |
@@ -180,6 +192,18 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; |
#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | CRIS_SUBTARGET_DEFAULT) |
#undef TARGET_HANDLE_OPTION |
#define TARGET_HANDLE_OPTION cris_handle_option |
+#undef TARGET_FRAME_POINTER_REQUIRED |
+#define TARGET_FRAME_POINTER_REQUIRED cris_frame_pointer_required |
+ |
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE |
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE cris_asm_trampoline_template |
+#undef TARGET_TRAMPOLINE_INIT |
+#define TARGET_TRAMPOLINE_INIT cris_trampoline_init |
+ |
+#undef TARGET_FUNCTION_VALUE |
+#define TARGET_FUNCTION_VALUE cris_function_value |
+#undef TARGET_LIBCALL_VALUE |
+#define TARGET_LIBCALL_VALUE cris_libcall_value |
struct gcc_target targetm = TARGET_INITIALIZER; |
@@ -1431,13 +1455,18 @@ cris_normal_notice_update_cc (rtx exp, rtx insn) |
if (SET_DEST (exp) == cc0_rtx) |
{ |
CC_STATUS_INIT; |
- cc_status.value1 = SET_SRC (exp); |
- /* Handle flags for the special btstq on one bit. */ |
- if (GET_CODE (SET_SRC (exp)) == ZERO_EXTRACT |
- && XEXP (SET_SRC (exp), 1) == const1_rtx) |
+ if (GET_CODE (SET_SRC (exp)) == COMPARE |
+ && XEXP (SET_SRC (exp), 1) == const0_rtx) |
+ cc_status.value1 = XEXP (SET_SRC (exp), 0); |
+ else |
+ cc_status.value1 = SET_SRC (exp); |
+ |
+ /* Handle flags for the special btstq on one bit. */ |
+ if (GET_CODE (cc_status.value1) == ZERO_EXTRACT |
+ && XEXP (cc_status.value1, 1) == const1_rtx) |
{ |
- if (CONST_INT_P (XEXP (SET_SRC (exp), 0))) |
+ if (CONST_INT_P (XEXP (cc_status.value1, 0))) |
/* Using cmpq. */ |
cc_status.flags = CC_INVERTED; |
else |
@@ -1445,7 +1474,7 @@ cris_normal_notice_update_cc (rtx exp, rtx insn) |
cc_status.flags = CC_Z_IN_NOT_N; |
} |
- if (GET_CODE (SET_SRC (exp)) == COMPARE) |
+ else if (GET_CODE (SET_SRC (exp)) == COMPARE) |
{ |
if (!REG_P (XEXP (SET_SRC (exp), 0)) |
&& XEXP (SET_SRC (exp), 1) != const0_rtx) |
@@ -1855,6 +1884,11 @@ cris_rtx_costs (rtx x, int code, int outer_code, int *total, |
} |
return false; |
+ case ZERO_EXTRACT: |
+ if (outer_code != COMPARE) |
+ return false; |
+ /* fall through */ |
+ |
case ZERO_EXTEND: case SIGN_EXTEND: |
*total = rtx_cost (XEXP (x, 0), outer_code, speed); |
return true; |
@@ -3739,6 +3773,54 @@ cris_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED, |
|| CRIS_FUNCTION_ARG_SIZE (mode, type) > 8); |
} |
+/* A combination of defining TARGET_PROMOTE_FUNCTION_MODE, promoting arguments |
+ and *not* defining TARGET_PROMOTE_PROTOTYPES or PROMOTE_MODE gives the |
+ best code size and speed for gcc, ipps and products in gcc-2.7.2. */ |
+ |
+enum machine_mode |
+cris_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, |
+ enum machine_mode mode, |
+ int *punsignedp ATTRIBUTE_UNUSED, |
+ const_tree fntype ATTRIBUTE_UNUSED, |
+ int for_return) |
+{ |
+ /* Defining PROMOTE_FUNCTION_RETURN in gcc-2.7.2 uncovered bug 981110 (even |
+ when modifying TARGET_FUNCTION_VALUE to return the promoted mode). |
+ Maybe pointless as of now, but let's keep the old behavior. */ |
+ if (for_return == 1) |
+ return mode; |
+ return CRIS_PROMOTED_MODE (mode, *punsignedp, type); |
+} |
+ |
+/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the |
+ time being. */ |
+ |
+static rtx |
+cris_function_value(const_tree type, |
+ const_tree func ATTRIBUTE_UNUSED, |
+ bool outgoing ATTRIBUTE_UNUSED) |
+{ |
+ return gen_rtx_REG (TYPE_MODE (type), CRIS_FIRST_ARG_REG); |
+} |
+ |
+/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the |
+ time being. */ |
+ |
+static rtx |
+cris_libcall_value (enum machine_mode mode, |
+ const_rtx fun ATTRIBUTE_UNUSED) |
+{ |
+ return gen_rtx_REG (mode, CRIS_FIRST_ARG_REG); |
+} |
+ |
+/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the |
+ time being. */ |
+ |
+bool |
+cris_function_value_regno_p (const unsigned int regno) |
+{ |
+ return (regno == CRIS_FIRST_ARG_REG); |
+} |
static int |
cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode, |
@@ -3804,6 +3886,115 @@ cris_md_asm_clobbers (tree outputs, tree inputs, tree in_clobbers) |
clobbers); |
} |
+/* Implement TARGET_FRAME_POINTER_REQUIRED. |
+ |
+ Really only needed if the stack frame has variable length (alloca |
+ or variable sized local arguments (GNU C extension). See PR39499 and |
+ PR38609 for the reason this isn't just 0. */ |
+ |
+bool |
+cris_frame_pointer_required (void) |
+{ |
+ return !current_function_sp_is_unchanging; |
+} |
+ |
+/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. |
+ |
+ This looks too complicated, and it is. I assigned r7 to be the |
+ static chain register, but it is call-saved, so we have to save it, |
+ and come back to restore it after the call, so we have to save srp... |
+ Anyway, trampolines are rare enough that we can cope with this |
+ somewhat lack of elegance. |
+ (Do not be tempted to "straighten up" whitespace in the asms; the |
+ assembler #NO_APP state mandates strict spacing). */ |
+/* ??? See the i386 regparm=3 implementation that pushes the static |
+ chain value to the stack in the trampoline, and uses a call-saved |
+ register when called directly. */ |
+ |
+static void |
+cris_asm_trampoline_template (FILE *f) |
+{ |
+ if (TARGET_V32) |
+ { |
+ /* This normally-unused nop insn acts as an instruction to |
+ the simulator to flush its instruction cache. None of |
+ the other instructions in the trampoline template suits |
+ as a trigger for V32. The pc-relative addressing mode |
+ works nicely as a trigger for V10. |
+ FIXME: Have specific V32 template (possibly avoiding the |
+ use of a special instruction). */ |
+ fprintf (f, "\tclearf x\n"); |
+ /* We have to use a register as an intermediate, choosing |
+ semi-randomly R1 (which has to not be the STATIC_CHAIN_REGNUM), |
+ so we can use it for address indirection and jsr target. */ |
+ fprintf (f, "\tmove $r1,$mof\n"); |
+ /* +4 */ |
+ fprintf (f, "\tmove.d 0,$r1\n"); |
+ fprintf (f, "\tmove.d $%s,[$r1]\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ fprintf (f, "\taddq 6,$r1\n"); |
+ fprintf (f, "\tmove $mof,[$r1]\n"); |
+ fprintf (f, "\taddq 6,$r1\n"); |
+ fprintf (f, "\tmove $srp,[$r1]\n"); |
+ /* +20 */ |
+ fprintf (f, "\tmove.d 0,$%s\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ /* +26 */ |
+ fprintf (f, "\tmove.d 0,$r1\n"); |
+ fprintf (f, "\tjsr $r1\n"); |
+ fprintf (f, "\tsetf\n"); |
+ /* +36 */ |
+ fprintf (f, "\tmove.d 0,$%s\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ /* +42 */ |
+ fprintf (f, "\tmove.d 0,$r1\n"); |
+ /* +48 */ |
+ fprintf (f, "\tmove.d 0,$r9\n"); |
+ fprintf (f, "\tjump $r9\n"); |
+ fprintf (f, "\tsetf\n"); |
+ } |
+ else |
+ { |
+ fprintf (f, "\tmove.d $%s,[$pc+20]\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ fprintf (f, "\tmove $srp,[$pc+22]\n"); |
+ fprintf (f, "\tmove.d 0,$%s\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ fprintf (f, "\tjsr 0\n"); |
+ fprintf (f, "\tmove.d 0,$%s\n", reg_names[STATIC_CHAIN_REGNUM]); |
+ fprintf (f, "\tjump 0\n"); |
+ } |
+} |
+ |
+/* Implement TARGET_TRAMPOLINE_INIT. */ |
+ |
+static void |
+cris_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) |
+{ |
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); |
+ rtx tramp = XEXP (m_tramp, 0); |
+ rtx mem; |
+ |
+ emit_block_move (m_tramp, assemble_trampoline_template (), |
+ GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); |
+ |
+ if (TARGET_V32) |
+ { |
+ mem = adjust_address (m_tramp, SImode, 6); |
+ emit_move_insn (mem, plus_constant (tramp, 38)); |
+ mem = adjust_address (m_tramp, SImode, 22); |
+ emit_move_insn (mem, chain_value); |
+ mem = adjust_address (m_tramp, SImode, 28); |
+ emit_move_insn (mem, fnaddr); |
+ } |
+ else |
+ { |
+ mem = adjust_address (m_tramp, SImode, 10); |
+ emit_move_insn (mem, chain_value); |
+ mem = adjust_address (m_tramp, SImode, 16); |
+ emit_move_insn (mem, fnaddr); |
+ } |
+ |
+ /* Note that there is no need to do anything with the cache for |
+ sake of a trampoline. */ |
+} |
+ |
+ |
#if 0 |
/* Various small functions to replace macros. Only called from a |
debugger. They might collide with gcc functions or system functions, |