Mercurial > hg > CbC > CbC_gcc
diff gcc/config/iq2000/iq2000.c @ 55:77e2b8dfacca gcc-4.4.5
update it from 4.4.3 to 4.5.0
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 12 Feb 2010 23:39:51 +0900 |
parents | a06113de4d67 |
children | b7f97abdc517 |
line wrap: on
line diff
--- a/gcc/config/iq2000/iq2000.c Sun Feb 07 18:28:00 2010 +0900 +++ b/gcc/config/iq2000/iq2000.c Fri Feb 12 23:39:51 2010 +0900 @@ -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 @@ 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 @@ /* 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 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 @@ #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 @@ #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 @@ 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 @@ } 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 @@ 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) + invert = 0; + reg = gen_int_relational (test_code, NULL_RTX, cmp0, cmp1, &invert); + + if (reg) { - 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))); - - test_code = test_code == NE ? EQ : NE; - mode = CCmode; 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 @@ 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 @@ 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 @@ 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 @@ && 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 @@ /* 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); - - /* 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); + tree func = fn_decl_or_type; + + if (fn_decl_or_type + && !DECL_P (fn_decl_or_type)) + fn_decl_or_type = NULL; + + /* 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 @@ 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 @@ 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"