📄 a29k.c
字号:
/* Subroutines used for code generation on AMD Am29000. Copyright (C) 1987, 88, 90-94, 1995, 1997, 1999 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@nyu.edu)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 <stdio.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 "recog.h"#include "expr.h"#include "obstack.h"#include "tree.h"#include "reload.h"#define min(A,B) ((A) < (B) ? (A) : (B))/* This gives the size in words of the register stack for the current procedure. */static int a29k_regstack_size;/* True if the current procedure has a call instruction. */static int a29k_makes_calls;/* This points to the last insn of the insn prologue. It is set when an insn without a filled delay slot is found near the start of the function. */static char *a29k_last_prologue_insn;/* This points to the first insn that will be in the epilogue. It is null if no epilogue is required. */static char *a29k_first_epilogue_insn;/* This is nonzero if a a29k_first_epilogue_insn was put in a delay slot. It indicates that an intermediate label needs to be written. */static int a29k_first_epilogue_insn_used;/* Location to hold the name of the current function. We need this prolog to contain the tag words prior to the declaration. So the name must be stored away. */char *a29k_function_name;/* Mapping of registers to debug register numbers. The only change is for the frame pointer and the register numbers used for the incoming arguments. */int a29k_debug_reg_map[FIRST_PSEUDO_REGISTER];/* Save information from a "cmpxx" operation until the branch or scc is emitted. */rtx a29k_compare_op0, a29k_compare_op1;int a29k_compare_fp_p;/* Gives names for registers. */extern char *reg_names[];/* Returns 1 if OP is a 8-bit constant. */intcint_8_operand (op, mode) register rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffffff00) == 0;}/* Returns 1 if OP is a 16-bit constant. */intcint_16_operand (op, mode) rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff0000) == 0;}/* Returns 1 if OP is a constant that cannot be moved in a single insn. */intlong_const_operand (op, mode) register rtx op; enum machine_mode mode;{ if (! CONSTANT_P (op)) return 0; if (TARGET_29050 && GET_CODE (op) == CONST_INT && (INTVAL (op) & 0xffff) == 0) return 0; return (GET_CODE (op) != CONST_INT || ((INTVAL (op) & 0xffff0000) != 0 && (INTVAL (op) & 0xffff0000) != 0xffff0000 && INTVAL (op) != 0x80000000));}/* The following four functions detect constants of 0, 8, 16, and 24 used as a position in ZERO_EXTRACT operations. They can either be the appropriate constant integer or a shift (which will be produced by combine). */static intshift_constant_operand (op, mode, val) rtx op; enum machine_mode mode; int val;{ return ((GET_CODE (op) == CONST_INT && INTVAL (op) == val) || (GET_CODE (op) == ASHIFT && GET_CODE (XEXP (op, 0)) == CONST_INT && INTVAL (XEXP (op, 0)) == val / 8 && GET_CODE (XEXP (op, 1)) == CONST_INT && INTVAL (XEXP (op, 1)) == 3));}intconst_0_operand (op, mode) rtx op; enum machine_mode mode;{ return shift_constant_operand (op, mode, 0);}intconst_8_operand (op, mode) rtx op; enum machine_mode mode;{ return shift_constant_operand (op, mode, 8);}intconst_16_operand (op, mode) rtx op; enum machine_mode mode;{ return shift_constant_operand (op, mode, 16);}intconst_24_operand (op, mode) rtx op; enum machine_mode mode;{ return shift_constant_operand (op, mode, 24);}/* Returns 1 if OP is a floating-point constant of the proper mode. */intfloat_const_operand (op, mode) rtx op; enum machine_mode mode;{ return GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == mode;}/* Returns 1 if OP is a floating-point constant of the proper mode or a general-purpose register. */intgpc_reg_or_float_constant_operand (op, mode) rtx op; enum machine_mode mode;{ return float_const_operand (op, mode) || gpc_reg_operand (op, mode);}/* Returns 1 if OP is an integer constant of the proper mode or a general-purpose register. */intgpc_reg_or_integer_constant_operand (op, mode) rtx op; enum machine_mode mode;{ return ((GET_MODE (op) == VOIDmode && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)) || gpc_reg_operand (op, mode));} /* Returns 1 if OP is a special machine register. */intspec_reg_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != REG || GET_MODE (op) != mode) return 0; switch (GET_MODE_CLASS (mode)) { case MODE_PARTIAL_INT: return REGNO (op) >= R_BP && REGNO (op) <= R_CR; case MODE_INT: return REGNO (op) >= R_Q && REGNO (op) <= R_EXO; default: return 0; }}/* Returns 1 if OP is an accumulator register. */intaccum_reg_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == REG && REGNO (op) >= R_ACU (0) && REGNO (op) <= R_ACU (3));}/* Returns 1 if OP is a normal data register. */intgpc_reg_operand (op, mode) rtx op; enum machine_mode mode;{ int regno; if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == REG) regno = REGNO (op); else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) { regno = REGNO (SUBREG_REG (op)); if (regno < FIRST_PSEUDO_REGISTER) regno += SUBREG_WORD (op); } else return 0; return (regno >= FIRST_PSEUDO_REGISTER || regno < R_BP || (regno >= R_KR (0) && regno <= R_KR (31)));}/* Returns 1 if OP is either an 8-bit constant integer or a general register. If a register, it must be in the proper mode unless MODE is VOIDmode. */intsrcb_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT && (mode == QImode || (INTVAL (op) & 0xffffff00) == 0)) return 1; if (GET_MODE (op) != mode && mode != VOIDmode) return 0; return gpc_reg_operand (op, mode);}intcmplsrcb_operand (op, mode) register rtx op; enum machine_mode mode;{ if (GET_CODE (op) == CONST_INT && (mode == QImode || (INTVAL (op) & 0xffffff00) == 0xffffff00)) return 1; if (GET_MODE (op) != mode && mode != VOIDmode) return 0; return gpc_reg_operand (op, mode);}/* Return 1 if OP is either an immediate or a general register. This is used for the input operand of mtsr/mtrsim. */intgpc_reg_or_immediate_operand (op, mode) rtx op; enum machine_mode mode;{ return gpc_reg_operand (op, mode) || immediate_operand (op, mode);}/* Return 1 if OP can be used as the second operand of and AND insn. This includes srcb_operand and a constant whose complement fits in 8 bits. */intand_operand (op, mode) rtx op; enum machine_mode mode;{ return (srcb_operand (op, mode) || (GET_CODE (op) == CONST_INT && ((unsigned) ((~ INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));}/* Return 1 if OP can be used as the second operand of an ADD insn. This is the same as above, except we use negative, rather than complement. */intadd_operand (op, mode) rtx op; enum machine_mode mode;{ return (srcb_operand (op, mode) || (GET_CODE (op) == CONST_INT && ((unsigned) ((- INTVAL (op)) & GET_MODE_MASK (mode)) < 256)));}/* Return 1 if OP is a valid address in a CALL_INSN. These are a SYMBOL_REF to the current function, all SYMBOL_REFs if TARGET_SMALL_MEMORY, or a sufficiently-small constant. */intcall_operand (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case SYMBOL_REF: return (TARGET_SMALL_MEMORY || (! TARGET_LARGE_MEMORY && ((GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FLAG (op)) || ! strcmp (XSTR (op, 0), current_function_name)))); case CONST_INT: return (unsigned HOST_WIDE_INT) INTVAL (op) < 0x40000; default: return 0; }}/* Return 1 if OP can be used as the input operand for a move insn. */intin_operand (op, mode) rtx op; enum machine_mode mode;{ rtx orig_op = op; if (! general_operand (op, mode)) return 0; while (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); switch (GET_CODE (op)) { case REG: return 1; case MEM: return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE); case CONST_INT: if (GET_MODE_CLASS (mode) != MODE_INT && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT) return 0; return 1; case CONST: case SYMBOL_REF: case LABEL_REF: return (GET_MODE (op) == mode || mode == SImode || mode == HImode || mode == QImode); case CONST_DOUBLE: return ((GET_MODE_CLASS (mode) == MODE_FLOAT && mode == GET_MODE (op)) || (GET_MODE (op) == VOIDmode && GET_MODE_CLASS (mode) == MODE_INT)); default: return 0; }}/* Return 1 if OP can be used as the output operand for a move insn. */intout_operand (op, mode) rtx op; enum machine_mode mode;{ rtx orig_op = op; if (! general_operand (op, mode)) return 0; while (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) == REG) return (gpc_reg_operand (orig_op, mode) || spec_reg_operand (orig_op, mode) || (GET_MODE_CLASS (mode) == MODE_FLOAT && accum_reg_operand (orig_op, mode))); else if (GET_CODE (op) == MEM) return (GET_MODE_SIZE (mode) >= UNITS_PER_WORD || TARGET_DW_ENABLE); else return 0;}/* Return 1 if OP is an item in memory, given that we are in reload. */intreload_memory_operand (op, mode) rtx op; enum machine_mode mode;{ int regno = true_regnum (op); return (! CONSTANT_P (op) && (regno == -1 || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)));}/* Given an object for which reload_memory_operand is true, return the address of the operand, taking into account anything that reload may do. */rtxa29k_get_reloaded_address (op) rtx op;{ if (GET_CODE (op) == SUBREG) { if (SUBREG_WORD (op) != 0) abort (); op = SUBREG_REG (op); } if (GET_CODE (op) == REG) op = reg_equiv_mem[REGNO (op)]; return find_replacement (&XEXP (op, 0));}/* Subfunction of the following function. Update the flags of any MEM found in part of X. */static voida29k_set_memflags_1 (x, in_struct_p, scalar_p, volatile_p, unchanging_p) rtx x; int in_struct_p, scalar_p, volatile_p, unchanging_p;{ int i; switch (GET_CODE (x)) { case SEQUENCE: case PARALLEL: for (i = XVECLEN (x, 0) - 1; i >= 0; i--) a29k_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p, unchanging_p); break; case INSN: a29k_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p, unchanging_p); break; case SET: a29k_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p, unchanging_p); a29k_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p, unchanging_p); break; case MEM: MEM_IN_STRUCT_P (x) = in_struct_p; MEM_SCALAR_P (x) = scalar_p; MEM_VOLATILE_P (x) = volatile_p; RTX_UNCHANGING_P (x) = unchanging_p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -