📄 arc.c
字号:
/* Subroutines used for code generation on the Argonaut ARC cpu. Copyright (C) 1994, 1995, 1997 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 <stdio.h>#include "config.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"/* Which cpu we're compiling for (NULL(=base), ???). */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). */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. */char *arc_text_string = ARC_DEFAULT_TEXT_SECTION;char *arc_data_string = ARC_DEFAULT_DATA_SECTION;char *arc_rodata_string = ARC_DEFAULT_RODATA_SECTION;/* Name of text, data, and rodata sections used in varasm.c. */char *arc_text_section;char *arc_data_section;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 ();void arc_init_reg_tables ();/* Called by OVERRIDE_OPTIONS to initialize various things. */voidarc_init (void){ 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 = xmalloc (strlen (arc_text_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (arc_text_section, ARC_SECTION_FORMAT, arc_text_string); arc_data_section = xmalloc (strlen (arc_data_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (arc_data_section, ARC_SECTION_FORMAT, arc_data_string); arc_rodata_section = xmalloc (strlen (arc_rodata_string) + sizeof (ARC_SECTION_FORMAT) + 1); sprintf (arc_rodata_section, 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 char *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;{ 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; } } 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. */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];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*//* Return nonzero if IDENTIFIER is a valid decl attribute. */intarc_valid_machine_decl_attribute (type, attributes, identifier, args) tree type; tree attributes; tree identifier; tree args;{ if (identifier == get_identifier ("__interrupt__") && list_length (args) == 1 && TREE_CODE (TREE_VALUE (args)) == STRING_CST) { tree value = TREE_VALUE (args); if (!strcmp (TREE_STRING_POINTER (value), "ilink1") || !strcmp (TREE_STRING_POINTER (value), "ilink2")) 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). */intarc_comp_type_attributes (type1, type2) tree type1, type2;{ return 1;}/* Set the default attributes for TYPE. */voidarc_set_default_type_attributes (type) tree type;{}/* 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;{ 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;{ 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;{ if (GET_CODE (op) != CONST_INT) return 0; return SMALL_INT (INTVAL (op));}/* Return true if OP will require a long immediate (limm) value. This is currently only used when calculating length attributes. */intlong_immediate_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case SYMBOL_REF : case LABEL_REF : case CONST : return 1; case CONST_INT : return !SMALL_INT (INTVAL (op)); case CONST_DOUBLE : /* These can happen because large unsigned 32 bit constants are represented this way (the multiplication patterns can cause these to be generated). They also occur for SFmode values. */ return 1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -