(strict_single_insn_op_p, relop): Deleted these useless functions.
From-SVN: r1409
This commit is contained in:
parent
079a79484f
commit
483f4fb305
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user