📄 i860.c
字号:
/* Subroutines for insn-output.c for Intel 860 Copyright (C) 1989, 91, 97, 98, 1999 Free Software Foundation, Inc. Derived from sparc.c. Written by Richard Stallman (rms@ai.mit.edu). Hacked substantially by Ron Guilmette (rfg@netcom.com) to cater to the whims of the System V Release 4 assembler.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 "flags.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 "recog.h"#include "insn-attr.h"static rtx find_addr_reg ();#ifndef I860_REG_PREFIX#define I860_REG_PREFIX ""#endifchar *i860_reg_prefix = I860_REG_PREFIX;/* Save information from a "cmpxx" operation until the branch is emitted. */rtx i860_compare_op0, i860_compare_op1;/* Return non-zero if this pattern, can be evaluated safely, even if it was not asked for. */intsafe_insn_src_p (op, mode) rtx op; enum machine_mode mode;{ /* Just experimenting. */ /* No floating point src is safe if it contains an arithmetic operation, since that operation may trap. */ switch (GET_CODE (op)) { case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST: return 1; case REG: return 1; case MEM: return CONSTANT_ADDRESS_P (XEXP (op, 0)); /* We never need to negate or complement constants. */ case NEG: return (mode != SFmode && mode != DFmode); case NOT: case ZERO_EXTEND: return 1; case EQ: case NE: case LT: case GT: case LE: case GE: case LTU: case GTU: case LEU: case GEU: case MINUS: case PLUS: return (mode != SFmode && mode != DFmode); case AND: case IOR: case XOR: case ASHIFT: case ASHIFTRT: case LSHIFTRT: if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1)))) return 0; return 1; default: return 0; }}/* Return 1 if REG is clobbered in IN. Return 2 if REG is used in IN. Return 3 if REG is both used and clobbered in IN. Return 0 if neither. */static intreg_clobbered_p (reg, in) rtx reg; rtx in;{ register enum rtx_code code; if (in == 0) return 0; code = GET_CODE (in); if (code == SET || code == CLOBBER) { rtx dest = SET_DEST (in); int set = 0; int used = 0; while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG || GET_CODE (dest) == SIGN_EXTRACT || GET_CODE (dest) == ZERO_EXTRACT) dest = XEXP (dest, 0); if (dest == reg) set = 1; else if (GET_CODE (dest) == REG && refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), SET_DEST (in), 0)) { set = 1; /* Anything that sets just part of the register is considered using as well as setting it. But note that a straight SUBREG of a single-word value clobbers the entire value. */ if (dest != SET_DEST (in) && ! (GET_CODE (SET_DEST (in)) == SUBREG || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest)))) used = 1; } if (code == SET) { if (set) used = refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), SET_SRC (in), 0); else used = refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), in, 0); } return set + used * 2; } if (refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), in, 0)) return 2; return 0;}/* Return non-zero if OP can be written to without screwing up GCC's model of what's going on. It is assumed that this operand appears in the dest position of a SET insn in a conditional branch's delay slot. AFTER is the label to start looking from. */intoperand_clobbered_before_used_after (op, after) rtx op; rtx after;{ /* Just experimenting. */ if (GET_CODE (op) == CC0) return 1; if (GET_CODE (op) == REG) { rtx insn; if (op == stack_pointer_rtx) return 0; /* Scan forward from the label, to see if the value of OP is clobbered before the first use. */ for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn)) { if (GET_CODE (insn) == NOTE) continue; if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN) { switch (reg_clobbered_p (op, PATTERN (insn))) { default: return 0; case 1: return 1; case 0: break; } } /* If we reach another label without clobbering OP, then we cannot safely write it here. */ else if (GET_CODE (insn) == CODE_LABEL) return 0; if (GET_CODE (insn) == JUMP_INSN) { if (condjump_p (insn)) return 0; /* This is a jump insn which has already been mangled. We can't tell what it does. */ if (GET_CODE (PATTERN (insn)) == PARALLEL) return 0; if (! JUMP_LABEL (insn)) return 0; /* Keep following jumps. */ insn = JUMP_LABEL (insn); } } return 1; } /* In both of these cases, the first insn executed for this op will be a orh whatever%h,%?r0,%?r31, which is tolerable. */ if (GET_CODE (op) == MEM) return (CONSTANT_ADDRESS_P (XEXP (op, 0))); return 0;}/* Return non-zero if this pattern, as a source to a "SET", is known to yield an instruction of unit size. */intsingle_insn_src_p (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case CONST_INT: /* This is not always a single insn src, technically, but output_delayed_branch knows how to deal with it. */ return 1; case SYMBOL_REF: case CONST: /* This is not a single insn src, technically, but output_delayed_branch knows how to deal with it. */ return 1; case REG: return 1; case MEM: return 1; /* We never need to negate or complement constants. */ case NEG: return (mode != DFmode); case NOT: case ZERO_EXTEND: return 1; case PLUS: case MINUS: /* Detect cases that require multiple instructions. */ if (CONSTANT_P (XEXP (op, 1)) && !(GET_CODE (XEXP (op, 1)) == CONST_INT && SMALL_INT (XEXP (op, 1)))) return 0; case EQ: case NE: case LT: case GT: case LE: case GE: case LTU: case GTU: case LEU: case GEU: /* Not doing floating point, since they probably take longer than the branch slot they might fill. */ return (mode != SFmode && mode != DFmode); case AND: if (GET_CODE (XEXP (op, 1)) == NOT) { rtx arg = XEXP (XEXP (op, 1), 0); if (CONSTANT_P (arg) && !(GET_CODE (arg) == CONST_INT && (SMALL_INT (arg) || (INTVAL (arg) & 0xffff) == 0))) return 0; } case IOR: case XOR: /* Both small and round numbers take one instruction; others take two. */ if (CONSTANT_P (XEXP (op, 1)) && !(GET_CODE (XEXP (op, 1)) == CONST_INT && (SMALL_INT (XEXP (op, 1)) || (INTVAL (XEXP (op, 1)) & 0xffff) == 0))) return 0; case ASHIFT: case ASHIFTRT: case LSHIFTRT: return 1; case SUBREG: if (SUBREG_WORD (op) != 0) return 0; return single_insn_src_p (SUBREG_REG (op), mode); /* Not doing floating point, since they probably take longer than the branch slot they might fill. */ case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT: case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: return 0; default: return 0; }}/* 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;{ return (op == const0_rtx || register_operand (op, mode) || op == CONST0_RTX (mode));}/* Return truth value of whether OP can be used as an operands in a three address add/subtract 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 1 if OP is a valid first operand for a logical insn of mode MODE. */intlogic_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));}/* Return 1 if OP is a valid first operand for a shift insn of mode MODE. */intshift_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT));}/* Return 1 if OP is a valid first operand for either a logical insn or an add insn of mode MODE. */intcompare_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));}/* Return truth value of whether OP can be used as the 5-bit immediate operand of a bte or btne insn. */intbte_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -