home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
gcc-2.3.3-src.lha
/
GNU
/
src
/
amiga
/
gcc-2.3.3
/
recog.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
55KB
|
1,960 lines
/* Subroutines used by or related to instruction recognition.
Copyright (C) 1987, 1988, 1991, 1992 Free Software Foundation, Inc.
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 "rtl.h"
#include <stdio.h>
#include "insn-config.h"
#include "insn-attr.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "recog.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
#include "real.h"
#ifndef STACK_PUSH_CODE
#ifdef STACK_GROWS_DOWNWARD
#define STACK_PUSH_CODE PRE_DEC
#else
#define STACK_PUSH_CODE PRE_INC
#endif
#endif
/* Import from final.c: */
extern rtx alter_subreg ();
int strict_memory_address_p ();
int memory_address_p ();
/* Nonzero means allow operands to be volatile.
This should be 0 if you are generating rtl, such as if you are calling
the functions in optabs.c and expmed.c (most of the time).
This should be 1 if all valid insns need to be recognized,
such as in regclass.c and final.c and reload.c.
init_recog and init_recog_no_volatile are responsible for setting this. */
int volatile_ok;
/* On return from `constrain_operands', indicate which alternative
was satisfied. */
int which_alternative;
/* Nonzero after end of reload pass.
Set to 1 or 0 by toplev.c.
Controls the significance of (SUBREG (MEM)). */
int reload_completed;
/* Initialize data used by the function `recog'.
This must be called once in the compilation of a function
before any insn recognition may be done in the function. */
void
init_recog_no_volatile ()
{
volatile_ok = 0;
}
void
init_recog ()
{
volatile_ok = 1;
}
/* Try recognizing the instruction INSN,
and return the code number that results.
Remeber the code so that repeated calls do not
need to spend the time for actual rerecognition.
This function is the normal interface to instruction recognition.
The automatically-generated function `recog' is normally called
through this one. (The only exception is in combine.c.) */
int
recog_memoized (insn)
rtx insn;
{
if (INSN_CODE (insn) < 0)
INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL_PTR);
return INSN_CODE (insn);
}
/* Check that X is an insn-body for an `asm' with operands
and that the operands mentioned in it are legitimate. */
int
check_asm_operands (x)
rtx x;
{
int noperands = asm_noperands (x);
rtx *operands;
int i;
if (noperands < 0)
return 0;
if (noperands == 0)
return 1;
operands = (rtx *) alloca (noperands * sizeof (rtx));
decode_asm_operands (x, operands, NULL_PTR, NULL_PTR, NULL_PTR);
for (i = 0; i < noperands; i++)
if (!general_operand (operands[i], VOIDmode))
return 0;
return 1;
}
/* Static data for the next two routines.
The maximum number of changes supported is defined as the maximum
number of operands times 5. This allows for repeated substitutions
inside complex indexed address, or, alternatively, changes in up
to 5 insns. */
#define MAX_CHANGE_LOCS (MAX_RECOG_OPERANDS * 5)
static rtx change_objects[MAX_CHANGE_LOCS];
static int change_old_codes[MAX_CHANGE_LOCS];
static rtx *change_locs[MAX_CHANGE_LOCS];
static rtx change_olds[MAX_CHANGE_LOCS];
static int num_changes = 0;
/* Validate a proposed change to OBJECT. LOC is the location in the rtl for
at which NEW will be placed. If OBJECT is zero, no validation is done,
the change is simply made.
Two types of objects are supported: If OBJECT is a MEM, memory_address_p
will be called with the address and mode as parameters. If OBJECT is
an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with
the change in place.
IN_GROUP is non-zero if this is part of a group of changes that must be
performed as a group. In that case, the changes will be stored. The
function `apply_change_group' will validate and apply the changes.
If IN_GROUP is zero, this is a single change. Try to recognize the insn
or validate the memory reference with the change applied. If the result
is not valid for the machine, suppress the change and return zero.
Otherwise, perform the change and return 1. */
int
validate_change (object, loc, new, in_group)
rtx object;
rtx *loc;
rtx new;
int in_group;
{
rtx old = *loc;
if (old == new || rtx_equal_p (old, new))
return 1;
if (num_changes >= MAX_CHANGE_LOCS
|| (in_group == 0 && num_changes != 0))
abort ();
*loc = new;
/* Save the information describing this change. */
change_objects[num_changes] = object;
change_locs[num_changes] = loc;
change_olds[num_changes] = old;
if (object && GET_CODE (object) != MEM)
{
/* Set INSN_CODE to force rerecognition of insn. Save old code in
case invalid. */
change_old_codes[num_changes] = INSN_CODE (object);
INSN_CODE (object) = -1;
}
num_changes++;
/* If we are making a group of changes, return 1. Otherwise, validate the
change group we made. */
if (in_group)
return 1;
else
return apply_change_group ();
}
/* Apply a group of changes previously issued with `validate_change'.
Return 1 if all changes are valid, zero otherwise. */
int
apply_change_group ()
{
int i;
/* The changes have been applied and all INSN_CODEs have been reset to force
rerecognition.
The changes are valid if we aren't given an object, or if we are
given a MEM and it still is a valid address, or if this is in insn
and it is recognized. In the latter case, if reload has completed,
we also require that the operands meet the constraints for
the insn. We do not allow modifying an ASM_OPERANDS after reload
has completed because verifying the constraints is too difficult. */
for (i = 0; i < num_changes; i++)
{
rtx object = change_objects[i];
if (object == 0)
continue;
if (GET_CODE (object) == MEM)
{
if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
break;
}
else if ((recog_memoized (object) < 0
&& (asm_noperands (PATTERN (object)) < 0
|| ! check_asm_operands (PATTERN (object))
|| reload_completed))
|| (reload_completed
&& (insn_extract (object),
! constrain_operands (INSN_CODE (object), 1))))
{
rtx pat = PATTERN (object);
/* Perhaps we couldn't recognize the insn because there were
extra CLOBBERs at the end. If so, try to re-recognize
without the last CLOBBER (later iterations will cause each of
them to be eliminated, in turn). But don't do this if we
have an ASM_OPERAND. */
if (GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, XVECLEN (pat, 0) - 1)) == CLOBBER
&& asm_noperands (PATTERN (object)) < 0)
{
rtx newpat;
if (XVECLEN (pat, 0) == 2)
newpat = XVECEXP (pat, 0, 0);
else
{
int j;
newpat = gen_rtx (PARALLEL, VOIDmode,
gen_rtvec (XVECLEN (pat, 0) - 1));
for (j = 0; j < XVECLEN (newpat, 0); j++)
XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
}
/* Add a new change to this group to replace the pattern
with this new pattern. Then consider this change
as having succeeded. The change we added will
cause the entire call to fail if things remain invalid.
Note that this can lose if a later change than the one
we are processing specified &XVECEXP (PATTERN (object), 0, X)
but this shouldn't occur. */
validate_change (object, &PATTERN (object), newpat, 1);
}
else if (GET_CODE (pat) == USE