📄 iq2000.c
字号:
/* Subroutines used for code generation on Vitesse IQ2000 processors Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.This file is part of GCC.GCC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GCC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING. If not, write tothe Free Software Foundation, 51 Franklin Street, Fifth Floor,Boston, MA 02110-1301, USA. */#include "config.h"#include "system.h"#include "coretypes.h"#include <signal.h>#include "tm.h"#include "tree.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "function.h"#include "expr.h"#include "optabs.h"#include "libfuncs.h"#include "recog.h"#include "toplev.h"#include "reload.h"#include "ggc.h"#include "tm_p.h"#include "debug.h"#include "target.h"#include "target-def.h"#include "langhooks.h"/* Enumeration for all of the relational tests, so that we can build arrays indexed by the test type, and not worry about the order of EQ, NE, etc. */enum internal_test { ITEST_EQ, ITEST_NE, ITEST_GT, ITEST_GE, ITEST_LT, ITEST_LE, ITEST_GTU, ITEST_GEU, ITEST_LTU, ITEST_LEU, ITEST_MAX };struct constant;/* Structure to be filled in by compute_frame_size with register save masks, and offsets for the current function. */struct iq2000_frame_info{ long total_size; /* # bytes that the entire frame takes up. */ long var_size; /* # bytes that variables take up. */ long args_size; /* # bytes that outgoing arguments take up. */ long extra_size; /* # bytes of extra gunk. */ int gp_reg_size; /* # bytes needed to store gp regs. */ int fp_reg_size; /* # bytes needed to store fp regs. */ long mask; /* Mask of saved gp registers. */ long gp_save_offset; /* Offset from vfp to store gp registers. */ long fp_save_offset; /* Offset from vfp to store fp registers. */ long gp_sp_offset; /* Offset from new sp to store gp registers. */ long fp_sp_offset; /* Offset from new sp to store fp registers. */ int initialized; /* != 0 if frame size already calculated. */ int num_gp; /* Number of gp registers saved. */} iq2000_frame_info;struct machine_function GTY(()){ /* Current frame information, calculated by compute_frame_size. */ long total_size; /* # bytes that the entire frame takes up. */ long var_size; /* # bytes that variables take up. */ long args_size; /* # bytes that outgoing arguments take up. */ long extra_size; /* # bytes of extra gunk. */ int gp_reg_size; /* # bytes needed to store gp regs. */ int fp_reg_size; /* # bytes needed to store fp regs. */ long mask; /* Mask of saved gp registers. */ long gp_save_offset; /* Offset from vfp to store gp registers. */ long fp_save_offset; /* Offset from vfp to store fp registers. */ long gp_sp_offset; /* Offset from new sp to store gp registers. */ long fp_sp_offset; /* Offset from new sp to store fp registers. */ int initialized; /* != 0 if frame size already calculated. */ int num_gp; /* Number of gp registers saved. */};/* Global variables for machine-dependent things. *//* List of all IQ2000 punctuation characters used by print_operand. */char iq2000_print_operand_punct[256];/* The target cpu for optimization and scheduling. */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. */static int iq2000_branch_likely;/* Count of delay slots and how many are filled. */static int dslots_load_total;static int dslots_load_filled;static int dslots_jump_total;/* # of nops needed by previous insn. */static int dslots_number_nops;/* Number of 1/2/3 word references to data items (i.e., not jal's). */static int num_refs[3];/* Registers to check for load delay. */static rtx iq2000_load_reg;static rtx iq2000_load_reg2;static rtx iq2000_load_reg3;static rtx iq2000_load_reg4;/* Mode used for saving/restoring general purpose registers. */static enum machine_mode gpr_mode;/* Initialize the GCC target structure. */static struct machine_function* iq2000_init_machine_status (void);static bool iq2000_handle_option (size_t, const char *, int);static void iq2000_select_rtx_section (enum machine_mode, rtx, unsigned HOST_WIDE_INT);static void iq2000_init_builtins (void);static rtx iq2000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);static bool iq2000_return_in_memory (tree, tree);static void iq2000_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);static bool iq2000_rtx_costs (rtx, int, int, int *);static int iq2000_address_cost (rtx);static void iq2000_select_section (tree, int, unsigned HOST_WIDE_INT);static bool iq2000_return_in_memory (tree, tree);static bool iq2000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);static int iq2000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);#undef TARGET_INIT_BUILTINS#define TARGET_INIT_BUILTINS iq2000_init_builtins#undef TARGET_EXPAND_BUILTIN#define TARGET_EXPAND_BUILTIN iq2000_expand_builtin#undef TARGET_ASM_SELECT_RTX_SECTION#define TARGET_ASM_SELECT_RTX_SECTION iq2000_select_rtx_section#undef TARGET_HANDLE_OPTION#define TARGET_HANDLE_OPTION iq2000_handle_option#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS iq2000_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST iq2000_address_cost#undef TARGET_ASM_SELECT_SECTION#define TARGET_ASM_SELECT_SECTION iq2000_select_section#undef TARGET_PROMOTE_FUNCTION_ARGS#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true#undef TARGET_PROMOTE_FUNCTION_RETURN#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true#undef TARGET_PROMOTE_PROTOTYPES#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY iq2000_return_in_memory#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE iq2000_pass_by_reference#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES hook_callee_copies_named#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES iq2000_arg_partial_bytes#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS iq2000_setup_incoming_varargs#undef TARGET_STRICT_ARGUMENT_NAMING#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_truestruct gcc_target targetm = TARGET_INITIALIZER;/* Return nonzero if we split the address into high and low parts. */intiq2000_check_split (rtx address, enum machine_mode mode){ /* This is the same check used in simple_memory_operand. We use it here because LO_SUM is not offsettable. */ if (GET_MODE_SIZE (mode) > (unsigned) UNITS_PER_WORD) return 0; if ((GET_CODE (address) == SYMBOL_REF) || (GET_CODE (address) == CONST && GET_CODE (XEXP (XEXP (address, 0), 0)) == SYMBOL_REF) || GET_CODE (address) == LABEL_REF) return 1; return 0;}/* Return nonzero if REG is valid for MODE. */intiq2000_reg_mode_ok_for_base_p (rtx reg, enum machine_mode mode ATTRIBUTE_UNUSED, int strict){ return (strict ? REGNO_MODE_OK_FOR_BASE_P (REGNO (reg), mode) : GP_REG_OR_PSEUDO_NONSTRICT_P (REGNO (reg), mode));}/* Return a nonzero value if XINSN is a legitimate address for a memory operand of the indicated MODE. STRICT is nonzero if this function is called during reload. */intiq2000_legitimate_address_p (enum machine_mode mode, rtx xinsn, int strict){ if (TARGET_DEBUG_A_MODE) { GO_PRINTF2 ("\n========== GO_IF_LEGITIMATE_ADDRESS, %sstrict\n", strict ? "" : "not "); GO_DEBUG_RTX (xinsn); } /* Check for constant before stripping off SUBREG, so that we don't accept (subreg (const_int)) which will fail to reload. */ if (CONSTANT_ADDRESS_P (xinsn) && ! (iq2000_check_split (xinsn, mode)) && ! (GET_CODE (xinsn) == CONST_INT && ! SMALL_INT (xinsn))) return 1; while (GET_CODE (xinsn) == SUBREG) xinsn = SUBREG_REG (xinsn); if (GET_CODE (xinsn) == REG && iq2000_reg_mode_ok_for_base_p (xinsn, mode, strict)) return 1; if (GET_CODE (xinsn) == LO_SUM) { rtx xlow0 = XEXP (xinsn, 0); rtx xlow1 = XEXP (xinsn, 1); while (GET_CODE (xlow0) == SUBREG) xlow0 = SUBREG_REG (xlow0); if (GET_CODE (xlow0) == REG && iq2000_reg_mode_ok_for_base_p (xlow0, mode, strict) && iq2000_check_split (xlow1, mode)) return 1; } if (GET_CODE (xinsn) == PLUS) { rtx xplus0 = XEXP (xinsn, 0); rtx xplus1 = XEXP (xinsn, 1); enum rtx_code code0; enum rtx_code code1; while (GET_CODE (xplus0) == SUBREG) xplus0 = SUBREG_REG (xplus0); code0 = GET_CODE (xplus0); while (GET_CODE (xplus1) == SUBREG) xplus1 = SUBREG_REG (xplus1); code1 = GET_CODE (xplus1); if (code0 == REG && iq2000_reg_mode_ok_for_base_p (xplus0, mode, strict)) { if (code1 == CONST_INT && SMALL_INT (xplus1) && SMALL_INT_UNSIGNED (xplus1) /* No negative offsets */) return 1; } } if (TARGET_DEBUG_A_MODE) GO_PRINTF ("Not a legitimate address\n"); /* The address was not legitimate. */ return 0;}/* Returns an operand string for the given instruction's delay slot, after updating filled delay slot statistics. We assume that operands[0] is the target register that is set. In order to check the next insn, most of this functionality is moved to FINAL_PRESCAN_INSN, and we just set the global variables that it needs. */const char *iq2000_fill_delay_slot (const char *ret, enum delay_type type, rtx operands[], rtx cur_insn){ rtx set_reg; enum machine_mode mode; rtx next_insn = cur_insn ? NEXT_INSN (cur_insn) : NULL_RTX; int num_nops; if (type == DELAY_LOAD || type == DELAY_FCMP) num_nops = 1; else num_nops = 0; /* Make sure that we don't put nop's after labels. */ next_insn = NEXT_INSN (cur_insn); while (next_insn != 0 && (GET_CODE (next_insn) == NOTE || GET_CODE (next_insn) == CODE_LABEL)) next_insn = NEXT_INSN (next_insn); dslots_load_total += num_nops; if (TARGET_DEBUG_C_MODE || type == DELAY_NONE || operands == 0 || cur_insn == 0 || next_insn == 0 || GET_CODE (next_insn) == CODE_LABEL || (set_reg = operands[0]) == 0) { dslots_number_nops = 0; iq2000_load_reg = 0; iq2000_load_reg2 = 0; iq2000_load_reg3 = 0; iq2000_load_reg4 = 0; return ret; } set_reg = operands[0]; if (set_reg == 0) return ret; while (GET_CODE (set_reg) == SUBREG) set_reg = SUBREG_REG (set_reg); mode = GET_MODE (set_reg); dslots_number_nops = num_nops; iq2000_load_reg = set_reg; if (GET_MODE_SIZE (mode) > (unsigned) (UNITS_PER_WORD)) iq2000_load_reg2 = gen_rtx_REG (SImode, REGNO (set_reg) + 1); else iq2000_load_reg2 = 0; return ret;}/* Determine whether a memory reference takes one (based off of the GP pointer), two (normal), or three (label + reg) instructions, and bump the appropriate counter for -mstats. */static voidiq2000_count_memory_refs (rtx op, int num){ int additional = 0; int n_words = 0; rtx addr, plus0, plus1; enum rtx_code code0, code1; int looping; if (TARGET_DEBUG_B_MODE) { fprintf (stderr, "\n========== iq2000_count_memory_refs:\n"); debug_rtx (op); } /* Skip MEM if passed, otherwise handle movsi of address. */ addr = (GET_CODE (op) != MEM) ? op : XEXP (op, 0); /* Loop, going through the address RTL. */ do { looping = FALSE; switch (GET_CODE (addr)) { case REG: case CONST_INT: case LO_SUM: break; case PLUS: plus0 = XEXP (addr, 0); plus1 = XEXP (addr, 1); code0 = GET_CODE (plus0); code1 = GET_CODE (plus1); if (code0 == REG) { additional++; addr = plus1; looping = 1; continue; } if (code0 == CONST_INT) { addr = plus1; looping = 1; continue; } if (code1 == REG) { additional++; addr = plus0; looping = 1; continue; } if (code1 == CONST_INT) { addr = plus0; looping = 1; continue; } if (code0 == SYMBOL_REF || code0 == LABEL_REF || code0 == CONST) { addr = plus0; looping = 1; continue; } if (code1 == SYMBOL_REF || code1 == LABEL_REF || code1 == CONST) { addr = plus1; looping = 1; continue; } break; case LABEL_REF: n_words = 2; /* Always 2 words. */ break; case CONST: addr = XEXP (addr, 0); looping = 1; continue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -