📄 m32r.c
字号:
/* Subroutines used for code generation on the Mitsubishi M32R cpu. Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.This file is part of GNU CC.GNU CC 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.GNU CC 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 GNU CC; 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 "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 "expr.h"#include "function.h"#include "recog.h"#include "toplev.h"#include "ggc.h"#include "tm_p.h"#include "target.h"#include "target-def.h"/* Save the operands last given to a compare for use when we generate a scc or bcc insn. */rtx m32r_compare_op0, m32r_compare_op1;/* Array of valid operand punctuation characters. */char m32r_punct_chars[256];/* Selected code model. */const char * m32r_model_string = M32R_MODEL_DEFAULT;enum m32r_model m32r_model;/* Selected SDA support. */const char * m32r_sdata_string = M32R_SDATA_DEFAULT;enum m32r_sdata m32r_sdata;/* Scheduler support */static int m32r_sched_odd_word_p;/* Forward declaration. */static void init_reg_tables PARAMS ((void));static void block_move_call PARAMS ((rtx, rtx, rtx));static int m32r_is_insn PARAMS ((rtx));const struct attribute_spec m32r_attribute_table[];static tree m32r_handle_model_attribute PARAMS ((tree *, tree, tree, int, bool *));static void m32r_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void m32r_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static int m32r_adjust_cost PARAMS ((rtx, rtx, rtx, int));static int m32r_adjust_priority PARAMS ((rtx, int));static void m32r_sched_init PARAMS ((FILE *, int, int));static int m32r_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int));static int m32r_variable_issue PARAMS ((FILE *, int, rtx, int));static int m32r_issue_rate PARAMS ((void));static void m32r_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));static void m32r_encode_section_info PARAMS ((tree, int));static const char *m32r_strip_name_encoding PARAMS ((const char *));static void init_idents PARAMS ((void));/* Initialize the GCC target structure. */#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE m32r_attribute_table#undef TARGET_ASM_ALIGNED_HI_OP#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"#undef TARGET_ASM_ALIGNED_SI_OP#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE m32r_output_function_epilogue#undef TARGET_SCHED_ADJUST_COST#define TARGET_SCHED_ADJUST_COST m32r_adjust_cost#undef TARGET_SCHED_ADJUST_PRIORITY#define TARGET_SCHED_ADJUST_PRIORITY m32r_adjust_priority#undef TARGET_SCHED_ISSUE_RATE#define TARGET_SCHED_ISSUE_RATE m32r_issue_rate#undef TARGET_SCHED_VARIABLE_ISSUE#define TARGET_SCHED_VARIABLE_ISSUE m32r_variable_issue#undef TARGET_SCHED_INIT#define TARGET_SCHED_INIT m32r_sched_init#undef TARGET_SCHED_REORDER#define TARGET_SCHED_REORDER m32r_sched_reorder#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO m32r_encode_section_info#undef TARGET_STRIP_NAME_ENCODING#define TARGET_STRIP_NAME_ENCODING m32r_strip_name_encodingstruct gcc_target targetm = TARGET_INITIALIZER;/* Called by OVERRIDE_OPTIONS to initialize various things. */voidm32r_init (){ init_reg_tables (); /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ memset (m32r_punct_chars, 0, sizeof (m32r_punct_chars)); m32r_punct_chars['#'] = 1; m32r_punct_chars['@'] = 1; /* ??? no longer used */ /* Provide default value if not specified. */ if (!g_switch_set) g_switch_value = SDATA_DEFAULT_SIZE; if (strcmp (m32r_model_string, "small") == 0) m32r_model = M32R_MODEL_SMALL; else if (strcmp (m32r_model_string, "medium") == 0) m32r_model = M32R_MODEL_MEDIUM; else if (strcmp (m32r_model_string, "large") == 0) m32r_model = M32R_MODEL_LARGE; else error ("bad value (%s) for -mmodel switch", m32r_model_string); if (strcmp (m32r_sdata_string, "none") == 0) m32r_sdata = M32R_SDATA_NONE; else if (strcmp (m32r_sdata_string, "sdata") == 0) m32r_sdata = M32R_SDATA_SDATA; else if (strcmp (m32r_sdata_string, "use") == 0) m32r_sdata = M32R_SDATA_USE; else error ("bad value (%s) for -msdata switch", m32r_sdata_string);}/* Vectors to keep interesting information about registers where it can easily be got. We use to use the actual mode value as the bit number, but there is (or may be) more than 32 modes now. Instead we use two tables: one indexed by hard register number, and one indexed by mode. *//* The purpose of m32r_mode_class is to shrink the range of modes so that they all fit (as bit numbers) in a 32 bit word (again). Each real mode is mapped into one m32r_mode_class mode. */enum m32r_mode_class{ C_MODE, S_MODE, D_MODE, T_MODE, O_MODE, SF_MODE, DF_MODE, TF_MODE, OF_MODE, A_MODE};/* Modes for condition codes. */#define C_MODES (1 << (int) C_MODE)/* Modes for single-word and smaller quantities. */#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))/* Modes for double-word and smaller quantities. */#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))/* Modes for quad-word and smaller quantities. */#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))/* Modes for accumulators. */#define A_MODES (1 << (int) A_MODE)/* Value is 1 if register/mode pair is acceptable on arc. */const unsigned int m32r_hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] ={ T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES, S_MODES, C_MODES, A_MODES, A_MODES};unsigned int m32r_mode_class [NUM_MACHINE_MODES];enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];static voidinit_reg_tables (){ int i; for (i = 0; i < NUM_MACHINE_MODES; i++) { switch (GET_MODE_CLASS (i)) { case MODE_INT: case MODE_PARTIAL_INT: case MODE_COMPLEX_INT: if (GET_MODE_SIZE (i) <= 4) m32r_mode_class[i] = 1 << (int) S_MODE; else if (GET_MODE_SIZE (i) == 8) m32r_mode_class[i] = 1 << (int) D_MODE; else if (GET_MODE_SIZE (i) == 16) m32r_mode_class[i] = 1 << (int) T_MODE; else if (GET_MODE_SIZE (i) == 32) m32r_mode_class[i] = 1 << (int) O_MODE; else m32r_mode_class[i] = 0; break; case MODE_FLOAT: case MODE_COMPLEX_FLOAT: if (GET_MODE_SIZE (i) <= 4) m32r_mode_class[i] = 1 << (int) SF_MODE; else if (GET_MODE_SIZE (i) == 8) m32r_mode_class[i] = 1 << (int) DF_MODE; else if (GET_MODE_SIZE (i) == 16) m32r_mode_class[i] = 1 << (int) TF_MODE; else if (GET_MODE_SIZE (i) == 32) m32r_mode_class[i] = 1 << (int) OF_MODE; else m32r_mode_class[i] = 0; break; case MODE_CC: default: /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so we must explicitly check for them here. */ if (i == (int) CCmode) m32r_mode_class[i] = 1 << (int) C_MODE; else m32r_mode_class[i] = 0; break; } } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (GPR_P (i)) m32r_regno_reg_class[i] = GENERAL_REGS; else if (i == ARG_POINTER_REGNUM) m32r_regno_reg_class[i] = GENERAL_REGS; else m32r_regno_reg_class[i] = NO_REGS; }}/* M32R specific attribute support. interrupt - for interrupt functions model - select code model used to access object small: addresses use 24 bits, use bl to make calls medium: addresses use 32 bits, use bl to make calls large: addresses use 32 bits, use seth/add3/jl to make calls Grep for MODEL in m32r.h for more info.*/static tree small_ident1;static tree small_ident2;static tree medium_ident1;static tree medium_ident2;static tree large_ident1;static tree large_ident2;static voidinit_idents (){ if (small_ident1 == 0) { small_ident1 = get_identifier ("small"); small_ident2 = get_identifier ("__small__"); medium_ident1 = get_identifier ("medium"); medium_ident2 = get_identifier ("__medium__"); large_ident1 = get_identifier ("large"); large_ident2 = get_identifier ("__large__"); }}const struct attribute_spec m32r_attribute_table[] ={ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt", 0, 0, true, false, false, NULL }, { "model", 1, 1, true, false, false, m32r_handle_model_attribute }, { NULL, 0, 0, false, false, false, NULL }};/* Handle an "model" attribute; arguments as in struct attribute_spec.handler. */static treem32r_handle_model_attribute (node, name, args, flags, no_add_attrs) tree *node ATTRIBUTE_UNUSED; tree name; tree args; int flags ATTRIBUTE_UNUSED; bool *no_add_attrs;{ tree arg; init_idents (); arg = TREE_VALUE (args); if (arg != small_ident1 && arg != small_ident2 && arg != medium_ident1 && arg != medium_ident2 && arg != large_ident1 && arg != large_ident2) { warning ("invalid argument of `%s' attribute", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}/* A C statement or statements to switch to the appropriate section for output of DECL. DECL is either a `VAR_DECL' node or a constant of some sort. RELOC indicates whether forming the initial value of DECL requires link-time relocations. */static voidm32r_select_section (decl, reloc, align) tree decl; int reloc; unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;{ if (TREE_CODE (decl) == STRING_CST) { if (! flag_writable_strings) readonly_data_section (); else data_section (); } else if (TREE_CODE (decl) == VAR_DECL) { if (SDATA_NAME_P (XSTR (XEXP (DECL_RTL (decl), 0), 0))) sdata_section (); else if ((flag_pic && reloc) || !TREE_READONLY (decl) || TREE_SIDE_EFFECTS (decl) || !DECL_INITIAL (decl) || (DECL_INITIAL (decl) != error_mark_node && !TREE_CONSTANT (DECL_INITIAL (decl)))) data_section (); else readonly_data_section (); } else readonly_data_section ();}/* Encode section information of DECL, which is either a VAR_DECL, FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???. For the M32R we want to record: - whether the object lives in .sdata/.sbss. objects living in .sdata/.sbss are prefixed with SDATA_FLAG_CHAR - what code model should be used to access the object small: recorded with no flag - for space efficiency since they'll be the most common medium: prefixed with MEDIUM_FLAG_CHAR large: prefixed with LARGE_FLAG_CHAR*/static voidm32r_encode_section_info (decl, first) tree decl; int first;{ char prefix = 0; tree model = 0; if (!first) return; switch (TREE_CODE (decl)) { case VAR_DECL : case FUNCTION_DECL : model = lookup_attribute ("model", DECL_ATTRIBUTES (decl)); break; case STRING_CST : case CONSTRUCTOR : /* ??? document all others that can appear here */ default : return; } /* Only mark the object as being small data area addressable if it hasn't been explicitly marked with a code model. The user can explicitly put an object in the small data area with the section attribute. If the object is in sdata/sbss and marked with a code model do both [put the object in .sdata and mark it as being addressed with a specific code model - don't mark it as being addressed with an SDA reloc though]. This is ok and might be useful at times. If the object doesn't fit the linker will give an error. */ if (! model) { if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd' && DECL_SECTION_NAME (decl) != NULL_TREE) { char *name = (char *) TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); if (! strcmp (name, ".sdata") || ! strcmp (name, ".sbss")) {#if 0 /* ??? There's no reason to disallow this, is there? */ if (TREE_READONLY (decl)) error_with_decl (decl, "const objects cannot go in .sdata/.sbss");#endif prefix = SDATA_FLAG_CHAR; } } else { if (TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl) && ! TARGET_SDATA_NONE) { int size = int_size_in_bytes (TREE_TYPE (decl)); if (size > 0 && size <= g_switch_value) prefix = SDATA_FLAG_CHAR; } } } /* If data area not decided yet, check for a code model. */ if (prefix == 0) { if (model) { tree id; init_idents (); id = TREE_VALUE (TREE_VALUE (model)); if (id == small_ident1 || id == small_ident2) ; /* don't mark the symbol specially */ else if (id == medium_ident1 || id == medium_ident2) prefix = MEDIUM_FLAG_CHAR; else if (id == large_ident1 || id == large_ident2) prefix = LARGE_FLAG_CHAR; else abort (); /* shouldn't happen */ } else { if (TARGET_MODEL_SMALL) ; /* don't mark the symbol specially */ else if (TARGET_MODEL_MEDIUM) prefix = MEDIUM_FLAG_CHAR; else if (TARGET_MODEL_LARGE) prefix = LARGE_FLAG_CHAR; else abort (); /* shouldn't happen */ } } if (prefix != 0) { rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' ? TREE_CST_RTL (decl) : DECL_RTL (decl));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -