?? out-sparc.c
字號:
/* Subroutines for insn-output.c for Sun SPARC. Copyright (C) 1987, 1988, 1989 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@mcc.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 1, 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. *//* Global variables for machine-dependend things. *//* This should go away if we pass floats to regs via the stack instead of the frame, and if we learn how to renumber all the registers when we don't do a save (hard!). */extern int frame_pointer_needed;static rtx find_addr_reg ();rtx next_real_insn_no_labels ();/* 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));}/* Return non-zero if INSN is a conditional insn with a predicate valid after an addcc or subcc instruction. */intignore_overflow_conditional_p (insn) rtx insn;{ rtx x = SET_SRC (PATTERN (insn)); RTX_CODE code; if (GET_CODE (x) == IF_THEN_ELSE) x = XEXP (x, 0); code = GET_CODE (x); return code == EQ || code == NE || code == GE || code == LT;}/* 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: return 1; case COMPARE: case MINUS: case PLUS: return (mode != SFmode && mode != DFmode); case AND: case IOR: case XOR: case LSHIFT: 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 0 if REG is used in IN (other than being clobbered). Return 2 if REG does not appear in IN. */static intreg_clobbered_p (reg, in) rtx reg; rtx in;{ register char *fmt; register int i, result = 0; register enum rtx_code code; if (in == 0) return 2; code = GET_CODE (in); switch (code) { /* Let these fail out quickly. */ case CONST_INT: case SYMBOL_REF: case CONST: return 2; case SUBREG: if (SUBREG_WORD (in) != 0) in = gen_rtx (REG, SImode, REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); else in = SUBREG_REG (in); case REG: if (in == reg || refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), in, 0)) return 0; return 2; case SET: if (SET_SRC (in) == reg || refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), SET_SRC (in), 0)) return 0; if (SET_DEST (in) == reg) return 1; if (refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), SET_DEST (in), 0)) if (GET_CODE (SET_DEST (in)) == REG || GET_CODE (SET_DEST (in)) == SUBREG) return 1; else return 0; return 2; case USE: if (XEXP (in, 0) == reg || refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), XEXP (in, 0), 0)) return 0; return 2; case CLOBBER: if (XEXP (in, 0) == reg) return 1; /* If the CLOBBER expression is a SUBREG, accept that as a clobber. But if it is some expression based on this register, that is like a USE as far as this register is concerned, so we won't take it. */ if (refers_to_regno_p (REGNO (reg), REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)), XEXP (in, 0), 0)) if (GET_CODE (XEXP (in, 0)) == REG || GET_CODE (XEXP (in, 0)) == SUBREG) return 1; else return 0; return 2; } fmt = GET_RTX_FORMAT (code); result = 2; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (in, i) - 1; j >= 0; j--) switch (reg_clobbered_p (reg, XVECEXP (in, i, j))) { case 0: return 0; case 2: continue; case 1: result = 1; break; } } else if (fmt[i] == 'e') switch (reg_clobbered_p (reg, XEXP (in, i))) { case 0: return 0; case 2: continue; case 1: result = 1; break; } } return result;}/* 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;{ extern char call_used_regs[]; /* Just experimenting. */ if (GET_CODE (op) == CC0) return 1; if (GET_CODE (op) == REG) { rtx insn; if (op == stack_pointer_rtx) return 0; 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))) { case 0: return 0; case 2: break; case 1: return 1; } if (dead_or_set_p (insn, op)) return 1; } 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 sethi %hi(whatever),%g1, 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:#if 1 /* This is not always a single insn src, technically, but output_delayed_branch knows how to deal with it. */ return 1;#else if (SMALL_INT (op)) return 1; /* We can put this set insn into delay slot, because this is one insn; 'sethi'. */ if ((INTVAL (op) & 0x3ff) == 0) return 1; /* This is not a single insn src, technically, but output_delayed_branch knows how to deal with it. */ return 1;#endif#if 1 case SYMBOL_REF: /* This is not a single insn src, technically, but output_delayed_branch knows how to deal with it. */ return 1;#else return 0;#endif case REG: return 1; case MEM:#if 0 /* This is not a single insn src, technically, but output_delayed_branch knows how to deal with it. */ if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF) return 0;#endif return 1; /* We never need to negate or complement constants. */ case NEG: return (mode != DFmode); case NOT: return 1; case COMPARE: case MINUS: /* If the target is cc0, then these insns will take two insns (one being a nop). */ if (mode != SFmode && mode != DFmode) return 0; case PLUS: case AND: case IOR: case XOR: 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; case LSHIFT: case ASHIFT: case ASHIFTRT: case LSHIFTRT: if (GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0))) return 0; if (GET_CODE (XEXP (op, 1)) != REG && (GET_CODE (XEXP (op, 1)) != SUBREG || GET_CODE (SUBREG_REG (XEXP (op, 1))) != REG)) return 0; return 1; case SUBREG: if (SUBREG_WORD (op) != 0) return 0; return single_insn_src_p (SUBREG_REG (op), mode); case SIGN_EXTEND: case ZERO_EXTEND: /* Lazy... could check for more cases. */ if (GET_CODE (XEXP (op, 0)) == MEM && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) return 1; return 0; /* 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; }}/* This extra test must be done to verify that a move insn really is just one assembler insn. */intsingle_insn_extra_test (dest, src) rtx dest, src;{ /* Moves between FP regs and CPU regs are two insns. */ return (!(GET_CODE (src) == REG && GET_CODE (dest) == REG && (FP_REG_P (src) != FP_REG_P (dest))));}/* Nonzero only if this *really* is a single insn operand. */intstrict_single_insn_op_p (op, mode) rtx op; enum machine_mode mode;{ if (mode == VOIDmode) mode = GET_MODE (op); switch (GET_CODE (op)) { case CC0: return 1; case CONST_INT: if (SMALL_INT (op)) return 1; /* We can put this set insn into delay slot, because this is one insn; 'sethi'. */ if ((INTVAL (op) & 0x3ff) == 0) return 1; return 0; case SYMBOL_REF: return 0; case REG: return (mode != DFmode && mode != DImode); case MEM: if (! CONSTANT_ADDRESS_P (XEXP (op, 0))) return (mode != DFmode && mode != DImode); return 0; /* We never need to negate or complement constants. */ case NEG: return (mode != DFmode); case NOT: return 1; case COMPARE: case MINUS: /* If the target is cc0, then these insns will take two insns (one being a nop). */ return (mode != SFmode && mode != DFmode); case PLUS: case AND: case IOR: case XOR: case LSHIFT: 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; case SUBREG: if (SUBREG_WORD (op) != 0) return 0; return strict_single_insn_op_p (SUBREG_REG (op), mode); case SIGN_EXTEND: case ZERO_EXTEND: if (GET_CODE (XEXP (op, 0)) == MEM && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0))) return 1; return 0; /* 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 truth value of whether OP is a relational operator. */intrelop (op, mode) rtx op; enum machine_mode mode;{ switch (GET_CODE (op)) { case EQ: case NE: case GT: case GE: case LT: case LE: case GTU: case GEU: case LTU: case LEU: return 1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -