Index: gcc/gcc/config/frv/frv.c |
diff --git a/gcc/gcc/config/frv/frv.c b/gcc/gcc/config/frv/frv.c |
index 7dde7e4464badf32e8c5d4bf15a258b455110603..a757472f37bf76979ce37f60f48e32e6fe455945 100644 |
--- a/gcc/gcc/config/frv/frv.c |
+++ b/gcc/gcc/config/frv/frv.c |
@@ -1,5 +1,5 @@ |
/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, |
- 2008 Free Software Foundation, Inc. |
+ 2008, 2009 Free Software Foundation, Inc. |
Contributed by Red Hat, Inc. |
This file is part of GCC. |
@@ -139,7 +139,7 @@ struct frv_io { |
REG++) |
/* This structure contains machine specific function data. */ |
-struct machine_function GTY(()) |
+struct GTY(()) machine_function |
{ |
/* True if we have created an rtx that relies on the stack frame. */ |
int frame_needed; |
@@ -193,11 +193,6 @@ typedef struct |
int base_offset; |
} frv_frame_accessor_t; |
-/* Define the information needed to generate branch and scc insns. This is |
- stored from the compare operation. */ |
-rtx frv_compare_op0; |
-rtx frv_compare_op1; |
- |
/* Conditional execution support gathered together in one structure. */ |
typedef struct |
{ |
@@ -269,6 +264,7 @@ frv_cpu_t frv_cpu_type = CPU_TYPE; /* value of -mcpu= */ |
/* Forward references */ |
static bool frv_handle_option (size_t, const char *, int); |
+static bool frv_legitimate_address_p (enum machine_mode, rtx, bool); |
static int frv_default_flags_for_cpu (void); |
static int frv_string_begins_with (const_tree, const char *); |
static FRV_INLINE bool frv_small_data_reloc_p (rtx, int); |
@@ -277,6 +273,10 @@ static void frv_print_operand_memory_reference_reg |
static void frv_print_operand_memory_reference (FILE *, rtx, int); |
static int frv_print_operand_jump_hint (rtx); |
static const char *comparison_string (enum rtx_code, rtx); |
+static rtx frv_function_value (const_tree, const_tree, |
+ bool); |
+static rtx frv_libcall_value (enum machine_mode, |
+ const_rtx); |
static FRV_INLINE int frv_regno_ok_for_base_p (int, int); |
static rtx single_set_pattern (rtx); |
static int frv_function_contains_far_jump (void); |
@@ -303,6 +303,7 @@ static int frv_check_constant_argument (enum insn_code, int, rtx); |
static rtx frv_legitimize_target (enum insn_code, rtx); |
static rtx frv_legitimize_argument (enum insn_code, int, rtx); |
static rtx frv_legitimize_tls_address (rtx, enum tls_model); |
+static rtx frv_legitimize_address (rtx, rtx, enum machine_mode); |
static rtx frv_expand_set_builtin (enum insn_code, tree, rtx); |
static rtx frv_expand_unop_builtin (enum insn_code, tree, rtx); |
static rtx frv_expand_binop_builtin (enum insn_code, tree, rtx); |
@@ -384,6 +385,9 @@ static void frv_output_dwarf_dtprel (FILE *, int, rtx) |
static bool frv_secondary_reload (bool, rtx, enum reg_class, |
enum machine_mode, |
secondary_reload_info *); |
+static bool frv_frame_pointer_required (void); |
+static bool frv_can_eliminate (const int, const int); |
+static void frv_trampoline_init (rtx, tree, rtx); |
/* Allow us to easily change the default for -malloc-cc. */ |
#ifndef DEFAULT_NO_ALLOC_CC |
@@ -433,6 +437,9 @@ static bool frv_secondary_reload (bool, rtx, enum reg_class, |
#undef TARGET_SCHED_ISSUE_RATE |
#define TARGET_SCHED_ISSUE_RATE frv_issue_rate |
+#undef TARGET_LEGITIMIZE_ADDRESS |
+#define TARGET_LEGITIMIZE_ADDRESS frv_legitimize_address |
+ |
#undef TARGET_FUNCTION_OK_FOR_SIBCALL |
#define TARGET_FUNCTION_OK_FOR_SIBCALL frv_function_ok_for_sibcall |
#undef TARGET_CANNOT_FORCE_CONST_MEM |
@@ -468,6 +475,23 @@ static bool frv_secondary_reload (bool, rtx, enum reg_class, |
#undef TARGET_SECONDARY_RELOAD |
#define TARGET_SECONDARY_RELOAD frv_secondary_reload |
+#undef TARGET_LEGITIMATE_ADDRESS_P |
+#define TARGET_LEGITIMATE_ADDRESS_P frv_legitimate_address_p |
+ |
+#undef TARGET_FRAME_POINTER_REQUIRED |
+#define TARGET_FRAME_POINTER_REQUIRED frv_frame_pointer_required |
+ |
+#undef TARGET_CAN_ELIMINATE |
+#define TARGET_CAN_ELIMINATE frv_can_eliminate |
+ |
+#undef TARGET_TRAMPOLINE_INIT |
+#define TARGET_TRAMPOLINE_INIT frv_trampoline_init |
+ |
+#undef TARGET_FUNCTION_VALUE |
+#define TARGET_FUNCTION_VALUE frv_function_value |
+#undef TARGET_LIBCALL_VALUE |
+#define TARGET_LIBCALL_VALUE frv_libcall_value |
+ |
struct gcc_target targetm = TARGET_INITIALIZER; |
#define FRV_SYMBOL_REF_TLS_P(RTX) \ |
@@ -1687,7 +1711,21 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset) |
emit_insn (gen_rtx_SET (VOIDmode, reg, temp)); |
} |
else |
- emit_insn (gen_rtx_SET (VOIDmode, reg, mem)); |
+ { |
+ /* We cannot use reg+reg addressing for DImode access. */ |
+ if (mode == DImode |
+ && GET_CODE (XEXP (mem, 0)) == PLUS |
+ && GET_CODE (XEXP (XEXP (mem, 0), 0)) == REG |
+ && GET_CODE (XEXP (XEXP (mem, 0), 1)) == REG) |
+ { |
+ rtx temp = gen_rtx_REG (SImode, TEMP_REGNO); |
+ rtx insn = emit_move_insn (temp, |
+ gen_rtx_PLUS (SImode, XEXP (XEXP (mem, 0), 0), |
+ XEXP (XEXP (mem, 0), 1))); |
+ mem = gen_rtx_MEM (DImode, temp); |
+ } |
+ emit_insn (gen_rtx_SET (VOIDmode, reg, mem)); |
+ } |
emit_use (reg); |
} |
else |
@@ -1699,7 +1737,7 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset) |
frv_frame_insn (gen_rtx_SET (Pmode, mem, temp), |
frv_dwarf_store (reg, stack_offset)); |
} |
- else if (GET_MODE (reg) == DImode) |
+ else if (mode == DImode) |
{ |
/* For DImode saves, the dwarf2 version needs to be a SEQUENCE |
with a separate save for each register. */ |
@@ -1707,6 +1745,19 @@ frv_frame_access (frv_frame_accessor_t *accessor, rtx reg, int stack_offset) |
rtx reg2 = gen_rtx_REG (SImode, REGNO (reg) + 1); |
rtx set1 = frv_dwarf_store (reg1, stack_offset); |
rtx set2 = frv_dwarf_store (reg2, stack_offset + 4); |
+ |
+ /* Also we cannot use reg+reg addressing. */ |
+ if (GET_CODE (XEXP (mem, 0)) == PLUS |
+ && GET_CODE (XEXP (XEXP (mem, 0), 0)) == REG |
+ && GET_CODE (XEXP (XEXP (mem, 0), 1)) == REG) |
+ { |
+ rtx temp = gen_rtx_REG (SImode, TEMP_REGNO); |
+ rtx insn = emit_move_insn (temp, |
+ gen_rtx_PLUS (SImode, XEXP (XEXP (mem, 0), 0), |
+ XEXP (XEXP (mem, 0), 1))); |
+ mem = gen_rtx_MEM (DImode, temp); |
+ } |
+ |
frv_frame_insn (gen_rtx_SET (Pmode, mem, reg), |
gen_rtx_PARALLEL (VOIDmode, |
gen_rtvec (2, set1, set2))); |
@@ -2075,28 +2126,10 @@ frv_asm_output_mi_thunk (FILE *file, |
} |
-/* A C expression which is nonzero if a function must have and use a frame |
- pointer. This expression is evaluated in the reload pass. If its value is |
- nonzero the function will have a frame pointer. |
- |
- The expression can in principle examine the current function and decide |
- according to the facts, but on most machines the constant 0 or the constant |
- 1 suffices. Use 0 when the machine allows code to be generated with no |
- frame pointer, and doing so saves some time or space. Use 1 when there is |
- no possible advantage to avoiding a frame pointer. |
- |
- In certain cases, the compiler does not know how to produce valid code |
- without a frame pointer. The compiler recognizes those cases and |
- automatically gives the function a frame pointer regardless of what |
- `FRAME_POINTER_REQUIRED' says. You don't need to worry about them. |
- |
- In a function that does not require a frame pointer, the frame pointer |
- register can be allocated for ordinary usage, unless you mark it as a fixed |
- register. See `FIXED_REGISTERS' for more information. */ |
/* On frv, create a frame whenever we need to create stack. */ |
-int |
+static bool |
frv_frame_pointer_required (void) |
{ |
/* If we forgoing the usual linkage requirements, we only need |
@@ -2105,30 +2138,40 @@ frv_frame_pointer_required (void) |
return !current_function_sp_is_unchanging; |
if (! current_function_is_leaf) |
- return TRUE; |
+ return true; |
if (get_frame_size () != 0) |
- return TRUE; |
+ return true; |
if (cfun->stdarg) |
- return TRUE; |
+ return true; |
if (!current_function_sp_is_unchanging) |
- return TRUE; |
+ return true; |
if (!TARGET_FDPIC && flag_pic && crtl->uses_pic_offset_table) |
- return TRUE; |
+ return true; |
if (profile_flag) |
- return TRUE; |
+ return true; |
if (cfun->machine->frame_needed) |
- return TRUE; |
+ return true; |
- return FALSE; |
+ return false; |
} |
+/* Worker function for TARGET_CAN_ELIMINATE. */ |
+ |
+bool |
+frv_can_eliminate (const int from, const int to) |
+{ |
+ return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM |
+ ? ! frame_pointer_needed |
+ : true); |
+} |
+ |
/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It specifies the |
initial difference between the specified pair of registers. This macro must |
be defined if `ELIMINABLE_REGS' is defined. */ |
@@ -2506,7 +2549,7 @@ frv_return_addr_rtx (int count, rtx frame) |
MEMREF has already happened. |
MEMREF must be a legitimate operand for modes larger than SImode. |
- GO_IF_LEGITIMATE_ADDRESS forbids register+register addresses, which |
+ frv_legitimate_address_p forbids register+register addresses, which |
this function cannot handle. */ |
rtx |
frv_index_memory (rtx memref, enum machine_mode mode, int index) |
@@ -2545,6 +2588,12 @@ frv_print_operand_address (FILE * stream, rtx x) |
output_addr_const (stream, x); |
return; |
+ case PLUS: |
+ /* Poorly constructed asm statements can trigger this alternative. |
+ See gcc/testsuite/gcc.dg/asm-4.c for an example. */ |
+ frv_print_operand_memory_reference (stream, x, 0); |
+ return; |
+ |
default: |
break; |
} |
@@ -3251,6 +3300,35 @@ frv_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, |
} |
+/* Implements TARGET_FUNCTION_VALUE. */ |
+ |
+static rtx |
+frv_function_value (const_tree valtype, |
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED, |
+ bool outgoing ATTRIBUTE_UNUSED) |
+{ |
+ return gen_rtx_REG (TYPE_MODE (valtype), RETURN_VALUE_REGNUM); |
+} |
+ |
+ |
+/* Implements TARGET_LIBCALL_VALUE. */ |
+ |
+static rtx |
+frv_libcall_value (enum machine_mode mode, |
+ const_rtx fun ATTRIBUTE_UNUSED) |
+{ |
+ return gen_rtx_REG (mode, RETURN_VALUE_REGNUM); |
+} |
+ |
+ |
+/* Implements FUNCTION_VALUE_REGNO_P. */ |
+ |
+bool |
+frv_function_value_regno_p (const unsigned int regno) |
+{ |
+ return (regno == RETURN_VALUE_REGNUM); |
+} |
+ |
/* Return true if a register is ok to use as a base or index register. */ |
static FRV_INLINE int |
@@ -3291,12 +3369,6 @@ frv_regno_ok_for_base_p (int regno, int strict_p) |
conditional to define the strict variant in that case and the non-strict |
variant otherwise. |
- Subroutines to check for acceptable registers for various purposes (one for |
- base registers, one for index registers, and so on) are typically among the |
- subroutines used to define `GO_IF_LEGITIMATE_ADDRESS'. Then only these |
- subroutine macros need have two variants; the higher levels of macros may be |
- the same whether strict or not. |
- |
Normally, constant addresses which are the sum of a `symbol_ref' and an |
integer are stored inside a `const' RTX to mark them as constant. |
Therefore, there is no need to recognize such sums specifically as |
@@ -3307,30 +3379,14 @@ frv_regno_ok_for_base_p (int regno, int strict_p) |
are not marked with `const'. It assumes that a naked `plus' indicates |
indexing. If so, then you *must* reject such naked constant sums as |
illegitimate addresses, so that none of them will be given to |
- `PRINT_OPERAND_ADDRESS'. |
- |
- On some machines, whether a symbolic address is legitimate depends on the |
- section that the address refers to. On these machines, define the macro |
- `ENCODE_SECTION_INFO' to store the information into the `symbol_ref', and |
- then check for it here. When you see a `const', you will have to look |
- inside it to find the `symbol_ref' in order to determine the section. |
- |
- The best way to modify the name string is by adding text to the beginning, |
- with suitable punctuation to prevent any ambiguity. Allocate the new name |
- in `saveable_obstack'. You will have to modify `ASM_OUTPUT_LABELREF' to |
- remove and decode the added text and output the name accordingly, and define |
- `(* targetm.strip_name_encoding)' to access the original name string. |
- |
- You can check the information stored here into the `symbol_ref' in the |
- definitions of the macros `GO_IF_LEGITIMATE_ADDRESS' and |
`PRINT_OPERAND_ADDRESS'. */ |
int |
-frv_legitimate_address_p (enum machine_mode mode, |
- rtx x, |
- int strict_p, |
- int condexec_p, |
- int allow_double_reg_p) |
+frv_legitimate_address_p_1 (enum machine_mode mode, |
+ rtx x, |
+ int strict_p, |
+ int condexec_p, |
+ int allow_double_reg_p) |
{ |
rtx x0, x1; |
int ret = 0; |
@@ -3448,7 +3504,7 @@ frv_legitimate_address_p (enum machine_mode mode, |
if (TARGET_DEBUG_ADDR) |
{ |
- fprintf (stderr, "\n========== GO_IF_LEGITIMATE_ADDRESS, mode = %s, result = %d, addresses are %sstrict%s\n", |
+ fprintf (stderr, "\n========== legitimate_address_p, mode = %s, result = %d, addresses are %sstrict%s\n", |
GET_MODE_NAME (mode), ret, (strict_p) ? "" : "not ", |
(condexec_p) ? ", inside conditional code" : ""); |
debug_rtx (x); |
@@ -3457,6 +3513,12 @@ frv_legitimate_address_p (enum machine_mode mode, |
return ret; |
} |
+bool |
+frv_legitimate_address_p (enum machine_mode mode, rtx x, bool strict_p) |
+{ |
+ return frv_legitimate_address_p_1 (mode, x, strict_p, FALSE, FALSE); |
+} |
+ |
/* Given an ADDR, generate code to inline the PLT. */ |
static rtx |
gen_inlined_tls_plt (rtx addr) |
@@ -3628,7 +3690,7 @@ frv_legitimize_address (rtx x, |
return frv_legitimize_tls_address (x, model); |
} |
- return NULL_RTX; |
+ return x; |
} |
/* Test whether a local function descriptor is canonical, i.e., |
@@ -3751,8 +3813,8 @@ frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p) |
{ |
return ((GET_MODE (op) == mode || mode == VOIDmode) |
&& GET_CODE (op) == MEM |
- && frv_legitimate_address_p (mode, XEXP (op, 0), |
- reload_completed, condexec_p, FALSE)); |
+ && frv_legitimate_address_p_1 (mode, XEXP (op, 0), |
+ reload_completed, condexec_p, FALSE)); |
} |
void |
@@ -3912,7 +3974,7 @@ condexec_memory_operand (rtx op, enum machine_mode mode) |
return FALSE; |
addr = XEXP (op, 0); |
- return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE); |
+ return frv_legitimate_address_p_1 (mode, addr, reload_completed, TRUE, FALSE); |
} |
/* Return true if the bare return instruction can be used outside of the |
@@ -4731,19 +4793,18 @@ frv_emit_comparison (enum rtx_code test, rtx op0, rtx op1) |
} |
-/* Emit code for a conditional branch. The comparison operands were previously |
- stored in frv_compare_op0 and frv_compare_op1. |
- |
+/* Emit code for a conditional branch. |
XXX: I originally wanted to add a clobber of a CCR register to use in |
conditional execution, but that confuses the rest of the compiler. */ |
int |
-frv_emit_cond_branch (enum rtx_code test, rtx label) |
+frv_emit_cond_branch (rtx operands[]) |
{ |
rtx test_rtx; |
rtx label_ref; |
rtx if_else; |
- rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1); |
+ enum rtx_code test = GET_CODE (operands[0]); |
+ rtx cc_reg = frv_emit_comparison (test, operands[1], operands[2]); |
enum machine_mode cc_mode = GET_MODE (cc_reg); |
/* Branches generate: |
@@ -4751,7 +4812,7 @@ frv_emit_cond_branch (enum rtx_code test, rtx label) |
(if_then_else (<test>, <cc_reg>, (const_int 0)) |
(label_ref <branch_label>) |
(pc))) */ |
- label_ref = gen_rtx_LABEL_REF (VOIDmode, label); |
+ label_ref = gen_rtx_LABEL_REF (VOIDmode, operands[3]); |
test_rtx = gen_rtx_fmt_ee (test, cc_mode, cc_reg, const0_rtx); |
if_else = gen_rtx_IF_THEN_ELSE (cc_mode, test_rtx, label_ref, pc_rtx); |
emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, if_else)); |
@@ -4759,23 +4820,23 @@ frv_emit_cond_branch (enum rtx_code test, rtx label) |
} |
-/* Emit code to set a gpr to 1/0 based on a comparison. The comparison |
- operands were previously stored in frv_compare_op0 and frv_compare_op1. */ |
+/* Emit code to set a gpr to 1/0 based on a comparison. */ |
int |
-frv_emit_scc (enum rtx_code test, rtx target) |
+frv_emit_scc (rtx operands[]) |
{ |
rtx set; |
rtx test_rtx; |
rtx clobber; |
rtx cr_reg; |
- rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1); |
+ enum rtx_code test = GET_CODE (operands[1]); |
+ rtx cc_reg = frv_emit_comparison (test, operands[2], operands[3]); |
/* SCC instructions generate: |
(parallel [(set <target> (<test>, <cc_reg>, (const_int 0)) |
(clobber (<ccr_reg>))]) */ |
test_rtx = gen_rtx_fmt_ee (test, SImode, cc_reg, const0_rtx); |
- set = gen_rtx_SET (VOIDmode, target, test_rtx); |
+ set = gen_rtx_SET (VOIDmode, operands[0], test_rtx); |
cr_reg = ((TARGET_ALLOC_CC) |
? gen_reg_rtx (CC_CCRmode) |
@@ -4837,7 +4898,8 @@ frv_emit_cond_move (rtx dest, rtx test_rtx, rtx src1, rtx src2) |
rtx cr_reg; |
rtx if_rtx; |
enum rtx_code test = GET_CODE (test_rtx); |
- rtx cc_reg = frv_emit_comparison (test, frv_compare_op0, frv_compare_op1); |
+ rtx cc_reg = frv_emit_comparison (test, |
+ XEXP (test_rtx, 0), XEXP (test_rtx, 1)); |
enum machine_mode cc_mode = GET_MODE (cc_reg); |
/* Conditional move instructions generate: |
@@ -5814,7 +5876,7 @@ frv_ifcvt_rewrite_mem (rtx mem, enum machine_mode mode, rtx insn) |
{ |
rtx addr = XEXP (mem, 0); |
- if (!frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE)) |
+ if (!frv_legitimate_address_p_1 (mode, addr, reload_completed, TRUE, FALSE)) |
{ |
if (GET_CODE (addr) == PLUS) |
{ |
@@ -6280,9 +6342,11 @@ frv_trampoline_size (void) |
sethi #0, <static_chain> |
jmpl @(gr0,<jmp_reg>) */ |
-void |
-frv_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain) |
+static void |
+frv_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain) |
{ |
+ rtx addr = XEXP (m_tramp, 0); |
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); |
rtx sc_reg = force_reg (Pmode, static_chain); |
emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"), |