📄 iq2000.c
字号:
/* Subroutines used for code generation on Vitesse IQ2000 processors Copyright (C) 2003, 2004 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, 59 Temple Place - Suite 330,Boston, MA 02111-1307, 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;/* Strings to hold which cpu and instruction set architecture to use. */const char * iq2000_cpu_string; /* For -mcpu=<xxx>. */const char * iq2000_arch_string; /* For -march=<xxx>. *//* 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;/* The target cpu for code generation. */static enum processor_type iq2000_arch;/* 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 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_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 1 if OP can be used as an operand where a register or 16 bit unsigned integer is needed. */intuns_arith_operand (rtx op, enum machine_mode mode){ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (op)) return 1; return register_operand (op, mode);}/* Return 1 if OP can be used as an operand where a 16 bit integer is needed. */intarith_operand (rtx op, enum machine_mode mode){ if (GET_CODE (op) == CONST_INT && SMALL_INT (op)) return 1; return register_operand (op, mode);}/* Return 1 if OP is a integer which fits in 16 bits. */intsmall_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return 1 if OP is a 32 bit integer which is too big to be loaded with one instruction. */intlarge_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ HOST_WIDE_INT value; if (GET_CODE (op) != CONST_INT) return 0; value = INTVAL (op); /* IOR reg,$r0,value. */ if ((value & ~ ((HOST_WIDE_INT) 0x0000ffff)) == 0) return 0; /* SUBU reg,$r0,value. */ if (((unsigned HOST_WIDE_INT) (value + 32768)) <= 32767) return 0; /* LUI reg,value >> 16. */ if ((value & 0x0000ffff) == 0) return 0; return 1;}/* Return 1 if OP is a register or the constant 0. */intreg_or_0_operand (rtx op, enum machine_mode mode){ switch (GET_CODE (op)) { case CONST_INT: return INTVAL (op) == 0; case CONST_DOUBLE: return op == CONST0_RTX (mode); case REG: case SUBREG: return register_operand (op, mode); default: break; } return 0;}/* Return 1 if OP is a memory operand that fits in a single instruction (i.e., register + small offset). */intsimple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ rtx addr, plus0, plus1; /* Eliminate non-memory operations. */ if (GET_CODE (op) != MEM) return 0; /* Dword operations really put out 2 instructions, so eliminate them. */ if (GET_MODE_SIZE (GET_MODE (op)) > (unsigned) UNITS_PER_WORD) return 0; /* Decode the address now. */ addr = XEXP (op, 0); switch (GET_CODE (addr)) { case REG: case LO_SUM: return 1; case CONST_INT: return SMALL_INT (addr); case PLUS: plus0 = XEXP (addr, 0); plus1 = XEXP (addr, 1); if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT && SMALL_INT (plus1) && SMALL_INT_UNSIGNED (plus1) /* No negative offsets. */) return 1; else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT && SMALL_INT (plus0) && SMALL_INT_UNSIGNED (plus1) /* No negative offsets. */) return 1; else return 0; case SYMBOL_REF: return 0; default: break; } return 0;}/* Return nonzero if the code of this rtx pattern is EQ or NE. */intequality_op (rtx op, enum machine_mode mode){ if (mode != GET_MODE (op)) return 0; return GET_CODE (op) == EQ || GET_CODE (op) == NE;}/* Return nonzero if the code is a relational operations (EQ, LE, etc). */intcmp_op (rtx op, enum machine_mode mode){ if (mode != GET_MODE (op)) return 0; return COMPARISON_P (op);}/* Return nonzero if the operand is either the PC or a label_ref. */intpc_or_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ if (op == pc_rtx) return 1; if (GET_CODE (op) == LABEL_REF) return 1; return 0;}/* Return nonzero if OP is a valid operand for a call instruction. */intcall_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ return (CONSTANT_ADDRESS_P (op) || (GET_CODE (op) == REG && op != arg_pointer_rtx && ! (REGNO (op) >= FIRST_PSEUDO_REGISTER && REGNO (op) <= LAST_VIRTUAL_REGISTER)));}/* Return nonzero if OP is valid as a source operand for a move instruction. */intmove_operand (rtx op, enum machine_mode mode){ /* Accept any general operand after reload has started; doing so avoids losing if reload does an in-place replacement of a register with a SYMBOL_REF or CONST. */ return (general_operand (op, mode) && (! (iq2000_check_split (op, mode)) || reload_in_progress || reload_completed));}/* Return nonzero if OP is a constant power of 2. */intpower_of_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ int intval; if (GET_CODE (op) != CONST_INT) return 0; else intval = INTVAL (op); return ((intval & ((unsigned)(intval) - 1)) == 0);}/* 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -