(strict_single_insn_op_p, relop): Deleted these useless functions.

From-SVN: r1409
This commit is contained in:
Richard Stallman 1992-07-03 20:34:59 +00:00
parent 079a79484f
commit 483f4fb305

View File

@ -1,495 +1,3 @@
/* Subroutines for insn-output.c for Intel 860
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
Derived from sparc.c.
Written by Richard Stallman (rms@ai.mit.edu).
Hacked substantially by Ron Guilmette (rfg@ncd.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 modify
it under the terms of the GNU General Public License as published by
the 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 of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "config.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"
#include <stdio.h>
static rtx find_addr_reg ();
#ifndef I860_REG_PREFIX
#define I860_REG_PREFIX ""
#endif
char *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. */
int
safe_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 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 2 if REG is used in IN.
Return 3 if REG is both used and clobbered in IN.
Return 0 if neither. */
static int
reg_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. */
int
operand_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. */
int
single_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 LSHIFT:
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;
}
}
/* Nonzero only if this *really* is a single insn operand. */
int
strict_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; `orh'. */
if ((INTVAL (op) & 0xffff) == 0)
return 1;
return 0;
case SYMBOL_REF:
return 0;
case REG:
#if 0
/* This loses when moving an freg to a general reg. */
return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
#endif
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:
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:
return 1;
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 LSHIFT:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
return 1;
case SUBREG:
if (SUBREG_WORD (op) != 0)
return 0;
return strict_single_insn_op_p (SUBREG_REG (op), mode);
case SIGN_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. */
int
relop (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;
}
return 0;
}
/* Return non-zero only if OP is a register of mode MODE,
or const0_rtx. */
@ -1691,7 +1199,7 @@ sfmode_constant_to_ulong (x)
for saving all of the "preserved" registers (and use that number, i.e.
`80', to define STARTING_FRAME_OFFSET) if we wanted to save them in
the lower part of the frame. That could potentially be very wasteful,
and that wastefulness could really hamper people compiling for embedded
and that could cause serious problems when compiling for embedded
i860 targets with very tight limits on stack space. Thus, we choose
here to save the preserved registers in the upper part of the
frame, so that we can decide at the very last minute how much (or how