📄 arc.c
字号:
/* Subroutines used for code generation on the Argonaut ARC cpu. Copyright (C) 1994, 1995, 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. *//* ??? This is an old port, and is undoubtedly suffering from bit rot. */#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 "function.h"#include "expr.h"#include "recog.h"#include "toplev.h"#include "tm_p.h"#include "target.h"#include "target-def.h"/* Which cpu we're compiling for (NULL(=base), ???). */const char *arc_cpu_string;int arc_cpu_type;/* Name of mangle string to add to symbols to separate code compiled for each cpu (or NULL). */const char *arc_mangle_cpu;/* Save the operands last given to a compare for use when we generate a scc or bcc insn. */rtx arc_compare_op0, arc_compare_op1;/* Name of text, data, and rodata sections, as specified on command line. Selected by -m{text,data,rodata} flags. */const char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;const char *arc_data_string = ARC_DEFAULT_DATA_SECTION;const char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;/* Name of text, data, and rodata sections used in varasm.c. */const char *arc_text_section;const char *arc_data_section;const char *arc_rodata_section;/* Array of valid operand punctuation characters. */char arc_punct_chars[256];/* Variables used by arc_final_prescan_insn to implement conditional execution. */static int arc_ccfsm_state;static int arc_ccfsm_current_cc;static rtx arc_ccfsm_target_insn;static int arc_ccfsm_target_label;/* The maximum number of insns skipped which will be conditionalised if possible. */#define MAX_INSNS_SKIPPED 3/* A nop is needed between a 4 byte insn that sets the condition codes and a branch that uses them (the same isn't true for an 8 byte insn that sets the condition codes). Set by arc_final_prescan_insn. Used by arc_print_operand. */static int last_insn_set_cc_p;static int current_insn_set_cc_p;static void record_cc_ref PARAMS ((rtx));static void arc_init_reg_tables PARAMS ((void));static int get_arc_condition_code PARAMS ((rtx));const struct attribute_spec arc_attribute_table[];static tree arc_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));static bool arc_assemble_integer PARAMS ((rtx, unsigned int, int));static void arc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));static void arc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));static void arc_encode_section_info PARAMS ((tree, int));/* Initialize the GCC target structure. */#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_INTEGER#define TARGET_ASM_INTEGER arc_assemble_integer#undef TARGET_ASM_FUNCTION_PROLOGUE#define TARGET_ASM_FUNCTION_PROLOGUE arc_output_function_prologue#undef TARGET_ASM_FUNCTION_EPILOGUE#define TARGET_ASM_FUNCTION_EPILOGUE arc_output_function_epilogue#undef TARGET_ATTRIBUTE_TABLE#define TARGET_ATTRIBUTE_TABLE arc_attribute_table#undef TARGET_ENCODE_SECTION_INFO#define TARGET_ENCODE_SECTION_INFO arc_encode_section_infostruct gcc_target targetm = TARGET_INITIALIZER;/* Called by OVERRIDE_OPTIONS to initialize various things. */voidarc_init (){ char *tmp; if (arc_cpu_string == 0 || !strcmp (arc_cpu_string, "base")) { /* Ensure we have a printable value for the .cpu pseudo-op. */ arc_cpu_string = "base"; arc_cpu_type = 0; arc_mangle_cpu = NULL; } else if (ARC_EXTENSION_CPU (arc_cpu_string)) ; /* nothing to do */ else { error ("bad value (%s) for -mcpu switch", arc_cpu_string); arc_cpu_string = "base"; arc_cpu_type = 0; arc_mangle_cpu = NULL; } /* Set the pseudo-ops for the various standard sections. */ arc_text_section = tmp = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (tmp, ARC_SECTION_FORMAT, arc_text_string); arc_data_section = tmp = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (tmp, ARC_SECTION_FORMAT, arc_data_string); arc_rodata_section = tmp = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (tmp, ARC_SECTION_FORMAT, arc_rodata_string); arc_init_reg_tables (); /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ memset (arc_punct_chars, 0, sizeof (arc_punct_chars)); arc_punct_chars['#'] = 1; arc_punct_chars['*'] = 1; arc_punct_chars['?'] = 1; arc_punct_chars['!'] = 1; arc_punct_chars['~'] = 1;}/* The condition codes of the ARC, and the inverse function. */static const char *const arc_condition_codes[] ={ "al", 0, "eq", "ne", "p", "n", "c", "nc", "v", "nv", "gt", "le", "ge", "lt", "hi", "ls", "pnz", 0};#define ARC_INVERSE_CONDITION_CODE(X) ((X) ^ 1)/* Returns the index of the ARC condition code string in `arc_condition_codes'. COMPARISON should be an rtx like `(eq (...) (...))'. */static intget_arc_condition_code (comparison) rtx comparison;{ switch (GET_CODE (comparison)) { case EQ : return 2; case NE : return 3; case GT : return 10; case LE : return 11; case GE : return 12; case LT : return 13; case GTU : return 14; case LEU : return 15; case LTU : return 6; case GEU : return 7; default : abort (); } /*NOTREACHED*/ return (42);}/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, return the mode to be used for the comparison. */enum machine_modearc_select_cc_mode (op, x, y) enum rtx_code op; rtx x, y ATTRIBUTE_UNUSED;{ switch (op) { case EQ : case NE : return CCZNmode; default : switch (GET_CODE (x)) { case AND : case IOR : case XOR : case SIGN_EXTEND : case ZERO_EXTEND : return CCZNmode; case ASHIFT : case ASHIFTRT : case LSHIFTRT : return CCZNCmode; default: break; } } return CCmode;}/* 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 arc_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 arc_mode_class mode. */enum arc_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. */const unsigned int arc_hard_regno_mode_ok[] = { 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, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, D_MODES, D_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, /* ??? Leave these as S_MODES for now. */ S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, S_MODES, C_MODES};unsigned int arc_mode_class [NUM_MACHINE_MODES];enum reg_class arc_regno_reg_class[FIRST_PSEUDO_REGISTER];static voidarc_init_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) arc_mode_class[i] = 1 << (int) S_MODE; else if (GET_MODE_SIZE (i) == 8) arc_mode_class[i] = 1 << (int) D_MODE; else if (GET_MODE_SIZE (i) == 16) arc_mode_class[i] = 1 << (int) T_MODE; else if (GET_MODE_SIZE (i) == 32) arc_mode_class[i] = 1 << (int) O_MODE; else arc_mode_class[i] = 0; break; case MODE_FLOAT: case MODE_COMPLEX_FLOAT: if (GET_MODE_SIZE (i) <= 4) arc_mode_class[i] = 1 << (int) SF_MODE; else if (GET_MODE_SIZE (i) == 8) arc_mode_class[i] = 1 << (int) DF_MODE; else if (GET_MODE_SIZE (i) == 16) arc_mode_class[i] = 1 << (int) TF_MODE; else if (GET_MODE_SIZE (i) == 32) arc_mode_class[i] = 1 << (int) OF_MODE; else arc_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 || i == (int) CCZNmode || i == (int) CCZNCmode) arc_mode_class[i] = 1 << (int) C_MODE; else arc_mode_class[i] = 0; break; } } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (i < 60) arc_regno_reg_class[i] = GENERAL_REGS; else if (i == 60) arc_regno_reg_class[i] = LPCOUNT_REG; else if (i == 61) arc_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */; else arc_regno_reg_class[i] = NO_REGS; }}/* ARC specific attribute support. The ARC has these attributes: interrupt - for interrupt functions*/const struct attribute_spec arc_attribute_table[] ={ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ { "interrupt", 1, 1, true, false, false, arc_handle_interrupt_attribute }, { NULL, 0, 0, false, false, false, NULL }};/* Handle an "interrupt" attribute; arguments as in struct attribute_spec.handler. */static treearc_handle_interrupt_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 value = TREE_VALUE (args); if (TREE_CODE (value) != STRING_CST) { warning ("argument of `%s' attribute is not a string constant", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } else if (strcmp (TREE_STRING_POINTER (value), "ilink1") && strcmp (TREE_STRING_POINTER (value), "ilink2")) { warning ("argument of `%s' attribute is not \"ilink1\" or \"ilink2\"", IDENTIFIER_POINTER (name)); *no_add_attrs = true; } return NULL_TREE;}/* Acceptable arguments to the call insn. */intcall_address_operand (op, mode) rtx op; enum machine_mode mode;{ return (symbolic_operand (op, mode) || (GET_CODE (op) == CONST_INT && LEGITIMATE_CONSTANT_P (op)) || (GET_CODE (op) == REG));}intcall_operand (op, mode) rtx op; enum machine_mode 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. */intsymbolic_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: case CONST : return 1; default: return 0; }}/* Return truth value of statement that OP is a symbolic memory operand of mode MODE. */intsymbolic_memory_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST || GET_CODE (op) == LABEL_REF);}/* Return true if OP is a short immediate (shimm) value. */intshort_immediate_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -