📄 m32r.c
字号:
/* Subroutines used for code generation on the Mitsubishi M32R cpu. Copyright (C) 1996, 1997, 1998 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 "insn-flags.h"#include "output.h"#include "insn-attr.h"#include "flags.h"#include "expr.h"#include "recog.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. */char *m32r_model_string = M32R_MODEL_DEFAULT;enum m32r_model m32r_model;/* Selected SDA support. */char *m32r_sdata_string = M32R_SDATA_DEFAULT;enum m32r_sdata m32r_sdata;/* Forward declaration. */static void init_reg_tables PROTO((void));/* 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};/* 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))/* Value is 1 if register/mode pair is acceptable on arc. */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};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 interrupt_ident1;static tree interrupt_ident2;static tree model_ident1;static tree model_ident2;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 PROTO ((void)){ if (interrupt_ident1 == 0) { interrupt_ident1 = get_identifier ("interrupt"); interrupt_ident2 = get_identifier ("__interrupt__"); model_ident1 = get_identifier ("model"); model_ident2 = get_identifier ("__model__"); 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__"); }}/* Return nonzero if IDENTIFIER is a valid decl attribute. */intm32r_valid_machine_decl_attribute (type, attributes, identifier, args) tree type; tree attributes; tree identifier; tree args;{ init_idents (); if ((identifier == interrupt_ident1 || identifier == interrupt_ident2) && list_length (args) == 0) return 1; if ((identifier == model_ident1 || identifier == model_ident2) && list_length (args) == 1 && (TREE_VALUE (args) == small_ident1 || TREE_VALUE (args) == small_ident2 || TREE_VALUE (args) == medium_ident1 || TREE_VALUE (args) == medium_ident2 || TREE_VALUE (args) == large_ident1 || TREE_VALUE (args) == large_ident2)) return 1; return 0;}/* Return zero if TYPE1 and TYPE are incompatible, one if they are compatible, and two if they are nearly compatible (which causes a warning to be generated). */intm32r_comp_type_attributes (type1, type2) tree type1, type2;{ return 1;}/* Set the default attributes for TYPE. */voidm32r_set_default_type_attributes (type) tree type;{}/* 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. */voidm32r_select_section (decl, reloc) tree decl; int reloc;{ if (TREE_CODE (decl) == STRING_CST) { if (! flag_writable_strings) const_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 const_section (); } else const_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*/voidm32r_encode_section_info (decl) tree decl;{ char prefix = 0; tree model = 0; switch (TREE_CODE (decl)) { case VAR_DECL : case FUNCTION_DECL : model = lookup_attribute ("model", DECL_MACHINE_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 = 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)); char *str = XSTR (XEXP (rtl, 0), 0); int len = strlen (str); char *newstr = savealloc (len + 2); strcpy (newstr + 1, str); *newstr = prefix; XSTR (XEXP (rtl, 0), 0) = newstr; }}/* Do anything needed before RTL is emitted for each function. */voidm32r_init_expanders (){ /* ??? At one point there was code here. The function is left in to make it easy to experiment. */}/* Acceptable arguments to the call insn. */intcall_address_operand (op, int_mode) rtx op; int int_mode;{ return symbolic_operand (op, int_mode);/* Constants and values in registers are not OK, because the m32r BL instruction can only support PC relative branching. */ }intcall_operand (op, int_mode) rtx op; int int_mode;{ enum machine_mode mode = (enum machine_mode)int_mode; if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); return call_address_operand (op, mode);}/* Returns 1 if OP is a symbol reference. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -