Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Unified Diff: gcc/gcc/config/iq2000/iq2000.c

Issue 3050029: [gcc] GCC 4.5.0=>4.5.1 (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/nacl-toolchain.git
Patch Set: Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gcc/gcc/config/iq2000/iq2000.h ('k') | gcc/gcc/config/iq2000/iq2000-protos.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gcc/gcc/config/iq2000/iq2000.c
diff --git a/gcc/gcc/config/iq2000/iq2000.c b/gcc/gcc/config/iq2000/iq2000.c
index 71533894551f7915aa090d733f71c229e5b752ad..4359f5edfb93cb135dd0120e5f946b1d76d1684b 100644
--- a/gcc/gcc/config/iq2000/iq2000.c
+++ b/gcc/gcc/config/iq2000/iq2000.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation on Vitesse IQ2000 processors
- Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
@@ -89,7 +89,7 @@ struct iq2000_frame_info
int num_gp; /* Number of gp registers saved. */
} iq2000_frame_info;
-struct machine_function GTY(())
+struct GTY(()) machine_function
{
/* Current frame information, calculated by compute_frame_size. */
long total_size; /* # bytes that the entire frame takes up. */
@@ -118,13 +118,6 @@ enum processor_type iq2000_tune;
/* Which instruction set architecture to use. */
int iq2000_isa;
-/* Cached operands, and operator to compare for use in set/branch/trap
- on condition codes. */
-rtx branch_cmp[2];
-
-/* What type of branch to use. */
-enum cmp_type branch_type;
-
/* Local variables. */
/* The next branch instruction is a branch likely, not branch normal. */
@@ -165,11 +158,18 @@ static void iq2000_setup_incoming_varargs (CUMULATIVE_ARGS *,
static bool iq2000_rtx_costs (rtx, int, int, int *, bool);
static int iq2000_address_cost (rtx, bool);
static section *iq2000_select_section (tree, int, unsigned HOST_WIDE_INT);
+static rtx iq2000_legitimize_address (rtx, rtx, enum machine_mode);
static bool iq2000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
const_tree, bool);
static int iq2000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
static void iq2000_va_start (tree, rtx);
+static bool iq2000_legitimate_address_p (enum machine_mode, rtx, bool);
+static bool iq2000_can_eliminate (const int, const int);
+static void iq2000_asm_trampoline_template (FILE *);
+static void iq2000_trampoline_init (rtx, tree, rtx);
+static rtx iq2000_function_value (const_tree, const_tree, bool);
+static rtx iq2000_libcall_value (enum machine_mode, const_rtx);
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS iq2000_init_builtins
@@ -186,18 +186,23 @@ static void iq2000_va_start (tree, rtx);
#undef TARGET_ASM_SELECT_SECTION
#define TARGET_ASM_SELECT_SECTION iq2000_select_section
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS iq2000_legitimize_address
+
/* The assembler supports switchable .bss sections, but
iq2000_select_section doesn't yet make use of them. */
#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
-#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE iq2000_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE iq2000_libcall_value
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY iq2000_return_in_memory
#undef TARGET_PASS_BY_REFERENCE
@@ -215,6 +220,17 @@ static void iq2000_va_start (tree, rtx);
#undef TARGET_EXPAND_BUILTIN_VA_START
#define TARGET_EXPAND_BUILTIN_VA_START iq2000_va_start
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P iq2000_legitimate_address_p
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE iq2000_can_eliminate
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE iq2000_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT iq2000_trampoline_init
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Return nonzero if we split the address into high and low parts. */
@@ -252,12 +268,12 @@ iq2000_reg_mode_ok_for_base_p (rtx reg,
memory operand of the indicated MODE. STRICT is nonzero if this
function is called during reload. */
-int
-iq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict)
+bool
+iq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, bool strict)
{
if (TARGET_DEBUG_A_MODE)
{
- GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n",
+ GO_PRINTF2 ("\n========== legitimate_address_p, %sstrict\n",
strict ? "" : "not ");
GO_DEBUG_RTX (xinsn);
}
@@ -314,7 +330,7 @@ iq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict)
}
if (TARGET_DEBUG_A_MODE)
- GO_PRINTF ("Not a legitimate address\n");
+ GO_PRINTF ("Not a enum machine_mode mode, legitimate address\n");
/* The address was not legitimate. */
return 0;
@@ -1006,60 +1022,31 @@ gen_int_relational (enum rtx_code test_code, rtx result, rtx cmp0, rtx cmp1,
The comparison operands are saved away by cmp{si,di,sf,df}. */
void
-gen_conditional_branch (rtx operands[], enum rtx_code test_code)
+gen_conditional_branch (rtx operands[], enum machine_mode mode)
{
- enum cmp_type type = branch_type;
- rtx cmp0 = branch_cmp[0];
- rtx cmp1 = branch_cmp[1];
- enum machine_mode mode;
+ enum rtx_code test_code = GET_CODE (operands[0]);
+ rtx cmp0 = operands[1];
+ rtx cmp1 = operands[2];
rtx reg;
int invert;
rtx label1, label2;
- switch (type)
- {
- case CMP_SI:
- case CMP_DI:
- mode = type == CMP_SI ? SImode : DImode;
- invert = 0;
- reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert);
-
- if (reg)
- {
- cmp0 = reg;
- cmp1 = const0_rtx;
- test_code = NE;
- }
- else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
- /* We don't want to build a comparison against a nonzero
- constant. */
- cmp1 = force_reg (mode, cmp1);
-
- break;
-
- case CMP_SF:
- case CMP_DF:
- reg = gen_reg_rtx (CCmode);
-
- /* For cmp0 != cmp1, build cmp0 == cmp1, and test for result == 0. */
- emit_insn (gen_rtx_SET (VOIDmode, reg,
- gen_rtx_fmt_ee (test_code == NE ? EQ : test_code,
- CCmode, cmp0, cmp1)));
+ invert = 0;
+ reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert);
- test_code = test_code == NE ? EQ : NE;
- mode = CCmode;
+ if (reg)
+ {
cmp0 = reg;
cmp1 = const0_rtx;
- invert = 0;
- break;
-
- default:
- abort_with_insn (gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1),
- "bad test");
+ test_code = NE;
}
+ else if (GET_CODE (cmp1) == CONST_INT && INTVAL (cmp1) != 0)
+ /* We don't want to build a comparison against a nonzero
+ constant. */
+ cmp1 = force_reg (mode, cmp1);
/* Generate the branch. */
- label1 = gen_rtx_LABEL_REF (VOIDmode, operands[0]);
+ label1 = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
label2 = pc_rtx;
if (invert)
@@ -1175,6 +1162,11 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
cum->arg_words += 2;
break;
+ case TImode:
+ cum->gp_reg_found = 1;
+ cum->arg_words += 4;
+ break;
+
case QImode:
case HImode:
case SImode:
@@ -1245,6 +1237,12 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, const_tree type,
case DImode:
cum->arg_words += (cum->arg_words & 1);
regbase = GP_ARG_FIRST;
+ break;
+
+ case TImode:
+ cum->arg_words += (cum->arg_words & 3);
+ regbase = GP_ARG_FIRST;
+ break;
}
if (*arg_words >= (unsigned) MAX_ARGS_IN_REGISTERS)
@@ -1697,6 +1695,22 @@ compute_frame_size (HOST_WIDE_INT size)
return total_size;
}
+
+/* We can always eliminate to the frame pointer. We can eliminate to the
+ stack pointer unless a frame pointer is needed. */
+
+bool
+iq2000_can_eliminate (const int from, const int to)
+{
+ return (from == RETURN_ADDRESS_POINTER_REGNUM
+ && (! leaf_function_p ()
+ || (to == GP_REG_FIRST + 31 && leaf_function_p)))
+ || (from != RETURN_ADDRESS_POINTER_REGNUM
+ && (to == HARD_FRAME_POINTER_REGNUM
+ || (to == STACK_POINTER_REGNUM
+ && ! frame_pointer_needed)));
+}
+
/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
pointer, argument pointer, or return address pointer. TO is either
the stack pointer or hard frame pointer. */
@@ -1877,7 +1891,8 @@ iq2000_expand_prologue (void)
&& targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)
{
tree type = build_pointer_type (fntype);
- tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);
+ tree function_result_decl = build_decl (BUILTINS_LOCATION,
+ PARM_DECL, NULL_TREE, type);
DECL_ARG_TYPE (function_result_decl) = type;
TREE_CHAIN (function_result_decl) = fnargs;
@@ -2201,19 +2216,47 @@ iq2000_select_section (tree decl, int reloc ATTRIBUTE_UNUSED,
/* Return register to use for a function return value with VALTYPE for function
FUNC. */
-rtx
-iq2000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
+static rtx
+iq2000_function_value (const_tree valtype,
+ const_tree fn_decl_or_type,
+ bool outgoing ATTRIBUTE_UNUSED)
{
int reg = GP_RETURN;
enum machine_mode mode = TYPE_MODE (valtype);
int unsignedp = TYPE_UNSIGNED (valtype);
+ tree func = fn_decl_or_type;
+
+ if (fn_decl_or_type
+ && !DECL_P (fn_decl_or_type))
+ fn_decl_or_type = NULL;
- /* Since we define TARGET_PROMOTE_FUNCTION_RETURN that returns true,
- we must promote the mode just as PROMOTE_MODE does. */
- mode = promote_mode (valtype, mode, &unsignedp, 1);
+ /* Since we promote return types, we must promote the mode here too. */
+ mode = promote_function_mode (valtype, mode, &unsignedp, func, 1);
return gen_rtx_REG (mode, reg);
}
+
+/* Worker function for TARGET_LIBCALL_VALUE. */
+
+static rtx
+iq2000_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (((GET_MODE_CLASS (mode) != MODE_INT
+ || GET_MODE_SIZE (mode) >= 4)
+ ? mode : SImode),
+ GP_RETURN);
+}
+
+/* Worker function for FUNCTION_VALUE_REGNO_P.
+
+ On the IQ2000, R2 and R3 are the only register thus used. */
+
+bool
+iq2000_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == GP_RETURN);
+}
+
/* Return true when an argument must be passed by reference. */
@@ -3203,6 +3246,73 @@ print_operand (FILE *file, rtx op, int letter)
output_addr_const (file, op);
}
+
+/* For the IQ2000, transform:
+
+ memory(X + <large int>)
+ into:
+ Y = <large int> & ~0x7fff;
+ Z = X + Y
+ memory (Z + (<large int> & 0x7fff));
+*/
+
+rtx
+iq2000_legitimize_address (rtx xinsn, rtx old_x ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ if (TARGET_DEBUG_B_MODE)
+ {
+ GO_PRINTF ("\n========== LEGITIMIZE_ADDRESS\n");
+ GO_DEBUG_RTX (xinsn);
+ }
+
+ if (iq2000_check_split (xinsn, mode))
+ {
+ return gen_rtx_LO_SUM (Pmode,
+ copy_to_mode_reg (Pmode,
+ gen_rtx_HIGH (Pmode, xinsn)),
+ xinsn);
+ }
+
+ if (GET_CODE (xinsn) == PLUS)
+ {
+ rtx xplus0 = XEXP (xinsn, 0);
+ rtx xplus1 = XEXP (xinsn, 1);
+ enum rtx_code code0 = GET_CODE (xplus0);
+ enum rtx_code code1 = GET_CODE (xplus1);
+
+ if (code0 != REG && code1 == REG)
+ {
+ xplus0 = XEXP (xinsn, 1);
+ xplus1 = XEXP (xinsn, 0);
+ code0 = GET_CODE (xplus0);
+ code1 = GET_CODE (xplus1);
+ }
+
+ if (code0 == REG && REG_MODE_OK_FOR_BASE_P (xplus0, mode)
+ && code1 == CONST_INT && !SMALL_INT (xplus1))
+ {
+ rtx int_reg = gen_reg_rtx (Pmode);
+ rtx ptr_reg = gen_reg_rtx (Pmode);
+
+ emit_move_insn (int_reg,
+ GEN_INT (INTVAL (xplus1) & ~ 0x7fff));
+
+ emit_insn (gen_rtx_SET (VOIDmode,
+ ptr_reg,
+ gen_rtx_PLUS (Pmode, xplus0, int_reg)));
+
+ return plus_constant (ptr_reg, INTVAL (xplus1) & 0x7fff);
+ }
+ }
+
+ if (TARGET_DEBUG_B_MODE)
+ GO_PRINTF ("LEGITIMIZE_ADDRESS could not fix.\n");
+
+ return xinsn;
+}
+
+
static bool
iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total,
bool speed ATTRIBUTE_UNUSED)
@@ -3342,4 +3452,47 @@ iq2000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total,
return true;
}
+/* Worker for TARGET_ASM_TRAMPOLINE_TEMPLATE. */
+
+static void
+iq2000_asm_trampoline_template (FILE *f)
+{
+ fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
+ fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
+ fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
+ if (Pmode == DImode)
+ {
+ fprintf (f, "\t.word\t0xdfe30014\t\t# ld $3,20($31)\n");
+ fprintf (f, "\t.word\t0xdfe2001c\t\t# ld $2,28($31)\n");
+ }
+ else
+ {
+ fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
+ fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
+ }
+ fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
+ fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
+ fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
+ fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n");
+ fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n");
+}
+
+/* Worker for TARGET_TRAMPOLINE_INIT. */
+
+static void
+iq2000_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx mem;
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (TRAMPOLINE_CODE_SIZE), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, Pmode, TRAMPOLINE_CODE_SIZE);
+ emit_move_insn (mem, fnaddr);
+ mem = adjust_address (m_tramp, Pmode,
+ TRAMPOLINE_CODE_SIZE + GET_MODE_SIZE (Pmode));
+ emit_move_insn (mem, chain_value);
+}
+
#include "gt-iq2000.h"
« no previous file with comments | « gcc/gcc/config/iq2000/iq2000.h ('k') | gcc/gcc/config/iq2000/iq2000-protos.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698