cris.c
来自「linux下编程用 编译软件」· C语言 代码 · 共 2,298 行 · 第 1/5 页
C
2,298 行
/* Definitions for GCC. Part of the machine description for CRIS. Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by Axis Communications. Written by Hans-Peter Nilsson.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 "tm.h"#include "rtl.h"#include "regs.h"#include "hard-reg-set.h"#include "real.h"#include "insn-config.h"#include "conditions.h"#include "insn-attr.h"#include "flags.h"#include "tree.h"#include "expr.h"#include "except.h"#include "function.h"#include "toplev.h"#include "recog.h"#include "reload.h"#include "tm_p.h"#include "debug.h"#include "output.h"#include "target.h"#include "target-def.h"#include "ggc.h"#include "optabs.h"/* Usable when we have an amount to add or subtract, and want the optimal size of the insn. */#define ADDITIVE_SIZE_MODIFIER(size) \ ((size) <= 63 ? "q" : (size) <= 255 ? "u.b" : (size) <= 65535 ? "u.w" : ".d")#define ASSERT_PLT_UNSPEC(x) \ CRIS_ASSERT (XINT (x, 1) == CRIS_UNSPEC_PLT \ && ((GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF) \ || GET_CODE (XVECEXP (x, 0, 0)) == LABEL_REF))#define LOSE_AND_RETURN(msgid, x) \ do \ { \ cris_operand_lossage (msgid, x); \ return; \ } while (0)enum cris_retinsn_type { CRIS_RETINSN_UNKNOWN = 0, CRIS_RETINSN_RET, CRIS_RETINSN_JUMP };/* Per-function machine data. */struct machine_function GTY(()) { int needs_return_address_on_stack; /* This is the number of registers we save in the prologue due to stdarg. */ int stdarg_regs; enum cris_retinsn_type return_type; };/* This little fix suppresses the 'u' or 's' when '%e' in assembly pattern. */static char cris_output_insn_is_bound = 0;/* In code for output macros, this is how we know whether e.g. constant goes in code or in a static initializer. */static int in_code = 0;/* Fix for reg_overlap_mentioned_p. */static int cris_reg_overlap_mentioned_p (rtx, rtx);static void cris_print_base (rtx, FILE *);static void cris_print_index (rtx, FILE *);static void cris_output_addr_const (FILE *, rtx);static struct machine_function * cris_init_machine_status (void);static rtx cris_struct_value_rtx (tree, int);static void cris_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree type, int *, int);static int cris_initial_frame_pointer_offset (void);static int saved_regs_mentioned (rtx);static void cris_operand_lossage (const char *, rtx);static int cris_reg_saved_in_regsave_area (unsigned int, bool);static void cris_asm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);static void cris_file_start (void);static void cris_init_libfuncs (void);static bool cris_rtx_costs (rtx, int, int, int *);static int cris_address_cost (rtx);static bool cris_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);static int cris_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);static tree cris_md_asm_clobbers (tree, tree, tree);static bool cris_handle_option (size_t, const char *, int);/* This is the parsed result of the "-max-stack-stackframe=" option. If it (still) is zero, then there was no such option given. */int cris_max_stackframe = 0;/* This is the parsed result of the "-march=" option, if given. */int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.dword\t"#undef TARGET_ASM_ALIGNED_DI_OP#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"/* We need to define these, since the 2byte, 4byte, 8byte op:s are only available in ELF. These "normal" pseudos do not have any alignment constraints or side-effects. */#undef TARGET_ASM_UNALIGNED_HI_OP#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP#undef TARGET_ASM_UNALIGNED_SI_OP#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP#undef TARGET_ASM_UNALIGNED_DI_OP#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP#undef TARGET_ASM_OUTPUT_MI_THUNK#define TARGET_ASM_OUTPUT_MI_THUNK cris_asm_output_mi_thunk#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall#undef TARGET_ASM_FILE_START#define TARGET_ASM_FILE_START cris_file_start#undef TARGET_INIT_LIBFUNCS#define TARGET_INIT_LIBFUNCS cris_init_libfuncs#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS cris_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST cris_address_cost#undef TARGET_PROMOTE_FUNCTION_ARGS#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true#undef TARGET_STRUCT_VALUE_RTX#define TARGET_STRUCT_VALUE_RTX cris_struct_value_rtx#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS cris_setup_incoming_varargs#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE cris_pass_by_reference#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES cris_arg_partial_bytes#undef TARGET_MD_ASM_CLOBBERS#define TARGET_MD_ASM_CLOBBERS cris_md_asm_clobbers#undef TARGET_DEFAULT_TARGET_FLAGS#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | CRIS_SUBTARGET_DEFAULT)#undef TARGET_HANDLE_OPTION#define TARGET_HANDLE_OPTION cris_handle_optionstruct gcc_target targetm = TARGET_INITIALIZER;/* Helper for cris_load_multiple_op and cris_ret_movem_op. */boolcris_movem_load_rest_p (rtx op, int offs){ unsigned int reg_count = XVECLEN (op, 0) - offs; rtx src_addr; int i; rtx elt; int setno; int regno_dir = 1; unsigned int regno = 0; /* Perform a quick check so we don't blow up below. FIXME: Adjust for other than (MEM reg). */ if (reg_count <= 1 || GET_CODE (XVECEXP (op, 0, offs)) != SET || GET_CODE (SET_DEST (XVECEXP (op, 0, offs))) != REG || GET_CODE (SET_SRC (XVECEXP (op, 0, offs))) != MEM) return false; /* Check a possible post-inc indicator. */ if (GET_CODE (SET_SRC (XVECEXP (op, 0, offs + 1))) == PLUS) { rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, offs + 1)), 0); rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, offs + 1)), 1); reg_count--; if (reg_count == 1 || !REG_P (reg) || !REG_P (SET_DEST (XVECEXP (op, 0, offs + 1))) || REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, offs + 1))) || GET_CODE (inc) != CONST_INT || INTVAL (inc) != (HOST_WIDE_INT) reg_count * 4) return false; i = offs + 2; } else i = offs + 1; /* FIXME: These two only for pre-v32. */ regno_dir = -1; regno = reg_count - 1; elt = XVECEXP (op, 0, offs); src_addr = XEXP (SET_SRC (elt), 0); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != SImode || REGNO (SET_DEST (elt)) != regno || GET_CODE (SET_SRC (elt)) != MEM || GET_MODE (SET_SRC (elt)) != SImode || !memory_address_p (SImode, src_addr)) return false; for (setno = 1; i < XVECLEN (op, 0); setno++, i++) { rtx elt = XVECEXP (op, 0, i); regno += regno_dir; if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != SImode || REGNO (SET_DEST (elt)) != regno || GET_CODE (SET_SRC (elt)) != MEM || GET_MODE (SET_SRC (elt)) != SImode || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != setno * 4) return false; } return true;}/* Worker function for predicate for the parallel contents in a movem to-memory. */boolcris_store_multiple_op_p (rtx op){ int reg_count = XVECLEN (op, 0); rtx dest; rtx dest_addr; rtx dest_base; int i; rtx elt; int setno; int regno_dir = 1; int regno = 0; int offset = 0; /* Perform a quick check so we don't blow up below. FIXME: Adjust for other than (MEM reg) and (MEM (PLUS reg const)). */ if (reg_count <= 1) return false; elt = XVECEXP (op, 0, 0); if (GET_CODE (elt) != SET) return false; dest = SET_DEST (elt); if (GET_CODE (SET_SRC (elt)) != REG || GET_CODE (dest) != MEM) return false; dest_addr = XEXP (dest, 0); /* Check a possible post-inc indicator. */ if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS) { rtx reg = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 0); rtx inc = XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1); reg_count--; if (reg_count == 1 || !REG_P (reg) || !REG_P (SET_DEST (XVECEXP (op, 0, 1))) || REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, 1))) || GET_CODE (inc) != CONST_INT /* Support increment by number of registers, and by the offset of the destination, if it has the form (MEM (PLUS reg offset)). */ || !((REG_P (dest_addr) && REGNO (dest_addr) == REGNO (reg) && INTVAL (inc) == (HOST_WIDE_INT) reg_count * 4) || (GET_CODE (dest_addr) == PLUS && REG_P (XEXP (dest_addr, 0)) && REGNO (XEXP (dest_addr, 0)) == REGNO (reg) && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT && INTVAL (XEXP (dest_addr, 1)) == INTVAL (inc)))) return false; i = 2; } else i = 1; /* FIXME: These two only for pre-v32. */ regno_dir = -1; regno = reg_count - 1; if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != SImode || REGNO (SET_SRC (elt)) != (unsigned int) regno || GET_CODE (SET_DEST (elt)) != MEM || GET_MODE (SET_DEST (elt)) != SImode) return false; if (REG_P (dest_addr)) { dest_base = dest_addr; offset = 0; } else if (GET_CODE (dest_addr) == PLUS && REG_P (XEXP (dest_addr, 0)) && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT) { dest_base = XEXP (dest_addr, 0); offset = INTVAL (XEXP (dest_addr, 1)); } else return false; for (setno = 1; i < XVECLEN (op, 0); setno++, i++) { rtx elt = XVECEXP (op, 0, i); regno += regno_dir; if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != SImode || REGNO (SET_SRC (elt)) != (unsigned int) regno || GET_CODE (SET_DEST (elt)) != MEM || GET_MODE (SET_DEST (elt)) != SImode || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_base) || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != setno * 4 + offset) return false; } return true;}/* The CONDITIONAL_REGISTER_USAGE worker. */voidcris_conditional_register_usage (void){ /* FIXME: This isn't nice. We should be able to use that register for something else if the PIC table isn't needed. */ if (flag_pic) fixed_regs[PIC_OFFSET_TABLE_REGNUM] = call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; if (TARGET_HAS_MUL_INSNS) fixed_regs[CRIS_MOF_REGNUM] = 0; /* On early versions, we must use the 16-bit condition-code register, which has another name. */ if (cris_cpu_version < 8) reg_names[CRIS_CC0_REGNUM] = "ccr";}/* Return current_function_uses_pic_offset_table. For use in cris.md, since some generated files do not include function.h. */intcris_cfun_uses_pic_table (void){ return current_function_uses_pic_offset_table;}/* Given an rtx, return the text string corresponding to the CODE of X. Intended for use in the assembly language output section of a define_insn. */const char *cris_op_str (rtx x){ cris_output_insn_is_bound = 0; switch (GET_CODE (x)) { case PLUS: return "add"; break; case MINUS: return "sub"; break; case MULT: /* This function is for retrieving a part of an instruction name for an operator, for immediate output. If that ever happens for MULT, we need to apply TARGET_MUL_BUG in the caller. Make sure we notice. */ internal_error ("MULT case in cris_op_str"); break; case DIV: return "div"; break; case AND: return "and"; break; case IOR: return "or"; break; case XOR: return "xor"; break; case NOT: return "not"; break; case ASHIFT: return "lsl"; break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?