📄 sparc.c
字号:
/* Subroutines for insn-output.c for Sun SPARC. Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com)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, 675 Mass Ave, Cambridge, MA 02139, USA. */#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"/* Global variables for machine-dependent things. *//* Save the operands last given to a compare for use when we generate a scc or bcc insn. */rtx sparc_compare_op0, sparc_compare_op1;/* We may need an epilogue if we spill too many registers. If this is non-zero, then we branch here for the epilogue. */static rtx leaf_label;#ifdef LEAF_REGISTERS/* Vector to say how input registers are mapped to output registers. FRAME_POINTER_REGNUM cannot be remapped by this function to eliminate it. You must use -fomit-frame-pointer to get that. */char leaf_reg_remap[] ={ 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, 9, 10, 11, 12, 13, -1, 15, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};char leaf_reg_backmap[] ={ 0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 14, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};#endif/* Global variables set by FUNCTION_PROLOGUE. *//* Size of frame. Need to know this to emit return insns from leaf procedures. */int apparent_fsize;int actual_fsize;/* Name of where we pretend to think the frame pointer points. Normally, this is "%fp", but if we are in a leaf procedure, this is "%sp+something". */char *frame_base_name;static rtx find_addr_reg ();/* Return non-zero only if OP is a register of mode MODE, or const0_rtx. */intreg_or_0_operand (op, mode) rtx op; enum machine_mode mode;{ if (op == const0_rtx || register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == 0) return 1; return 0;}/* Nonzero if OP can appear as the dest of a RESTORE insn. */intrestore_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == REG && GET_MODE (op) == mode && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));}/* PC-relative call insn on SPARC is independent of `memory_operand'. */intcall_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM) abort (); op = XEXP (op, 0); return (REG_P (op) || CONSTANT_P (op));}intcall_operand_address (op, mode) rtx op; enum machine_mode mode;{ return (REG_P (op) || CONSTANT_P (op));}/* Returns 1 if OP is either a symbol reference or a sum of a symbol reference and a constant. */intsymbolic_operand (op, mode) register rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: return 1; case CONST: op = XEXP (op, 0); return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF || GET_CODE (XEXP (op, 0)) == LABEL_REF) && GET_CODE (XEXP (op, 1)) == CONST_INT); /* This clause seems to be irrelevant. */ case CONST_DOUBLE: return GET_MODE (op) == mode; 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) == HIGH || GET_CODE (op) == LABEL_REF);}/* Return 1 if the operand is either a register or a memory operand that is not symbolic. */intreg_or_nonsymb_mem_operand (op, mode) register rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode)) return 1; return 0;}intsparc_operand (op, mode) rtx op; enum machine_mode mode;{ if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT) return SMALL_INT (op); if (GET_MODE (op) != mode) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); if (GET_CODE (op) == LO_SUM) return (GET_CODE (XEXP (op, 0)) == REG && symbolic_operand (XEXP (op, 1), Pmode)); return memory_address_p (mode, op);}intmove_operand (op, mode) rtx op; enum machine_mode mode;{ if (mode == DImode && arith_double_operand (op, mode)) return 1; if (register_operand (op, mode)) return 1; if (GET_CODE (op) == CONST_INT) return (SMALL_INT (op) || (INTVAL (op) & 0x3ff) == 0); if (GET_MODE (op) != mode) return 0; if (GET_CODE (op) == SUBREG) op = SUBREG_REG (op); if (GET_CODE (op) != MEM) return 0; op = XEXP (op, 0); if (GET_CODE (op) == LO_SUM) return (register_operand (XEXP (op, 0), Pmode) && CONSTANT_P (XEXP (op, 1))); return memory_address_p (mode, op);}intmove_pic_label (op, mode) rtx op; enum machine_mode mode;{ /* Special case for PIC. */ if (flag_pic && GET_CODE (op) == LABEL_REF) return 1; return 0;}/* The rtx for the global offset table which is a special form that *is* a position independent symbolic constant. */rtx pic_pc_rtx;/* Ensure that we are not using patterns that are not OK with PIC. */intcheck_pic (i) int i;{ switch (flag_pic) { case 1: if (GET_CODE (recog_operand[i]) == SYMBOL_REF || (GET_CODE (recog_operand[i]) == CONST && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) abort (); case 2: default: return 1; }}/* Return true if X is an address which needs a temporary register when reloaded while generating PIC code. */intpic_address_needs_scratch (x) rtx x;{ /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) return 1; return 0;}intmemop (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == MEM) return (mode == VOIDmode || mode == GET_MODE (op)); return 0;}/* Return truth value of whether OP is EQ or NE. */inteq_or_neq (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == EQ || GET_CODE (op) == NE);}/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU, or LTU for non-floating-point. We handle those specially. */intnormal_comp_operator (op, mode) rtx op; enum machine_mode mode;{ enum rtx_code code = GET_CODE (op); if (GET_RTX_CLASS (code) != '<') return 0; if (GET_MODE (XEXP (op, 0)) == CCFPmode || GET_MODE (XEXP (op, 0)) == CCFPEmode) return 1; return (code != NE && code != EQ && code != GEU && code != LTU);}/* Return 1 if this is a comparison operator. This allows the use of MATCH_OPERATOR to recognize all the branch insns. */intnoov_compare_op (op, mode) register rtx op; enum machine_mode mode;{ enum rtx_code code = GET_CODE (op); if (GET_RTX_CLASS (code) != '<') return 0; if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode) /* These are the only branches which work with CC_NOOVmode. */ return (code == EQ || code == NE || code == GE || code == LT); return 1;}/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */intextend_op (op, mode) rtx op; enum machine_mode mode;{ return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;}/* Return nonzero if OP is an operator of mode MODE which can set the condition codes explicitly. We do not include PLUS and MINUS because these require CC_NOOVmode, which we handle explicitly. */intcc_arithop (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR) return 1; return 0;}/* Return nonzero if OP is an operator of mode MODE which can bitwise complement its second operand and set the condition codes explicitly. */intcc_arithopn (op, mode) rtx op; enum machine_mode mode;{ /* XOR is not here because combine canonicalizes (xor (not ...) ...) and (xor ... (not ...)) to (not (xor ...)). */ return (GET_CODE (op) == AND || GET_CODE (op) == IOR);}/* Return truth value of whether OP can be used as an operands in a three address arithmetic insn (such as add %o1,7,%l2) of mode MODE. */intarith_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));}/* Return truth value of whether OP is a register or a CONST_DOUBLE. */intarith_double_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_DOUBLE && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000 && ((CONST_DOUBLE_HIGH (op) == -1 && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000) || (CONST_DOUBLE_HIGH (op) == 0 && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))) || (GET_CODE (op) == CONST_INT && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode) && (unsigned) (INTVAL (op) + 0x1000) < 0x2000));}/* Return truth value of whether OP is a integer which fits the range constraining immediate operands in three-address insns. */intsmall_int (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of statement that OP is a call-clobbered register. */intclobbered_register (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);}/* X and Y are two things to compare using CODE. Emit the compare insn and return the rtx for register 0 in the proper mode. */rtxgen_compare_reg (code, x, y) enum rtx_code code; rtx x, y;{ enum machine_mode mode = SELECT_CC_MODE (code, x, y);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -