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
/
genrecog.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-02-06
|
53KB
|
1,782 lines
/* Generate code from machine description to recognize rtl as insns.
Copyright (C) 1987, 1988, 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. */
/* This program is used to produce insn-recog.c, which contains
a function called `recog' plus its subroutines.
These functions contain a decision tree
that recognizes whether an rtx, the argument given to recog,
is a valid instruction.
recog returns -1 if the rtx is not valid.
If the rtx is valid, recog returns a nonnegative number
which is the insn code number for the pattern that matched.
This is the same as the order in the machine description of the
entry that matched. This number can be used as an index into various
insn_* tables, such as insn_template, insn_outfun, and insn_n_operands
(found in insn-output.c).
The third argument to recog is an optional pointer to an int.
If present, recog will accept a pattern if it matches except for
missing CLOBBER expressions at the end. In that case, the value
pointed to by the optional pointer will be set to the number of
CLOBBERs that need to be added (it should be initialized to zero by
the caller). If it is set nonzero, the caller should allocate a
PARALLEL of the appropriate size, copy the initial entries, and call
add_clobbers (found in insn-emit.c) to fill in the CLOBBERs.
This program also generates the function `split_insns',
which returns 0 if the rtl could not be split, or
it returns the split rtl in a SEQUENCE. */
#include <stdio.h>
#include "hconfig.h"
#include "rtl.h"
#include "obstack.h"
static struct obstack obstack;
struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern void free ();
extern rtx read_rtx ();
/* Data structure for a listhead of decision trees. The alternatives
to a node are kept in a doublely-linked list so we can easily add nodes
to the proper place when merging. */
struct decision_head { struct decision *first, *last; };
/* Data structure for decision tree for recognizing
legitimate instructions. */
struct decision
{
int number; /* Node number, used for labels */
char *position; /* String denoting position in pattern */
RTX_CODE code; /* Code to test for or UNKNOWN to suppress */
char ignore_code; /* If non-zero, need not test code */
char ignore_mode; /* If non-zero, need not test mode */
int veclen; /* Length of vector, if nonzero */
enum machine_mode mode; /* Machine mode of node */
char enforce_mode; /* If non-zero, test `mode' */
char retest_code, retest_mode; /* See write_tree_1 */
int test_elt_zero_int; /* Nonzero if should test XINT (rtl, 0) */
int elt_zero_int; /* Required value for XINT (rtl, 0) */
int test_elt_one_int; /* Nonzero if should test XINT (rtl, 1) */
int elt_one_int; /* Required value for XINT (rtl, 1) */
int test_elt_zero_wide; /* Nonzero if should test XWINT (rtl, 0) */
HOST_WIDE_INT elt_zero_wide; /* Required value for XWINT (rtl, 0) */
char *tests; /* If nonzero predicate to call */
int pred; /* `preds' index of predicate or -1 */
char *c_test; /* Additional test to perform */
struct decision_head success; /* Nodes to test on success */
int insn_code_number; /* Insn number matched, if success */
int num_clobbers_to_add; /* Number of CLOBBERs to be added to pattern */
struct decision *next; /* Node to test on failure */
struct decision *prev; /* Node whose failure tests us */
struct decision *afterward; /* Node to test on success, but failure of
successor nodes */
int opno; /* Operand number, if >= 0 */
int dupno; /* Number of operand to compare against */
int label_needed; /* Nonzero if label needed when writing tree */
int subroutine_number; /* Number of subroutine this node starts */
};
#define SUBROUTINE_THRESHOLD 50
static int next_subroutine_number;
/* We can write two types of subroutines: One for insn recognition and
one to split insns. This defines which type is being written. */
enum routine_type {RECOG, SPLIT};
/* Next available node number for tree nodes. */
static int next_number;
/* Next number to use as an insn_code. */
static int next_insn_code;
/* Similar, but counts all expressions in the MD file; used for
error messages. */
static int next_index;
/* Record the highest depth we ever have so we know how many variables to
allocate in each subroutine we make. */
static int max_depth;
/* This table contains a list of the rtl codes that can possibly match a
predicate defined in recog.c. The function `not_both_true' uses it to
deduce that there are no expressions that can be matches by certain pairs
of tree nodes. Also, if a predicate can match only one code, we can
hardwire that code into the node testing the predicate. */
static struct pred_table
{
char *name;
RTX_CODE codes[NUM_RTX_CODE];
} preds[]
= {{"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM}},
#ifdef PREDICATE_CODES
PREDICATE_CODES
#endif
{"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM, PLUS, MINUS, MULT}},
{"register_operand", {SUBREG, REG}},
{"scratch_operand", {SCRATCH, REG}},
{"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF}},
{"const_int_operand", {CONST_INT}},
{"const_double_operand", {CONST_INT, CONST_DOUBLE}},
{"nonimmediate_operand", {SUBREG, REG, MEM}},
{"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG}},
{"push_operand", {MEM}},
{"memory_operand", {SUBREG, MEM}},
{"indirect_operand", {SUBREG, MEM}},
{"comparison_operation", {EQ, NE, LE, LT, GE, LT, LEU, LTU, GEU, GTU}},
{"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM}}};
#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
static int try_merge_1 ();
static int no_same_mode ();
static int same_codes ();
static int same_modes ();
char *xmalloc ();
static struct decision *add_to_sequence ();
static struct decision_head merge_trees ();
static struct decision *try_merge_2 ();
static void write_subroutine ();
static void print_code ();
static void clear_codes ();
static void clear_modes ();
static void change_state ();
static void write_tree ();
static char *copystr ();
static char *concat ();
static void fatal ();
void fancy_abort ();
static void mybzero ();
static void mybcopy ();
/* Construct and return a sequence of decisions
that will recognize INSN.
TYPE says what type of routine we are recognizing (RECOG or SPLIT). */
static struct decision_head
make_insn_sequence (insn, type)
rtx insn;
enum routine_type type;
{
rtx x;
char *c_test = XSTR (insn, type == RECOG ? 2 : 1);
struct decision *last;
struct decision_head head;
if (XVECLEN (insn, type == RECOG) == 1)
x = XVECEXP (insn, type == RECOG, 0);
else
{
x = rtx_alloc (PARALLEL);
XVEC (x, 0) = XVEC (insn, type == RECOG);
PUT_MODE (x, VOIDmode);
}
last = add_to_sequence (x, &head, "");
if (c_test[0])
last->c_test = c_test;
last->insn_code_number = next_insn_code;
last->num_clobbers_to_add = 0;
/* If this is not a DEFINE_SPLIT and X is a PARALLEL, see if it ends with a
group of CLOBBERs of (hard) registers or MATCH_SCRATCHes. If so, set up
to recognize the pattern with