📄 v850.c
字号:
/* Subroutines for insn-output.c for NEC V850 series Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Jeff Law (law@cygnus.com). This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the 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 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING. If not, write to the 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 "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 "recog.h"#include "expr.h"#include "function.h"#include "toplev.h"#include "ggc.h"#include "integrate.h"#include "tm_p.h"#include "target.h"#include "target-def.h"#ifndef streq#define streq(a,b) (strcmp (a, b) == 0)#endif/* Function prototypes for stupid compilers: */static bool v850_handle_option (size_t, const char *, int);static void const_double_split (rtx, HOST_WIDE_INT *, HOST_WIDE_INT *);static int const_costs_int (HOST_WIDE_INT, int);static int const_costs (rtx, enum rtx_code);static bool v850_rtx_costs (rtx, int, int, int *);static void substitute_ep_register (rtx, rtx, int, int, rtx *, rtx *);static void v850_reorg (void);static int ep_memory_offset (enum machine_mode, int);static void v850_set_data_area (tree, v850_data_area);const struct attribute_spec v850_attribute_table[];static tree v850_handle_interrupt_attribute (tree *, tree, tree, int, bool *);static tree v850_handle_data_area_attribute (tree *, tree, tree, int, bool *);static void v850_insert_attributes (tree, tree *);static void v850_select_section (tree, int, unsigned HOST_WIDE_INT);static void v850_encode_data_area (tree, rtx);static void v850_encode_section_info (tree, rtx, int);static bool v850_return_in_memory (tree, tree);static void v850_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);static bool v850_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);static int v850_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, bool);/* Information about the various small memory areas. */struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] ={ /* name max physical max */ { "tda", 0, 256 }, { "sda", 0, 65536 }, { "zda", 0, 32768 },};/* Names of the various data areas used on the v850. */tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];/* Track the current data area set by the data area pragma (which can be nested). Tested by check_default_data_area. */data_area_stack_element * data_area_stack = NULL;/* True if we don't need to check any more if the current function is an interrupt handler. */static int v850_interrupt_cache_p = FALSE;/* Whether current function is an interrupt handler. */static int v850_interrupt_p = FALSE;/* Initialize the GCC target structure. */#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE v850_attribute_table#undef TARGET_INSERT_ATTRIBUTES#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes#undef TARGET_ASM_SELECT_SECTION#define TARGET_ASM_SELECT_SECTION v850_select_section#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true#undef TARGET_DEFAULT_TARGET_FLAGS#define TARGET_DEFAULT_TARGET_FLAGS (MASK_DEFAULT | MASK_APP_REGS)#undef TARGET_HANDLE_OPTION#define TARGET_HANDLE_OPTION v850_handle_option#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS v850_rtx_costs#undef TARGET_ADDRESS_COST#define TARGET_ADDRESS_COST hook_int_rtx_0#undef TARGET_MACHINE_DEPENDENT_REORG#define TARGET_MACHINE_DEPENDENT_REORG v850_reorg#undef TARGET_PROMOTE_PROTOTYPES#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true#undef TARGET_RETURN_IN_MEMORY#define TARGET_RETURN_IN_MEMORY v850_return_in_memory#undef TARGET_PASS_BY_REFERENCE#define TARGET_PASS_BY_REFERENCE v850_pass_by_reference#undef TARGET_CALLEE_COPIES#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true#undef TARGET_SETUP_INCOMING_VARARGS#define TARGET_SETUP_INCOMING_VARARGS v850_setup_incoming_varargs#undef TARGET_ARG_PARTIAL_BYTES#define TARGET_ARG_PARTIAL_BYTES v850_arg_partial_bytesstruct gcc_target targetm = TARGET_INITIALIZER;/* Set the maximum size of small memory area TYPE to the value given by VALUE. Return true if VALUE was syntactically correct. VALUE starts with the argument separator: either "-" or "=". */static boolv850_handle_memory_option (enum small_memory_type type, const char *value){ int i, size; if (*value != '-' && *value != '=') return false; value++; for (i = 0; value[i]; i++) if (!ISDIGIT (value[i])) return false; size = atoi (value); if (size > small_memory[type].physical_max) error ("value passed to %<-m%s%> is too large", small_memory[type].name); else small_memory[type].max = size; return true;}/* Implement TARGET_HANDLE_OPTION. */static boolv850_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED){ switch (code) { case OPT_mspace: target_flags |= MASK_EP | MASK_PROLOG_FUNCTION; return true; case OPT_mv850: target_flags &= ~(MASK_CPU ^ MASK_V850); return true; case OPT_mv850e: case OPT_mv850e1: target_flags &= ~(MASK_CPU ^ MASK_V850E); return true; case OPT_mtda: return v850_handle_memory_option (SMALL_MEMORY_TDA, arg); case OPT_msda: return v850_handle_memory_option (SMALL_MEMORY_SDA, arg); case OPT_mzda: return v850_handle_memory_option (SMALL_MEMORY_ZDA, arg); default: return true; }}static boolv850_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED){ unsigned HOST_WIDE_INT size; if (type) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); return size > 8;}/* Return an RTX to represent where a value with mode MODE will be returned from a function. If the result is 0, the argument is pushed. */rtxfunction_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, int named){ rtx result = 0; int size, align; if (TARGET_GHS && !named) return NULL_RTX; if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); if (size < 1) return 0; if (type) align = TYPE_ALIGN (type) / BITS_PER_UNIT; else align = size; cum->nbytes = (cum->nbytes + align - 1) &~(align - 1); if (cum->nbytes > 4 * UNITS_PER_WORD) return 0; if (type == NULL_TREE && cum->nbytes + size > 4 * UNITS_PER_WORD) return 0; switch (cum->nbytes / UNITS_PER_WORD) { case 0: result = gen_rtx_REG (mode, 6); break; case 1: result = gen_rtx_REG (mode, 7); break; case 2: result = gen_rtx_REG (mode, 8); break; case 3: result = gen_rtx_REG (mode, 9); break; default: result = 0; } return result;}/* Return the number of bytes which must be put into registers for values which are part in registers and part in memory. */static intv850_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, bool named){ int size, align; if (TARGET_GHS && !named) return 0; if (mode == BLKmode) size = int_size_in_bytes (type); else size = GET_MODE_SIZE (mode); if (type) align = TYPE_ALIGN (type) / BITS_PER_UNIT; else align = size; cum->nbytes = (cum->nbytes + align - 1) &~(align - 1); if (cum->nbytes > 4 * UNITS_PER_WORD) return 0; if (cum->nbytes + size <= 4 * UNITS_PER_WORD) return 0; if (type == NULL_TREE && cum->nbytes + size > 4 * UNITS_PER_WORD) return 0; return 4 * UNITS_PER_WORD - cum->nbytes;}/* Return the high and low words of a CONST_DOUBLE */static voidconst_double_split (rtx x, HOST_WIDE_INT * p_high, HOST_WIDE_INT * p_low){ if (GET_CODE (x) == CONST_DOUBLE) { long t[2]; REAL_VALUE_TYPE rv; switch (GET_MODE (x)) { case DFmode: REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_DOUBLE (rv, t); *p_high = t[1]; /* since v850 is little endian */ *p_low = t[0]; /* high is second word */ return; case SFmode: REAL_VALUE_FROM_CONST_DOUBLE (rv, x); REAL_VALUE_TO_TARGET_SINGLE (rv, *p_high); *p_low = 0; return; case VOIDmode: case DImode: *p_high = CONST_DOUBLE_HIGH (x); *p_low = CONST_DOUBLE_LOW (x); return; default: break; } } fatal_insn ("const_double_split got a bad insn:", x);}/* Return the cost of the rtx R with code CODE. */static intconst_costs_int (HOST_WIDE_INT value, int zero_cost){ if (CONST_OK_FOR_I (value)) return zero_cost; else if (CONST_OK_FOR_J (value)) return 1; else if (CONST_OK_FOR_K (value)) return 2; else return 4;}static intconst_costs (rtx r, enum rtx_code c){ HOST_WIDE_INT high, low; switch (c) { case CONST_INT: return const_costs_int (INTVAL (r), 0); case CONST_DOUBLE: const_double_split (r, &high, &low); if (GET_MODE (r) == SFmode) return const_costs_int (high, 1); else return const_costs_int (high, 1) + const_costs_int (low, 1); case SYMBOL_REF: case LABEL_REF: case CONST: return 2; case HIGH: return 1; default: return 4; }}static boolv850_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int * total){ switch (code) { case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: *total = COSTS_N_INSNS (const_costs (x, code)); return true; case MOD: case DIV: case UMOD: case UDIV: if (TARGET_V850E && optimize_size) *total = 6; else *total = 60; return true; case MULT: if (TARGET_V850E && ( GET_MODE (x) == SImode || GET_MODE (x) == HImode || GET_MODE (x) == QImode)) { if (GET_CODE (XEXP (x, 1)) == REG) *total = 4; else if (GET_CODE (XEXP (x, 1)) == CONST_INT) { if (CONST_OK_FOR_O (INTVAL (XEXP (x, 1)))) *total = 6; else if (CONST_OK_FOR_K (INTVAL (XEXP (x, 1)))) *total = 10; } } else *total = 20; return true; default: return false; }}/* Print operand X using operand code CODE to assembly language output file FILE. */voidprint_operand (FILE * file, rtx x, int code){ HOST_WIDE_INT high, low; switch (code) { case 'c': /* We use 'c' operands with symbols for .vtinherit */ if (GET_CODE (x) == SYMBOL_REF) { output_addr_const(file, x); break; } /* fall through */ case 'b': case 'B': case 'C': switch ((code == 'B' || code == 'C') ? reverse_condition (GET_CODE (x)) : GET_CODE (x)) { case NE: if (code == 'c' || code == 'C') fprintf (file, "nz"); else fprintf (file, "ne"); break; case EQ: if (code == 'c' || code == 'C') fprintf (file, "z"); else fprintf (file, "e"); break; case GE: fprintf (file, "ge"); break; case GT: fprintf (file, "gt"); break; case LE: fprintf (file, "le"); break; case LT: fprintf (file, "lt"); break; case GEU: fprintf (file, "nl"); break; case GTU:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -