118334Speter/* Generate code from machine description to compute values of attributes.
290075Sobrien   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998,
3169689Skan   1999, 2000, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
418334Speter   Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
518334Speter
690075SobrienThis file is part of GCC.
718334Speter
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1218334Speter
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1718334Speter
1818334SpeterYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2218334Speter
2318334Speter/* This program handles insn attributes and the DEFINE_DELAY and
24169689Skan   DEFINE_INSN_RESERVATION definitions.
2518334Speter
2618334Speter   It produces a series of functions named `get_attr_...', one for each insn
2718334Speter   attribute.  Each of these is given the rtx for an insn and returns a member
2818334Speter   of the enum for the attribute.
2918334Speter
3018334Speter   These subroutines have the form of a `switch' on the INSN_CODE (via
3118334Speter   `recog_memoized').  Each case either returns a constant attribute value
3218334Speter   or a value that depends on tests on other attributes, the form of
3318334Speter   operands, or some random C expression (encoded with a SYMBOL_REF
3418334Speter   expression).
3518334Speter
3618334Speter   If the attribute `alternative', or a random C expression is present,
3718334Speter   `constrain_operands' is called.  If either of these cases of a reference to
3852284Sobrien   an operand is found, `extract_insn' is called.
3918334Speter
4090075Sobrien   The special attribute `length' is also recognized.  For this operand,
4118334Speter   expressions involving the address of an operand or the current insn,
4218334Speter   (address (pc)), are valid.  In this case, an initial pass is made to
4318334Speter   set all lengths that do not depend on address.  Those that do are set to
4418334Speter   the maximum length.  Then each insn that depends on an address is checked
4518334Speter   and possibly has its length changed.  The process repeats until no further
4618334Speter   changed are made.  The resulting lengths are saved for use by
4718334Speter   `get_attr_length'.
4818334Speter
4918334Speter   A special form of DEFINE_ATTR, where the expression for default value is a
5018334Speter   CONST expression, indicates an attribute that is constant for a given run
5118334Speter   of the compiler.  The subroutine generated for these attributes has no
5218334Speter   parameters as it does not depend on any particular insn.  Constant
5318334Speter   attributes are typically used to specify which variety of processor is
5418334Speter   used.
5590075Sobrien
5618334Speter   Internal attributes are defined to handle DEFINE_DELAY and
57169689Skan   DEFINE_INSN_RESERVATION.  Special routines are output for these cases.
5818334Speter
5918334Speter   This program works by keeping a list of possible values for each attribute.
6018334Speter   These include the basic attribute choices, default values for attribute, and
6118334Speter   all derived quantities.
6218334Speter
6318334Speter   As the description file is read, the definition for each insn is saved in a
6418334Speter   `struct insn_def'.   When the file reading is complete, a `struct insn_ent'
6518334Speter   is created for each insn and chained to the corresponding attribute value,
6618334Speter   either that specified, or the default.
6718334Speter
6818334Speter   An optimization phase is then run.  This simplifies expressions for each
6918334Speter   insn.  EQ_ATTR tests are resolved, whenever possible, to a test that
7018334Speter   indicates when the attribute has the specified value for the insn.  This
7118334Speter   avoids recursive calls during compilation.
7218334Speter
73169689Skan   The strategy used when processing DEFINE_DELAY definitions is to create
74169689Skan   arbitrarily complex expressions and have the optimization simplify them.
7518334Speter
7618334Speter   Once optimization is complete, any required routines and definitions
7718334Speter   will be written.
7818334Speter
7918334Speter   An optimization that is not yet implemented is to hoist the constant
8018334Speter   expressions entirely out of the routines and definitions that are written.
8118334Speter   A way to do this is to iterate over all possible combinations of values
8218334Speter   for constant attributes and generate a set of functions for that given
8318334Speter   combination.  An initialization function would be written that evaluates
8418334Speter   the attributes and installs the corresponding set of routines and
8518334Speter   definitions (each would be accessed through a pointer).
8618334Speter
8718334Speter   We use the flags in an RTX as follows:
88117395Skan   `unchanging' (ATTR_IND_SIMPLIFIED_P): This rtx is fully simplified
8918334Speter      independent of the insn code.
90117395Skan   `in_struct' (ATTR_CURR_SIMPLIFIED_P): This rtx is fully simplified
9118334Speter      for the insn code currently being processed (see optimize_attrs).
92169689Skan   `return_val' (ATTR_PERMANENT_P): This rtx is permanent and unique
93169689Skan      (see attr_rtx).  */
9418334Speter
95117395Skan#define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), unchanging))
96117395Skan#define ATTR_CURR_SIMPLIFIED_P(RTX) (RTX_FLAG((RTX), in_struct))
97169689Skan#define ATTR_PERMANENT_P(RTX) (RTX_FLAG((RTX), return_val))
98117395Skan
99132718Skan#if 0
100132718Skan#define strcmp_check(S1, S2) ((S1) == (S2)		\
101132718Skan			      ? 0			\
102169689Skan			      : (gcc_assert (strcmp ((S1), (S2))), 1))
103132718Skan#else
104132718Skan#define strcmp_check(S1, S2) ((S1) != (S2))
105132718Skan#endif
106132718Skan
107132718Skan#include "bconfig.h"
10850397Sobrien#include "system.h"
109132718Skan#include "coretypes.h"
110132718Skan#include "tm.h"
11118334Speter#include "rtl.h"
11290075Sobrien#include "gensupport.h"
11318334Speter#include "obstack.h"
11490075Sobrien#include "errors.h"
11518334Speter
116169689Skan/* Flags for make_internal_attr's `special' parameter.  */
117169689Skan#define ATTR_NONE		0
118169689Skan#define ATTR_SPECIAL		(1 << 0)
119117395Skan
12090075Sobrienstatic struct obstack obstack1, obstack2;
121169689Skanstatic struct obstack *hash_obstack = &obstack1;
122169689Skanstatic struct obstack *temp_obstack = &obstack2;
12318334Speter
12418334Speter/* enough space to reserve for printing out ints */
12518334Speter#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
12618334Speter
12718334Speter/* Define structures used to record attributes and values.  */
12818334Speter
12918334Speter/* As each DEFINE_INSN, DEFINE_PEEPHOLE, or DEFINE_ASM_ATTRIBUTES is
13018334Speter   encountered, we store all the relevant information into a
13118334Speter   `struct insn_def'.  This is done to allow attribute definitions to occur
13218334Speter   anywhere in the file.  */
13318334Speter
13418334Speterstruct insn_def
13518334Speter{
13690075Sobrien  struct insn_def *next;	/* Next insn in chain.  */
13790075Sobrien  rtx def;			/* The DEFINE_...  */
13850397Sobrien  int insn_code;		/* Instruction number.  */
13950397Sobrien  int insn_index;		/* Expression numer in file, for errors.  */
14090075Sobrien  int lineno;			/* Line number.  */
14118334Speter  int num_alternatives;		/* Number of alternatives.  */
14250397Sobrien  int vec_idx;			/* Index of attribute vector in `def'.  */
14318334Speter};
14418334Speter
14518334Speter/* Once everything has been read in, we store in each attribute value a list
14618334Speter   of insn codes that have that value.  Here is the structure used for the
14718334Speter   list.  */
14818334Speter
14918334Speterstruct insn_ent
15018334Speter{
15190075Sobrien  struct insn_ent *next;	/* Next in chain.  */
152169689Skan  struct insn_def *def;		/* Instruction definition.  */
15318334Speter};
15418334Speter
15518334Speter/* Each value of an attribute (either constant or computed) is assigned a
15618334Speter   structure which is used as the listhead of the insns that have that
15718334Speter   value.  */
15818334Speter
15918334Speterstruct attr_value
16018334Speter{
16118334Speter  rtx value;			/* Value of attribute.  */
16218334Speter  struct attr_value *next;	/* Next attribute value in chain.  */
16318334Speter  struct insn_ent *first_insn;	/* First insn with this value.  */
16418334Speter  int num_insns;		/* Number of insns with this value.  */
16518334Speter  int has_asm_insn;		/* True if this value used for `asm' insns */
16618334Speter};
16718334Speter
16818334Speter/* Structure for each attribute.  */
16918334Speter
17018334Speterstruct attr_desc
17118334Speter{
17250397Sobrien  char *name;			/* Name of attribute.  */
17350397Sobrien  struct attr_desc *next;	/* Next attribute.  */
174132718Skan  struct attr_value *first_value; /* First value of this attribute.  */
175132718Skan  struct attr_value *default_val; /* Default value for this attribute.  */
176132718Skan  int lineno : 24;		/* Line number.  */
17750397Sobrien  unsigned is_numeric	: 1;	/* Values of this attribute are numeric.  */
17850397Sobrien  unsigned is_const	: 1;	/* Attribute value constant for each run.  */
17950397Sobrien  unsigned is_special	: 1;	/* Don't call `write_attr_set'.  */
18018334Speter};
18118334Speter
18218334Speter/* Structure for each DEFINE_DELAY.  */
18318334Speter
18418334Speterstruct delay_desc
18518334Speter{
18618334Speter  rtx def;			/* DEFINE_DELAY expression.  */
18750397Sobrien  struct delay_desc *next;	/* Next DEFINE_DELAY.  */
18818334Speter  int num;			/* Number of DEFINE_DELAY, starting at 1.  */
18990075Sobrien  int lineno;			/* Line number.  */
19018334Speter};
19118334Speter
19218334Speter/* Listheads of above structures.  */
19318334Speter
19418334Speter/* This one is indexed by the first character of the attribute name.  */
19518334Speter#define MAX_ATTRS_INDEX 256
19618334Speterstatic struct attr_desc *attrs[MAX_ATTRS_INDEX];
19718334Speterstatic struct insn_def *defs;
19818334Speterstatic struct delay_desc *delays;
19918334Speter
20050397Sobrien/* Other variables.  */
20118334Speter
20218334Speterstatic int insn_code_number;
20318334Speterstatic int insn_index_number;
20418334Speterstatic int got_define_asm_attributes;
20518334Speterstatic int must_extract;
20618334Speterstatic int must_constrain;
20718334Speterstatic int address_used;
20818334Speterstatic int length_used;
20918334Speterstatic int num_delays;
21018334Speterstatic int have_annul_true, have_annul_false;
21118334Speterstatic int num_insn_ents;
21218334Speter
21318334Speter/* Stores, for each insn code, the number of constraint alternatives.  */
21418334Speter
21518334Speterstatic int *insn_n_alternatives;
21618334Speter
21718334Speter/* Stores, for each insn code, a bitmap that has bits on for each possible
21818334Speter   alternative.  */
21918334Speter
22018334Speterstatic int *insn_alternatives;
22118334Speter
22218334Speter/* Used to simplify expressions.  */
22318334Speter
22418334Speterstatic rtx true_rtx, false_rtx;
22518334Speter
22618334Speter/* Used to reduce calls to `strcmp' */
22718334Speter
228169689Skanstatic const char *alternative_name;
229132718Skanstatic const char *length_str;
230132718Skanstatic const char *delay_type_str;
231132718Skanstatic const char *delay_1_0_str;
232132718Skanstatic const char *num_delay_slots_str;
23318334Speter
23418334Speter/* Simplify an expression.  Only call the routine if there is something to
23518334Speter   simplify.  */
23618334Speter#define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX)	\
237117395Skan  (ATTR_IND_SIMPLIFIED_P (EXP) || ATTR_CURR_SIMPLIFIED_P (EXP) ? (EXP)	\
23818334Speter   : simplify_test_exp (EXP, INSN_CODE, INSN_INDEX))
23990075Sobrien
240132718Skan#define DEF_ATTR_STRING(S) (attr_string ((S), strlen (S)))
241132718Skan
242169689Skan/* Forward declarations of functions used before their definitions, only.  */
243169689Skanstatic char *attr_string           (const char *, int);
244169689Skanstatic char *attr_printf           (unsigned int, const char *, ...)
245169689Skan  ATTRIBUTE_PRINTF_2;
246169689Skanstatic rtx make_numeric_value      (int);
247169689Skanstatic struct attr_desc *find_attr (const char **, int);
248169689Skanstatic rtx mk_attr_alt             (int);
249169689Skanstatic char *next_comma_elt	   (const char **);
250169689Skanstatic rtx insert_right_side	   (enum rtx_code, rtx, rtx, int, int);
251169689Skanstatic rtx copy_boolean		   (rtx);
252169689Skanstatic int compares_alternatives_p (rtx);
253169689Skanstatic void make_internal_attr     (const char *, rtx, int);
254169689Skanstatic void insert_insn_ent        (struct attr_value *, struct insn_ent *);
255169689Skanstatic void walk_attr_value	   (rtx);
256169689Skanstatic int max_attr_value	   (rtx, int*);
257169689Skanstatic int min_attr_value	   (rtx, int*);
258169689Skanstatic int or_attr_value	   (rtx, int*);
259169689Skanstatic rtx simplify_test_exp	   (rtx, int, int);
260132718Skanstatic rtx simplify_test_exp_in_temp (rtx, int, int);
261169689Skanstatic rtx copy_rtx_unchanging	   (rtx);
262169689Skanstatic bool attr_alt_subset_p      (rtx, rtx);
263169689Skanstatic bool attr_alt_subset_of_compl_p (rtx, rtx);
264169689Skanstatic void clear_struct_flag      (rtx);
265169689Skanstatic void write_attr_valueq	   (struct attr_desc *, const char *);
266132718Skanstatic struct attr_value *find_most_used  (struct attr_desc *);
267169689Skanstatic void write_attr_set	   (struct attr_desc *, int, rtx,
268169689Skan				    const char *, const char *, rtx,
269169689Skan				    int, int);
270169689Skanstatic void write_attr_case	   (struct attr_desc *, struct attr_value *,
271169689Skan				    int, const char *, const char *, int, rtx);
272169689Skanstatic void write_attr_value	   (struct attr_desc *, rtx);
273169689Skanstatic void write_upcase	   (const char *);
274169689Skanstatic void write_indent	   (int);
275169689Skanstatic rtx identity_fn		   (rtx);
276169689Skanstatic rtx zero_fn		   (rtx);
277169689Skanstatic rtx one_fn		   (rtx);
278169689Skanstatic rtx max_fn		   (rtx);
279169689Skanstatic rtx min_fn		   (rtx);
28018334Speter
28118334Speter#define oballoc(size) obstack_alloc (hash_obstack, size)
282132718Skan
28318334Speter/* Hash table for sharing RTL and strings.  */
28418334Speter
28518334Speter/* Each hash table slot is a bucket containing a chain of these structures.
28618334Speter   Strings are given negative hash codes; RTL expressions are given positive
28718334Speter   hash codes.  */
28818334Speter
28918334Speterstruct attr_hash
29018334Speter{
29118334Speter  struct attr_hash *next;	/* Next structure in the bucket.  */
29218334Speter  int hashcode;			/* Hash code of this rtx or string.  */
29318334Speter  union
29418334Speter    {
29518334Speter      char *str;		/* The string (negative hash codes) */
29618334Speter      rtx rtl;			/* or the RTL recorded here.  */
29718334Speter    } u;
29818334Speter};
29918334Speter
30018334Speter/* Now here is the hash table.  When recording an RTL, it is added to
30118334Speter   the slot whose index is the hash code mod the table size.  Note
30218334Speter   that the hash table is used for several kinds of RTL (see attr_rtx)
30318334Speter   and for strings.  While all these live in the same table, they are
30418334Speter   completely independent, and the hash code is computed differently
30518334Speter   for each.  */
30618334Speter
30718334Speter#define RTL_HASH_SIZE 4093
308169689Skanstatic struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
30918334Speter
31018334Speter/* Here is how primitive or already-shared RTL's hash
31118334Speter   codes are made.  */
31250397Sobrien#define RTL_HASH(RTL) ((long) (RTL) & 0777777)
31318334Speter
31418334Speter/* Add an entry to the hash table for RTL with hash code HASHCODE.  */
31518334Speter
31618334Speterstatic void
317132718Skanattr_hash_add_rtx (int hashcode, rtx rtl)
31818334Speter{
31990075Sobrien  struct attr_hash *h;
32018334Speter
321132718Skan  h = obstack_alloc (hash_obstack, sizeof (struct attr_hash));
32218334Speter  h->hashcode = hashcode;
32318334Speter  h->u.rtl = rtl;
32418334Speter  h->next = attr_hash_table[hashcode % RTL_HASH_SIZE];
32518334Speter  attr_hash_table[hashcode % RTL_HASH_SIZE] = h;
32618334Speter}
32718334Speter
32818334Speter/* Add an entry to the hash table for STRING with hash code HASHCODE.  */
32918334Speter
33018334Speterstatic void
331132718Skanattr_hash_add_string (int hashcode, char *str)
33218334Speter{
33390075Sobrien  struct attr_hash *h;
33418334Speter
335132718Skan  h = obstack_alloc (hash_obstack, sizeof (struct attr_hash));
33618334Speter  h->hashcode = -hashcode;
33718334Speter  h->u.str = str;
33818334Speter  h->next = attr_hash_table[hashcode % RTL_HASH_SIZE];
33918334Speter  attr_hash_table[hashcode % RTL_HASH_SIZE] = h;
34018334Speter}
34118334Speter
34218334Speter/* Generate an RTL expression, but avoid duplicates.
343117395Skan   Set the ATTR_PERMANENT_P flag for these permanent objects.
34418334Speter
34518334Speter   In some cases we cannot uniquify; then we return an ordinary
346117395Skan   impermanent rtx with ATTR_PERMANENT_P clear.
34718334Speter
348169689Skan   Args are as follows:
34918334Speter
35018334Speter   rtx attr_rtx (code, [element1, ..., elementn])  */
35118334Speter
35218334Speterstatic rtx
353132718Skanattr_rtx_1 (enum rtx_code code, va_list p)
35418334Speter{
35590075Sobrien  rtx rt_val = NULL_RTX;/* RTX to return to caller...		*/
35618334Speter  int hashcode;
35790075Sobrien  struct attr_hash *h;
35818334Speter  struct obstack *old_obstack = rtl_obstack;
35918334Speter
36018334Speter  /* For each of several cases, search the hash table for an existing entry.
36118334Speter     Use that entry if one is found; otherwise create a new RTL and add it
36218334Speter     to the table.  */
36318334Speter
364169689Skan  if (GET_RTX_CLASS (code) == RTX_UNARY)
36518334Speter    {
36618334Speter      rtx arg0 = va_arg (p, rtx);
36718334Speter
36818334Speter      /* A permanent object cannot point to impermanent ones.  */
369117395Skan      if (! ATTR_PERMANENT_P (arg0))
37018334Speter	{
37118334Speter	  rt_val = rtx_alloc (code);
37218334Speter	  XEXP (rt_val, 0) = arg0;
37318334Speter	  return rt_val;
37418334Speter	}
37518334Speter
37618334Speter      hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
37718334Speter      for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
37818334Speter	if (h->hashcode == hashcode
37918334Speter	    && GET_CODE (h->u.rtl) == code
38018334Speter	    && XEXP (h->u.rtl, 0) == arg0)
38190075Sobrien	  return h->u.rtl;
38218334Speter
38318334Speter      if (h == 0)
38418334Speter	{
38518334Speter	  rtl_obstack = hash_obstack;
38618334Speter	  rt_val = rtx_alloc (code);
38718334Speter	  XEXP (rt_val, 0) = arg0;
38818334Speter	}
38918334Speter    }
390169689Skan  else if (GET_RTX_CLASS (code) == RTX_BIN_ARITH
391169689Skan  	   || GET_RTX_CLASS (code) == RTX_COMM_ARITH
392169689Skan  	   || GET_RTX_CLASS (code) == RTX_COMPARE
393169689Skan  	   || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
39418334Speter    {
39518334Speter      rtx arg0 = va_arg (p, rtx);
39618334Speter      rtx arg1 = va_arg (p, rtx);
39718334Speter
39818334Speter      /* A permanent object cannot point to impermanent ones.  */
399117395Skan      if (! ATTR_PERMANENT_P (arg0) || ! ATTR_PERMANENT_P (arg1))
40018334Speter	{
40118334Speter	  rt_val = rtx_alloc (code);
40218334Speter	  XEXP (rt_val, 0) = arg0;
40318334Speter	  XEXP (rt_val, 1) = arg1;
40418334Speter	  return rt_val;
40518334Speter	}
40618334Speter
40718334Speter      hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
40818334Speter      for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
40918334Speter	if (h->hashcode == hashcode
41018334Speter	    && GET_CODE (h->u.rtl) == code
41118334Speter	    && XEXP (h->u.rtl, 0) == arg0
41218334Speter	    && XEXP (h->u.rtl, 1) == arg1)
41390075Sobrien	  return h->u.rtl;
41418334Speter
41518334Speter      if (h == 0)
41618334Speter	{
41718334Speter	  rtl_obstack = hash_obstack;
41818334Speter	  rt_val = rtx_alloc (code);
41918334Speter	  XEXP (rt_val, 0) = arg0;
42018334Speter	  XEXP (rt_val, 1) = arg1;
42118334Speter	}
42218334Speter    }
42318334Speter  else if (GET_RTX_LENGTH (code) == 1
42418334Speter	   && GET_RTX_FORMAT (code)[0] == 's')
42518334Speter    {
42690075Sobrien      char *arg0 = va_arg (p, char *);
42718334Speter
428132718Skan      arg0 = DEF_ATTR_STRING (arg0);
42918334Speter
43018334Speter      hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0));
43118334Speter      for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
43218334Speter	if (h->hashcode == hashcode
43318334Speter	    && GET_CODE (h->u.rtl) == code
43418334Speter	    && XSTR (h->u.rtl, 0) == arg0)
43590075Sobrien	  return h->u.rtl;
43618334Speter
43718334Speter      if (h == 0)
43818334Speter	{
43918334Speter	  rtl_obstack = hash_obstack;
44018334Speter	  rt_val = rtx_alloc (code);
44118334Speter	  XSTR (rt_val, 0) = arg0;
44218334Speter	}
44318334Speter    }
44418334Speter  else if (GET_RTX_LENGTH (code) == 2
44518334Speter	   && GET_RTX_FORMAT (code)[0] == 's'
44618334Speter	   && GET_RTX_FORMAT (code)[1] == 's')
44718334Speter    {
44818334Speter      char *arg0 = va_arg (p, char *);
44918334Speter      char *arg1 = va_arg (p, char *);
45018334Speter
45118334Speter      hashcode = ((HOST_WIDE_INT) code + RTL_HASH (arg0) + RTL_HASH (arg1));
45218334Speter      for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
45318334Speter	if (h->hashcode == hashcode
45418334Speter	    && GET_CODE (h->u.rtl) == code
45518334Speter	    && XSTR (h->u.rtl, 0) == arg0
45618334Speter	    && XSTR (h->u.rtl, 1) == arg1)
45790075Sobrien	  return h->u.rtl;
45818334Speter
45918334Speter      if (h == 0)
46018334Speter	{
46118334Speter	  rtl_obstack = hash_obstack;
46218334Speter	  rt_val = rtx_alloc (code);
46318334Speter	  XSTR (rt_val, 0) = arg0;
46418334Speter	  XSTR (rt_val, 1) = arg1;
46518334Speter	}
46618334Speter    }
46718334Speter  else if (code == CONST_INT)
46818334Speter    {
46918334Speter      HOST_WIDE_INT arg0 = va_arg (p, HOST_WIDE_INT);
47018334Speter      if (arg0 == 0)
47118334Speter	return false_rtx;
47290075Sobrien      else if (arg0 == 1)
47318334Speter	return true_rtx;
47490075Sobrien      else
47590075Sobrien	goto nohash;
47618334Speter    }
47718334Speter  else
47818334Speter    {
47990075Sobrien      int i;		/* Array indices...			*/
48090075Sobrien      const char *fmt;	/* Current rtx's format...		*/
48118334Speter    nohash:
48218334Speter      rt_val = rtx_alloc (code);	/* Allocate the storage space.  */
48390075Sobrien
48418334Speter      fmt = GET_RTX_FORMAT (code);	/* Find the right format...  */
48518334Speter      for (i = 0; i < GET_RTX_LENGTH (code); i++)
48618334Speter	{
48718334Speter	  switch (*fmt++)
48818334Speter	    {
48918334Speter	    case '0':		/* Unused field.  */
49018334Speter	      break;
49118334Speter
49218334Speter	    case 'i':		/* An integer?  */
49318334Speter	      XINT (rt_val, i) = va_arg (p, int);
49418334Speter	      break;
49518334Speter
49618334Speter	    case 'w':		/* A wide integer? */
49718334Speter	      XWINT (rt_val, i) = va_arg (p, HOST_WIDE_INT);
49818334Speter	      break;
49918334Speter
50018334Speter	    case 's':		/* A string?  */
50118334Speter	      XSTR (rt_val, i) = va_arg (p, char *);
50218334Speter	      break;
50318334Speter
50418334Speter	    case 'e':		/* An expression?  */
50518334Speter	    case 'u':		/* An insn?  Same except when printing.  */
50618334Speter	      XEXP (rt_val, i) = va_arg (p, rtx);
50718334Speter	      break;
50818334Speter
50918334Speter	    case 'E':		/* An RTX vector?  */
51018334Speter	      XVEC (rt_val, i) = va_arg (p, rtvec);
51118334Speter	      break;
51218334Speter
51318334Speter	    default:
514169689Skan	      gcc_unreachable ();
51518334Speter	    }
51618334Speter	}
51718334Speter      return rt_val;
51818334Speter    }
51918334Speter
52018334Speter  rtl_obstack = old_obstack;
52118334Speter  attr_hash_add_rtx (hashcode, rt_val);
522117395Skan  ATTR_PERMANENT_P (rt_val) = 1;
52318334Speter  return rt_val;
52490075Sobrien}
52518334Speter
52690075Sobrienstatic rtx
527132718Skanattr_rtx (enum rtx_code code, ...)
52890075Sobrien{
52990075Sobrien  rtx result;
530132718Skan  va_list p;
531132718Skan
532132718Skan  va_start (p, code);
53390075Sobrien  result = attr_rtx_1 (code, p);
534132718Skan  va_end (p);
53590075Sobrien  return result;
53618334Speter}
53718334Speter
53818334Speter/* Create a new string printed with the printf line arguments into a space
53918334Speter   of at most LEN bytes:
54018334Speter
54118334Speter   rtx attr_printf (len, format, [arg1, ..., argn])  */
54218334Speter
543169689Skanstatic char *
544132718Skanattr_printf (unsigned int len, const char *fmt, ...)
54518334Speter{
54690075Sobrien  char str[256];
547132718Skan  va_list p;
54818334Speter
549132718Skan  va_start (p, fmt);
550132718Skan
551169689Skan  gcc_assert (len < sizeof str); /* Leave room for \0.  */
55218334Speter
55318334Speter  vsprintf (str, fmt, p);
554132718Skan  va_end (p);
55518334Speter
556132718Skan  return DEF_ATTR_STRING (str);
55718334Speter}
55818334Speter
55990075Sobrienstatic rtx
560132718Skanattr_eq (const char *name, const char *value)
56118334Speter{
562132718Skan  return attr_rtx (EQ_ATTR, DEF_ATTR_STRING (name), DEF_ATTR_STRING (value));
56318334Speter}
56418334Speter
56590075Sobrienstatic const char *
566132718Skanattr_numeral (int n)
56718334Speter{
56818334Speter  return XSTR (make_numeric_value (n), 0);
56918334Speter}
57018334Speter
57118334Speter/* Return a permanent (possibly shared) copy of a string STR (not assumed
57218334Speter   to be null terminated) with LEN bytes.  */
57318334Speter
57418334Speterstatic char *
575132718Skanattr_string (const char *str, int len)
57618334Speter{
57790075Sobrien  struct attr_hash *h;
57818334Speter  int hashcode;
57918334Speter  int i;
58090075Sobrien  char *new_str;
58118334Speter
58218334Speter  /* Compute the hash code.  */
58390075Sobrien  hashcode = (len + 1) * 613 + (unsigned) str[0];
584169689Skan  for (i = 1; i < len; i += 2)
58590075Sobrien    hashcode = ((hashcode * 613) + (unsigned) str[i]);
58618334Speter  if (hashcode < 0)
58718334Speter    hashcode = -hashcode;
58818334Speter
58918334Speter  /* Search the table for the string.  */
59018334Speter  for (h = attr_hash_table[hashcode % RTL_HASH_SIZE]; h; h = h->next)
59118334Speter    if (h->hashcode == -hashcode && h->u.str[0] == str[0]
59218334Speter	&& !strncmp (h->u.str, str, len))
59318334Speter      return h->u.str;			/* <-- return if found.  */
59418334Speter
59518334Speter  /* Not found; create a permanent copy and add it to the hash table.  */
596132718Skan  new_str = obstack_alloc (hash_obstack, len + 1);
59790075Sobrien  memcpy (new_str, str, len);
59818334Speter  new_str[len] = '\0';
59918334Speter  attr_hash_add_string (hashcode, new_str);
60018334Speter
60118334Speter  return new_str;			/* Return the new string.  */
60218334Speter}
60318334Speter
60418334Speter/* Check two rtx's for equality of contents,
60518334Speter   taking advantage of the fact that if both are hashed
60618334Speter   then they can't be equal unless they are the same object.  */
60718334Speter
60890075Sobrienstatic int
609132718Skanattr_equal_p (rtx x, rtx y)
61018334Speter{
611117395Skan  return (x == y || (! (ATTR_PERMANENT_P (x) && ATTR_PERMANENT_P (y))
61218334Speter		     && rtx_equal_p (x, y)));
61318334Speter}
614132718Skan
61518334Speter/* Copy an attribute value expression,
61618334Speter   descending to all depths, but not copying any
61718334Speter   permanent hashed subexpressions.  */
61818334Speter
61990075Sobrienstatic rtx
620132718Skanattr_copy_rtx (rtx orig)
62118334Speter{
62290075Sobrien  rtx copy;
62390075Sobrien  int i, j;
62490075Sobrien  RTX_CODE code;
62590075Sobrien  const char *format_ptr;
62618334Speter
62718334Speter  /* No need to copy a permanent object.  */
628117395Skan  if (ATTR_PERMANENT_P (orig))
62918334Speter    return orig;
63018334Speter
63118334Speter  code = GET_CODE (orig);
63218334Speter
63318334Speter  switch (code)
63418334Speter    {
63518334Speter    case REG:
63618334Speter    case CONST_INT:
63718334Speter    case CONST_DOUBLE:
63896263Sobrien    case CONST_VECTOR:
63918334Speter    case SYMBOL_REF:
64018334Speter    case CODE_LABEL:
64118334Speter    case PC:
64218334Speter    case CC0:
64318334Speter      return orig;
64450397Sobrien
64550397Sobrien    default:
64650397Sobrien      break;
64718334Speter    }
64818334Speter
64918334Speter  copy = rtx_alloc (code);
65018334Speter  PUT_MODE (copy, GET_MODE (orig));
651117395Skan  ATTR_IND_SIMPLIFIED_P (copy) = ATTR_IND_SIMPLIFIED_P (orig);
652117395Skan  ATTR_CURR_SIMPLIFIED_P (copy) = ATTR_CURR_SIMPLIFIED_P (orig);
653117395Skan  ATTR_PERMANENT_P (copy) = ATTR_PERMANENT_P (orig);
65490075Sobrien
65518334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
65618334Speter
65718334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
65818334Speter    {
65918334Speter      switch (*format_ptr++)
66018334Speter	{
66118334Speter	case 'e':
66218334Speter	  XEXP (copy, i) = XEXP (orig, i);
66318334Speter	  if (XEXP (orig, i) != NULL)
66418334Speter	    XEXP (copy, i) = attr_copy_rtx (XEXP (orig, i));
66518334Speter	  break;
66618334Speter
66718334Speter	case 'E':
66818334Speter	case 'V':
66918334Speter	  XVEC (copy, i) = XVEC (orig, i);
67018334Speter	  if (XVEC (orig, i) != NULL)
67118334Speter	    {
67218334Speter	      XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
67318334Speter	      for (j = 0; j < XVECLEN (copy, i); j++)
67418334Speter		XVECEXP (copy, i, j) = attr_copy_rtx (XVECEXP (orig, i, j));
67518334Speter	    }
67618334Speter	  break;
67718334Speter
67818334Speter	case 'n':
67918334Speter	case 'i':
68018334Speter	  XINT (copy, i) = XINT (orig, i);
68118334Speter	  break;
68218334Speter
68318334Speter	case 'w':
68418334Speter	  XWINT (copy, i) = XWINT (orig, i);
68518334Speter	  break;
68618334Speter
68718334Speter	case 's':
68818334Speter	case 'S':
68918334Speter	  XSTR (copy, i) = XSTR (orig, i);
69018334Speter	  break;
69118334Speter
69218334Speter	default:
693169689Skan	  gcc_unreachable ();
69418334Speter	}
69518334Speter    }
69618334Speter  return copy;
69718334Speter}
698132718Skan
69918334Speter/* Given a test expression for an attribute, ensure it is validly formed.
70018334Speter   IS_CONST indicates whether the expression is constant for each compiler
70118334Speter   run (a constant expression may not test any particular insn).
70218334Speter
70318334Speter   Convert (eq_attr "att" "a1,a2") to (ior (eq_attr ... ) (eq_attrq ..))
70418334Speter   and (eq_attr "att" "!a1") to (not (eq_attr "att" "a1")).  Do the latter
70518334Speter   test first so that (eq_attr "att" "!a1,a2,a3") works as expected.
70618334Speter
70718334Speter   Update the string address in EQ_ATTR expression to be the same used
70818334Speter   in the attribute (or `alternative_name') to speed up subsequent
70918334Speter   `find_attr' calls and eliminate most `strcmp' calls.
71018334Speter
71190075Sobrien   Return the new expression, if any.  */
71218334Speter
713169689Skanstatic rtx
714132718Skancheck_attr_test (rtx exp, int is_const, int lineno)
71518334Speter{
71618334Speter  struct attr_desc *attr;
71718334Speter  struct attr_value *av;
71890075Sobrien  const char *name_ptr, *p;
71918334Speter  rtx orexp, newexp;
72018334Speter
72118334Speter  switch (GET_CODE (exp))
72218334Speter    {
72318334Speter    case EQ_ATTR:
72418334Speter      /* Handle negation test.  */
72518334Speter      if (XSTR (exp, 1)[0] == '!')
72618334Speter	return check_attr_test (attr_rtx (NOT,
72718334Speter					  attr_eq (XSTR (exp, 0),
72818334Speter						   &XSTR (exp, 1)[1])),
72990075Sobrien				is_const, lineno);
73018334Speter
73118334Speter      else if (n_comma_elts (XSTR (exp, 1)) == 1)
73218334Speter	{
733132718Skan	  attr = find_attr (&XSTR (exp, 0), 0);
73418334Speter	  if (attr == NULL)
73518334Speter	    {
73618334Speter	      if (! strcmp (XSTR (exp, 0), "alternative"))
737132718Skan		return mk_attr_alt (1 << atoi (XSTR (exp, 1)));
73818334Speter	      else
73990075Sobrien		fatal ("unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
74018334Speter	    }
74118334Speter
74218334Speter	  if (is_const && ! attr->is_const)
74390075Sobrien	    fatal ("constant expression uses insn attribute `%s' in EQ_ATTR",
74450397Sobrien		   XSTR (exp, 0));
74518334Speter
74618334Speter	  /* Copy this just to make it permanent,
74718334Speter	     so expressions using it can be permanent too.  */
74818334Speter	  exp = attr_eq (XSTR (exp, 0), XSTR (exp, 1));
74918334Speter
75018334Speter	  /* It shouldn't be possible to simplify the value given to a
75118334Speter	     constant attribute, so don't expand this until it's time to
75290075Sobrien	     write the test expression.  */
75318334Speter	  if (attr->is_const)
754117395Skan	    ATTR_IND_SIMPLIFIED_P (exp) = 1;
75518334Speter
75618334Speter	  if (attr->is_numeric)
75718334Speter	    {
75818334Speter	      for (p = XSTR (exp, 1); *p; p++)
75990075Sobrien		if (! ISDIGIT (*p))
76090075Sobrien		  fatal ("attribute `%s' takes only numeric values",
76190075Sobrien			 XSTR (exp, 0));
76218334Speter	    }
76318334Speter	  else
76418334Speter	    {
76518334Speter	      for (av = attr->first_value; av; av = av->next)
76618334Speter		if (GET_CODE (av->value) == CONST_STRING
76718334Speter		    && ! strcmp (XSTR (exp, 1), XSTR (av->value, 0)))
76818334Speter		  break;
76918334Speter
77018334Speter	      if (av == NULL)
77190075Sobrien		fatal ("unknown value `%s' for `%s' attribute",
77250397Sobrien		       XSTR (exp, 1), XSTR (exp, 0));
77318334Speter	    }
77418334Speter	}
77518334Speter      else
77618334Speter	{
777132718Skan	  if (! strcmp (XSTR (exp, 0), "alternative"))
77818334Speter	    {
779132718Skan	      int set = 0;
780132718Skan
781132718Skan	      name_ptr = XSTR (exp, 1);
782132718Skan	      while ((p = next_comma_elt (&name_ptr)) != NULL)
783132718Skan		set |= 1 << atoi (p);
784132718Skan
785132718Skan	      return mk_attr_alt (set);
78618334Speter	    }
787132718Skan	  else
788132718Skan	    {
789132718Skan	      /* Make an IOR tree of the possible values.  */
790132718Skan	      orexp = false_rtx;
791132718Skan	      name_ptr = XSTR (exp, 1);
792132718Skan	      while ((p = next_comma_elt (&name_ptr)) != NULL)
793132718Skan		{
794132718Skan		  newexp = attr_eq (XSTR (exp, 0), p);
795132718Skan		  orexp = insert_right_side (IOR, orexp, newexp, -2, -2);
796132718Skan		}
79718334Speter
798132718Skan	      return check_attr_test (orexp, is_const, lineno);
799132718Skan	    }
80018334Speter	}
80118334Speter      break;
80218334Speter
80318334Speter    case ATTR_FLAG:
80418334Speter      break;
80518334Speter
80618334Speter    case CONST_INT:
80718334Speter      /* Either TRUE or FALSE.  */
80818334Speter      if (XWINT (exp, 0))
80918334Speter	return true_rtx;
81018334Speter      else
81118334Speter	return false_rtx;
81218334Speter
81318334Speter    case IOR:
81418334Speter    case AND:
81590075Sobrien      XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
81690075Sobrien      XEXP (exp, 1) = check_attr_test (XEXP (exp, 1), is_const, lineno);
81718334Speter      break;
81818334Speter
81918334Speter    case NOT:
82090075Sobrien      XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const, lineno);
82118334Speter      break;
82218334Speter
82318334Speter    case MATCH_OPERAND:
82418334Speter      if (is_const)
82518334Speter	fatal ("RTL operator \"%s\" not valid in constant attribute test",
82650397Sobrien	       GET_RTX_NAME (GET_CODE (exp)));
82718334Speter      /* These cases can't be simplified.  */
828117395Skan      ATTR_IND_SIMPLIFIED_P (exp) = 1;
82918334Speter      break;
83090075Sobrien
83118334Speter    case LE:  case LT:  case GT:  case GE:
83218334Speter    case LEU: case LTU: case GTU: case GEU:
83318334Speter    case NE:  case EQ:
83418334Speter      if (GET_CODE (XEXP (exp, 0)) == SYMBOL_REF
83518334Speter	  && GET_CODE (XEXP (exp, 1)) == SYMBOL_REF)
83618334Speter	exp = attr_rtx (GET_CODE (exp),
83718334Speter			attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 0), 0)),
83818334Speter			attr_rtx (SYMBOL_REF, XSTR (XEXP (exp, 1), 0)));
83918334Speter      /* These cases can't be simplified.  */
840117395Skan      ATTR_IND_SIMPLIFIED_P (exp) = 1;
84118334Speter      break;
84218334Speter
84318334Speter    case SYMBOL_REF:
84418334Speter      if (is_const)
84518334Speter	{
84618334Speter	  /* These cases are valid for constant attributes, but can't be
84718334Speter	     simplified.  */
84818334Speter	  exp = attr_rtx (SYMBOL_REF, XSTR (exp, 0));
849117395Skan	  ATTR_IND_SIMPLIFIED_P (exp) = 1;
85018334Speter	  break;
85118334Speter	}
85218334Speter    default:
85318334Speter      fatal ("RTL operator \"%s\" not valid in attribute test",
85418334Speter	     GET_RTX_NAME (GET_CODE (exp)));
85518334Speter    }
85618334Speter
85718334Speter  return exp;
85818334Speter}
859132718Skan
86018334Speter/* Given an expression, ensure that it is validly formed and that all named
86118334Speter   attribute values are valid for the given attribute.  Issue a fatal error
86218334Speter   if not.  If no attribute is specified, assume a numeric attribute.
86318334Speter
86418334Speter   Return a perhaps modified replacement expression for the value.  */
86518334Speter
86618334Speterstatic rtx
867132718Skancheck_attr_value (rtx exp, struct attr_desc *attr)
86818334Speter{
86918334Speter  struct attr_value *av;
87090075Sobrien  const char *p;
87118334Speter  int i;
87218334Speter
87318334Speter  switch (GET_CODE (exp))
87418334Speter    {
87518334Speter    case CONST_INT:
87618334Speter      if (attr && ! attr->is_numeric)
87790075Sobrien	{
87890075Sobrien	  message_with_line (attr->lineno,
87990075Sobrien			     "CONST_INT not valid for non-numeric attribute %s",
88090075Sobrien			     attr->name);
88190075Sobrien	  have_error = 1;
88290075Sobrien	  break;
88390075Sobrien	}
88418334Speter
885169689Skan      if (INTVAL (exp) < 0)
88690075Sobrien	{
88790075Sobrien	  message_with_line (attr->lineno,
88890075Sobrien			     "negative numeric value specified for attribute %s",
88990075Sobrien			     attr->name);
89090075Sobrien	  have_error = 1;
89190075Sobrien	  break;
89290075Sobrien	}
89318334Speter      break;
89418334Speter
89518334Speter    case CONST_STRING:
89618334Speter      if (! strcmp (XSTR (exp, 0), "*"))
89718334Speter	break;
89818334Speter
89918334Speter      if (attr == 0 || attr->is_numeric)
90018334Speter	{
90118334Speter	  p = XSTR (exp, 0);
90218334Speter	  for (; *p; p++)
90390075Sobrien	    if (! ISDIGIT (*p))
90490075Sobrien	      {
90590075Sobrien		message_with_line (attr ? attr->lineno : 0,
90690075Sobrien				   "non-numeric value for numeric attribute %s",
90790075Sobrien				   attr ? attr->name : "internal");
90890075Sobrien		have_error = 1;
90990075Sobrien		break;
91090075Sobrien	      }
91118334Speter	  break;
91218334Speter	}
91318334Speter
91418334Speter      for (av = attr->first_value; av; av = av->next)
91518334Speter	if (GET_CODE (av->value) == CONST_STRING
91618334Speter	    && ! strcmp (XSTR (av->value, 0), XSTR (exp, 0)))
91718334Speter	  break;
91818334Speter
91918334Speter      if (av == NULL)
92090075Sobrien	{
92190075Sobrien	  message_with_line (attr->lineno,
92290075Sobrien			     "unknown value `%s' for `%s' attribute",
92390075Sobrien			     XSTR (exp, 0), attr ? attr->name : "internal");
92490075Sobrien	  have_error = 1;
92590075Sobrien	}
92618334Speter      break;
92718334Speter
92818334Speter    case IF_THEN_ELSE:
92918334Speter      XEXP (exp, 0) = check_attr_test (XEXP (exp, 0),
93090075Sobrien				       attr ? attr->is_const : 0,
93190075Sobrien				       attr ? attr->lineno : 0);
93218334Speter      XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
93318334Speter      XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
93418334Speter      break;
93518334Speter
93652284Sobrien    case PLUS:
93752284Sobrien    case MINUS:
93852284Sobrien    case MULT:
93952284Sobrien    case DIV:
94052284Sobrien    case MOD:
94152284Sobrien      if (attr && !attr->is_numeric)
94290075Sobrien	{
94390075Sobrien	  message_with_line (attr->lineno,
94490075Sobrien			     "invalid operation `%s' for non-numeric attribute value",
94590075Sobrien			     GET_RTX_NAME (GET_CODE (exp)));
94690075Sobrien	  have_error = 1;
94790075Sobrien	  break;
94890075Sobrien	}
949132718Skan      /* Fall through.  */
95052284Sobrien
95150397Sobrien    case IOR:
95250397Sobrien    case AND:
95350397Sobrien      XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
95450397Sobrien      XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
95550397Sobrien      break;
95650397Sobrien
95750397Sobrien    case FFS:
958132718Skan    case CLZ:
959132718Skan    case CTZ:
960132718Skan    case POPCOUNT:
961132718Skan    case PARITY:
96250397Sobrien      XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
96350397Sobrien      break;
96450397Sobrien
96518334Speter    case COND:
96618334Speter      if (XVECLEN (exp, 0) % 2 != 0)
96790075Sobrien	{
96890075Sobrien	  message_with_line (attr->lineno,
96990075Sobrien			     "first operand of COND must have even length");
97090075Sobrien	  have_error = 1;
97190075Sobrien	  break;
97290075Sobrien	}
97318334Speter
97418334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
97518334Speter	{
97618334Speter	  XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
97790075Sobrien						 attr ? attr->is_const : 0,
97890075Sobrien						 attr ? attr->lineno : 0);
97918334Speter	  XVECEXP (exp, 0, i + 1)
98018334Speter	    = check_attr_value (XVECEXP (exp, 0, i + 1), attr);
98118334Speter	}
98218334Speter
98318334Speter      XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
98418334Speter      break;
98518334Speter
98652284Sobrien    case ATTR:
98752284Sobrien      {
988132718Skan	struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0);
98952284Sobrien	if (attr2 == NULL)
99090075Sobrien	  {
99190075Sobrien	    message_with_line (attr ? attr->lineno : 0,
99290075Sobrien			       "unknown attribute `%s' in ATTR",
99390075Sobrien			       XSTR (exp, 0));
99490075Sobrien	    have_error = 1;
99590075Sobrien	  }
99690075Sobrien	else if (attr && attr->is_const && ! attr2->is_const)
99790075Sobrien	  {
99890075Sobrien	    message_with_line (attr->lineno,
99990075Sobrien		"non-constant attribute `%s' referenced from `%s'",
100090075Sobrien		XSTR (exp, 0), attr->name);
100190075Sobrien	    have_error = 1;
100290075Sobrien	  }
100390075Sobrien	else if (attr
1004169689Skan		 && attr->is_numeric != attr2->is_numeric)
100590075Sobrien	  {
100690075Sobrien	    message_with_line (attr->lineno,
100790075Sobrien		"numeric attribute mismatch calling `%s' from `%s'",
100890075Sobrien		XSTR (exp, 0), attr->name);
100990075Sobrien	    have_error = 1;
101090075Sobrien	  }
101152284Sobrien      }
101252284Sobrien      break;
101352284Sobrien
101418334Speter    case SYMBOL_REF:
101552284Sobrien      /* A constant SYMBOL_REF is valid as a constant attribute test and
101652284Sobrien         is expanded later by make_canonical into a COND.  In a non-constant
101752284Sobrien         attribute test, it is left be.  */
101852284Sobrien      return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
101918334Speter
102018334Speter    default:
102190075Sobrien      message_with_line (attr ? attr->lineno : 0,
102290075Sobrien			 "invalid operation `%s' for attribute value",
102390075Sobrien			 GET_RTX_NAME (GET_CODE (exp)));
102490075Sobrien      have_error = 1;
102590075Sobrien      break;
102618334Speter    }
102718334Speter
102818334Speter  return exp;
102918334Speter}
1030132718Skan
103118334Speter/* Given an SET_ATTR_ALTERNATIVE expression, convert to the canonical SET.
1032169689Skan   It becomes a COND with each test being (eq_attr "alternative" "n") */
103318334Speter
103418334Speterstatic rtx
1035132718Skanconvert_set_attr_alternative (rtx exp, struct insn_def *id)
103618334Speter{
103790075Sobrien  int num_alt = id->num_alternatives;
103818334Speter  rtx condexp;
103918334Speter  int i;
104018334Speter
104118334Speter  if (XVECLEN (exp, 1) != num_alt)
104290075Sobrien    {
104390075Sobrien      message_with_line (id->lineno,
104490075Sobrien			 "bad number of entries in SET_ATTR_ALTERNATIVE");
104590075Sobrien      have_error = 1;
104690075Sobrien      return NULL_RTX;
104790075Sobrien    }
104818334Speter
104918334Speter  /* Make a COND with all tests but the last.  Select the last value via the
105018334Speter     default.  */
105118334Speter  condexp = rtx_alloc (COND);
105218334Speter  XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
105318334Speter
105418334Speter  for (i = 0; i < num_alt - 1; i++)
105518334Speter    {
105690075Sobrien      const char *p;
105718334Speter      p = attr_numeral (i);
105818334Speter
105918334Speter      XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name, p);
106018334Speter      XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP (exp, 1, i);
106118334Speter    }
106218334Speter
106318334Speter  XEXP (condexp, 1) = XVECEXP (exp, 1, i);
106418334Speter
106518334Speter  return attr_rtx (SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);
106618334Speter}
1067132718Skan
106818334Speter/* Given a SET_ATTR, convert to the appropriate SET.  If a comma-separated
106918334Speter   list of values is given, convert to SET_ATTR_ALTERNATIVE first.  */
107018334Speter
107118334Speterstatic rtx
1072132718Skanconvert_set_attr (rtx exp, struct insn_def *id)
107318334Speter{
107418334Speter  rtx newexp;
107590075Sobrien  const char *name_ptr;
107618334Speter  char *p;
107718334Speter  int n;
107818334Speter
107918334Speter  /* See how many alternative specified.  */
108018334Speter  n = n_comma_elts (XSTR (exp, 1));
108118334Speter  if (n == 1)
108218334Speter    return attr_rtx (SET,
108318334Speter		     attr_rtx (ATTR, XSTR (exp, 0)),
108418334Speter		     attr_rtx (CONST_STRING, XSTR (exp, 1)));
108518334Speter
108618334Speter  newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);
108718334Speter  XSTR (newexp, 0) = XSTR (exp, 0);
108818334Speter  XVEC (newexp, 1) = rtvec_alloc (n);
108918334Speter
109018334Speter  /* Process each comma-separated name.  */
109118334Speter  name_ptr = XSTR (exp, 1);
109218334Speter  n = 0;
109318334Speter  while ((p = next_comma_elt (&name_ptr)) != NULL)
109418334Speter    XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
109518334Speter
109690075Sobrien  return convert_set_attr_alternative (newexp, id);
109718334Speter}
1098132718Skan
109918334Speter/* Scan all definitions, checking for validity.  Also, convert any SET_ATTR
110018334Speter   and SET_ATTR_ALTERNATIVE expressions to the corresponding SET
110150397Sobrien   expressions.  */
110218334Speter
110318334Speterstatic void
1104132718Skancheck_defs (void)
110518334Speter{
110618334Speter  struct insn_def *id;
110718334Speter  struct attr_desc *attr;
110818334Speter  int i;
110918334Speter  rtx value;
111018334Speter
111118334Speter  for (id = defs; id; id = id->next)
111218334Speter    {
111318334Speter      if (XVEC (id->def, id->vec_idx) == NULL)
111418334Speter	continue;
111518334Speter
111618334Speter      for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
111718334Speter	{
111818334Speter	  value = XVECEXP (id->def, id->vec_idx, i);
111918334Speter	  switch (GET_CODE (value))
112018334Speter	    {
112118334Speter	    case SET:
112218334Speter	      if (GET_CODE (XEXP (value, 0)) != ATTR)
112390075Sobrien		{
112490075Sobrien		  message_with_line (id->lineno, "bad attribute set");
112590075Sobrien		  have_error = 1;
112690075Sobrien		  value = NULL_RTX;
112790075Sobrien		}
112818334Speter	      break;
112918334Speter
113018334Speter	    case SET_ATTR_ALTERNATIVE:
113190075Sobrien	      value = convert_set_attr_alternative (value, id);
113218334Speter	      break;
113318334Speter
113418334Speter	    case SET_ATTR:
113590075Sobrien	      value = convert_set_attr (value, id);
113618334Speter	      break;
113718334Speter
113818334Speter	    default:
113990075Sobrien	      message_with_line (id->lineno, "invalid attribute code %s",
114090075Sobrien				 GET_RTX_NAME (GET_CODE (value)));
114190075Sobrien	      have_error = 1;
114290075Sobrien	      value = NULL_RTX;
114318334Speter	    }
114490075Sobrien	  if (value == NULL_RTX)
114590075Sobrien	    continue;
114618334Speter
1147132718Skan	  if ((attr = find_attr (&XSTR (XEXP (value, 0), 0), 0)) == NULL)
114890075Sobrien	    {
114990075Sobrien	      message_with_line (id->lineno, "unknown attribute %s",
115090075Sobrien				 XSTR (XEXP (value, 0), 0));
115190075Sobrien	      have_error = 1;
115290075Sobrien	      continue;
115390075Sobrien	    }
115418334Speter
115518334Speter	  XVECEXP (id->def, id->vec_idx, i) = value;
115618334Speter	  XEXP (value, 1) = check_attr_value (XEXP (value, 1), attr);
115718334Speter	}
115818334Speter    }
115918334Speter}
116018334Speter
116118334Speter/* Given a valid expression for an attribute value, remove any IF_THEN_ELSE
116218334Speter   expressions by converting them into a COND.  This removes cases from this
116318334Speter   program.  Also, replace an attribute value of "*" with the default attribute
116418334Speter   value.  */
116518334Speter
116618334Speterstatic rtx
1167132718Skanmake_canonical (struct attr_desc *attr, rtx exp)
116818334Speter{
116918334Speter  int i;
117018334Speter  rtx newexp;
117118334Speter
117218334Speter  switch (GET_CODE (exp))
117318334Speter    {
117418334Speter    case CONST_INT:
117518334Speter      exp = make_numeric_value (INTVAL (exp));
117618334Speter      break;
117718334Speter
117818334Speter    case CONST_STRING:
117918334Speter      if (! strcmp (XSTR (exp, 0), "*"))
118018334Speter	{
118118334Speter	  if (attr == 0 || attr->default_val == 0)
118290075Sobrien	    fatal ("(attr_value \"*\") used in invalid context");
118318334Speter	  exp = attr->default_val->value;
118418334Speter	}
1185132718Skan      else
1186132718Skan	XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
118718334Speter
118818334Speter      break;
118918334Speter
119018334Speter    case SYMBOL_REF:
1191117395Skan      if (!attr->is_const || ATTR_IND_SIMPLIFIED_P (exp))
119218334Speter	break;
119318334Speter      /* The SYMBOL_REF is constant for a given run, so mark it as unchanging.
119418334Speter	 This makes the COND something that won't be considered an arbitrary
119518334Speter	 expression by walk_attr_value.  */
1196117395Skan      ATTR_IND_SIMPLIFIED_P (exp) = 1;
119718334Speter      exp = check_attr_value (exp, attr);
119850397Sobrien      break;
119918334Speter
120018334Speter    case IF_THEN_ELSE:
120118334Speter      newexp = rtx_alloc (COND);
120218334Speter      XVEC (newexp, 0) = rtvec_alloc (2);
120318334Speter      XVECEXP (newexp, 0, 0) = XEXP (exp, 0);
120418334Speter      XVECEXP (newexp, 0, 1) = XEXP (exp, 1);
120518334Speter
120618334Speter      XEXP (newexp, 1) = XEXP (exp, 2);
120718334Speter
120818334Speter      exp = newexp;
120918334Speter      /* Fall through to COND case since this is now a COND.  */
121018334Speter
121118334Speter    case COND:
121218334Speter      {
121318334Speter	int allsame = 1;
121418334Speter	rtx defval;
121518334Speter
121650397Sobrien	/* First, check for degenerate COND.  */
121718334Speter	if (XVECLEN (exp, 0) == 0)
121818334Speter	  return make_canonical (attr, XEXP (exp, 1));
121918334Speter	defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
122018334Speter
122118334Speter	for (i = 0; i < XVECLEN (exp, 0); i += 2)
122218334Speter	  {
122318334Speter	    XVECEXP (exp, 0, i) = copy_boolean (XVECEXP (exp, 0, i));
122418334Speter	    XVECEXP (exp, 0, i + 1)
122518334Speter	      = make_canonical (attr, XVECEXP (exp, 0, i + 1));
122618334Speter	    if (! rtx_equal_p (XVECEXP (exp, 0, i + 1), defval))
122718334Speter	      allsame = 0;
122818334Speter	  }
122918334Speter	if (allsame)
123018334Speter	  return defval;
123118334Speter      }
123250397Sobrien      break;
123350397Sobrien
123450397Sobrien    default:
123550397Sobrien      break;
123618334Speter    }
123718334Speter
123818334Speter  return exp;
123918334Speter}
124018334Speter
124118334Speterstatic rtx
1242132718Skancopy_boolean (rtx exp)
124318334Speter{
124418334Speter  if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR)
124518334Speter    return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)),
124618334Speter		     copy_boolean (XEXP (exp, 1)));
1247132718Skan  if (GET_CODE (exp) == MATCH_OPERAND)
1248132718Skan    {
1249132718Skan      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1250132718Skan      XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2));
1251132718Skan    }
1252132718Skan  else if (GET_CODE (exp) == EQ_ATTR)
1253132718Skan    {
1254132718Skan      XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
1255132718Skan      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1256132718Skan    }
1257132718Skan
125818334Speter  return exp;
125918334Speter}
1260132718Skan
126118334Speter/* Given a value and an attribute description, return a `struct attr_value *'
126218334Speter   that represents that value.  This is either an existing structure, if the
126318334Speter   value has been previously encountered, or a newly-created structure.
126418334Speter
126518334Speter   `insn_code' is the code of an insn whose attribute has the specified
126618334Speter   value (-2 if not processing an insn).  We ensure that all insns for
126718334Speter   a given value have the same number of alternatives if the value checks
126818334Speter   alternatives.  */
126918334Speter
127018334Speterstatic struct attr_value *
1271132718Skanget_attr_value (rtx value, struct attr_desc *attr, int insn_code)
127218334Speter{
127318334Speter  struct attr_value *av;
127418334Speter  int num_alt = 0;
127518334Speter
127618334Speter  value = make_canonical (attr, value);
127718334Speter  if (compares_alternatives_p (value))
127818334Speter    {
127918334Speter      if (insn_code < 0 || insn_alternatives == NULL)
128018334Speter	fatal ("(eq_attr \"alternatives\" ...) used in non-insn context");
128118334Speter      else
128218334Speter	num_alt = insn_alternatives[insn_code];
128318334Speter    }
128418334Speter
128518334Speter  for (av = attr->first_value; av; av = av->next)
128618334Speter    if (rtx_equal_p (value, av->value)
128718334Speter	&& (num_alt == 0 || av->first_insn == NULL
1288169689Skan	    || insn_alternatives[av->first_insn->def->insn_code]))
128918334Speter      return av;
129018334Speter
1291132718Skan  av = oballoc (sizeof (struct attr_value));
129218334Speter  av->value = value;
129318334Speter  av->next = attr->first_value;
129418334Speter  attr->first_value = av;
129518334Speter  av->first_insn = NULL;
129618334Speter  av->num_insns = 0;
129718334Speter  av->has_asm_insn = 0;
129818334Speter
129918334Speter  return av;
130018334Speter}
1301132718Skan
130218334Speter/* After all DEFINE_DELAYs have been read in, create internal attributes
130318334Speter   to generate the required routines.
130418334Speter
130518334Speter   First, we compute the number of delay slots for each insn (as a COND of
130618334Speter   each of the test expressions in DEFINE_DELAYs).  Then, if more than one
130718334Speter   delay type is specified, we compute a similar function giving the
130818334Speter   DEFINE_DELAY ordinal for each insn.
130918334Speter
131018334Speter   Finally, for each [DEFINE_DELAY, slot #] pair, we compute an attribute that
131118334Speter   tells whether a given insn can be in that delay slot.
131218334Speter
131318334Speter   Normal attribute filling and optimization expands these to contain the
131418334Speter   information needed to handle delay slots.  */
131518334Speter
131618334Speterstatic void
1317132718Skanexpand_delays (void)
131818334Speter{
131918334Speter  struct delay_desc *delay;
132018334Speter  rtx condexp;
132118334Speter  rtx newexp;
132218334Speter  int i;
132318334Speter  char *p;
132418334Speter
132518334Speter  /* First, generate data for `num_delay_slots' function.  */
132618334Speter
132718334Speter  condexp = rtx_alloc (COND);
132818334Speter  XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
132918334Speter  XEXP (condexp, 1) = make_numeric_value (0);
133018334Speter
133118334Speter  for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
133218334Speter    {
133318334Speter      XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
133418334Speter      XVECEXP (condexp, 0, i + 1)
133518334Speter	= make_numeric_value (XVECLEN (delay->def, 1) / 3);
133618334Speter    }
133718334Speter
1338132718Skan  make_internal_attr (num_delay_slots_str, condexp, ATTR_NONE);
133918334Speter
134018334Speter  /* If more than one delay type, do the same for computing the delay type.  */
134118334Speter  if (num_delays > 1)
134218334Speter    {
134318334Speter      condexp = rtx_alloc (COND);
134418334Speter      XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
134518334Speter      XEXP (condexp, 1) = make_numeric_value (0);
134618334Speter
134718334Speter      for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
134818334Speter	{
134918334Speter	  XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
135018334Speter	  XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num);
135118334Speter	}
135218334Speter
1353132718Skan      make_internal_attr (delay_type_str, condexp, ATTR_SPECIAL);
135418334Speter    }
135518334Speter
135618334Speter  /* For each delay possibility and delay slot, compute an eligibility
135718334Speter     attribute for non-annulled insns and for each type of annulled (annul
135818334Speter     if true and annul if false).  */
135990075Sobrien  for (delay = delays; delay; delay = delay->next)
136090075Sobrien    {
136190075Sobrien      for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
136290075Sobrien	{
136390075Sobrien	  condexp = XVECEXP (delay->def, 1, i);
136490075Sobrien	  if (condexp == 0)
136590075Sobrien	    condexp = false_rtx;
136690075Sobrien	  newexp = attr_rtx (IF_THEN_ELSE, condexp,
136790075Sobrien			     make_numeric_value (1), make_numeric_value (0));
136818334Speter
136990075Sobrien	  p = attr_printf (sizeof "*delay__" + MAX_DIGITS * 2,
137090075Sobrien			   "*delay_%d_%d", delay->num, i / 3);
1371132718Skan	  make_internal_attr (p, newexp, ATTR_SPECIAL);
137218334Speter
137390075Sobrien	  if (have_annul_true)
137490075Sobrien	    {
137590075Sobrien	      condexp = XVECEXP (delay->def, 1, i + 1);
137690075Sobrien	      if (condexp == 0) condexp = false_rtx;
137790075Sobrien	      newexp = attr_rtx (IF_THEN_ELSE, condexp,
137890075Sobrien				 make_numeric_value (1),
137990075Sobrien				 make_numeric_value (0));
138090075Sobrien	      p = attr_printf (sizeof "*annul_true__" + MAX_DIGITS * 2,
138190075Sobrien			       "*annul_true_%d_%d", delay->num, i / 3);
1382132718Skan	      make_internal_attr (p, newexp, ATTR_SPECIAL);
138390075Sobrien	    }
138418334Speter
138590075Sobrien	  if (have_annul_false)
138690075Sobrien	    {
138790075Sobrien	      condexp = XVECEXP (delay->def, 1, i + 2);
138890075Sobrien	      if (condexp == 0) condexp = false_rtx;
138990075Sobrien	      newexp = attr_rtx (IF_THEN_ELSE, condexp,
139090075Sobrien				 make_numeric_value (1),
139190075Sobrien				 make_numeric_value (0));
139290075Sobrien	      p = attr_printf (sizeof "*annul_false__" + MAX_DIGITS * 2,
139390075Sobrien			       "*annul_false_%d_%d", delay->num, i / 3);
1394132718Skan	      make_internal_attr (p, newexp, ATTR_SPECIAL);
139590075Sobrien	    }
139690075Sobrien	}
139790075Sobrien    }
139818334Speter}
1399132718Skan
140018334Speter/* Once all attributes and insns have been read and checked, we construct for
140118334Speter   each attribute value a list of all the insns that have that value for
140218334Speter   the attribute.  */
140318334Speter
140418334Speterstatic void
1405132718Skanfill_attr (struct attr_desc *attr)
140618334Speter{
140718334Speter  struct attr_value *av;
140818334Speter  struct insn_ent *ie;
140918334Speter  struct insn_def *id;
141018334Speter  int i;
141118334Speter  rtx value;
141218334Speter
141318334Speter  /* Don't fill constant attributes.  The value is independent of
141418334Speter     any particular insn.  */
141518334Speter  if (attr->is_const)
141618334Speter    return;
141718334Speter
141818334Speter  for (id = defs; id; id = id->next)
141918334Speter    {
142018334Speter      /* If no value is specified for this insn for this attribute, use the
142118334Speter	 default.  */
142218334Speter      value = NULL;
142318334Speter      if (XVEC (id->def, id->vec_idx))
142418334Speter	for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
1425132718Skan	  if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
1426132718Skan			      attr->name))
142718334Speter	    value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
142818334Speter
142918334Speter      if (value == NULL)
143018334Speter	av = attr->default_val;
143118334Speter      else
143218334Speter	av = get_attr_value (value, attr, id->insn_code);
143318334Speter
1434132718Skan      ie = oballoc (sizeof (struct insn_ent));
1435169689Skan      ie->def = id;
143618334Speter      insert_insn_ent (av, ie);
143718334Speter    }
143818334Speter}
1439132718Skan
144018334Speter/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a
144118334Speter   test that checks relative positions of insns (uses MATCH_DUP or PC).
144218334Speter   If so, replace it with what is obtained by passing the expression to
144318334Speter   ADDRESS_FN.  If not but it is a COND or IF_THEN_ELSE, call this routine
144418334Speter   recursively on each value (including the default value).  Otherwise,
144518334Speter   return the value returned by NO_ADDRESS_FN applied to EXP.  */
144618334Speter
144718334Speterstatic rtx
1448132718Skansubstitute_address (rtx exp, rtx (*no_address_fn) (rtx),
1449132718Skan		    rtx (*address_fn) (rtx))
145018334Speter{
145118334Speter  int i;
145218334Speter  rtx newexp;
145318334Speter
145418334Speter  if (GET_CODE (exp) == COND)
145518334Speter    {
145618334Speter      /* See if any tests use addresses.  */
145718334Speter      address_used = 0;
145818334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
145918334Speter	walk_attr_value (XVECEXP (exp, 0, i));
146018334Speter
146118334Speter      if (address_used)
146218334Speter	return (*address_fn) (exp);
146318334Speter
146418334Speter      /* Make a new copy of this COND, replacing each element.  */
146518334Speter      newexp = rtx_alloc (COND);
146618334Speter      XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
146718334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
146818334Speter	{
146918334Speter	  XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
147018334Speter	  XVECEXP (newexp, 0, i + 1)
147118334Speter	    = substitute_address (XVECEXP (exp, 0, i + 1),
147218334Speter				  no_address_fn, address_fn);
147318334Speter	}
147418334Speter
147518334Speter      XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
147618334Speter					     no_address_fn, address_fn);
147718334Speter
147818334Speter      return newexp;
147918334Speter    }
148018334Speter
148118334Speter  else if (GET_CODE (exp) == IF_THEN_ELSE)
148218334Speter    {
148318334Speter      address_used = 0;
148418334Speter      walk_attr_value (XEXP (exp, 0));
148518334Speter      if (address_used)
148618334Speter	return (*address_fn) (exp);
148718334Speter
148818334Speter      return attr_rtx (IF_THEN_ELSE,
148918334Speter		       substitute_address (XEXP (exp, 0),
149018334Speter					   no_address_fn, address_fn),
149118334Speter		       substitute_address (XEXP (exp, 1),
149218334Speter					   no_address_fn, address_fn),
149318334Speter		       substitute_address (XEXP (exp, 2),
149418334Speter					   no_address_fn, address_fn));
149518334Speter    }
149618334Speter
149718334Speter  return (*no_address_fn) (exp);
149818334Speter}
1499132718Skan
150018334Speter/* Make new attributes from the `length' attribute.  The following are made,
150118334Speter   each corresponding to a function called from `shorten_branches' or
150218334Speter   `get_attr_length':
150318334Speter
150418334Speter   *insn_default_length		This is the length of the insn to be returned
150518334Speter				by `get_attr_length' before `shorten_branches'
150618334Speter				has been called.  In each case where the length
150718334Speter				depends on relative addresses, the largest
150818334Speter				possible is used.  This routine is also used
150918334Speter				to compute the initial size of the insn.
151018334Speter
151118334Speter   *insn_variable_length_p	This returns 1 if the insn's length depends
151218334Speter				on relative addresses, zero otherwise.
151318334Speter
151418334Speter   *insn_current_length		This is only called when it is known that the
151518334Speter				insn has a variable length and returns the
151618334Speter				current length, based on relative addresses.
151718334Speter  */
151818334Speter
151918334Speterstatic void
1520132718Skanmake_length_attrs (void)
152118334Speter{
1522132718Skan  static const char *new_names[] =
1523132718Skan    {
1524132718Skan      "*insn_default_length",
1525169689Skan      "*insn_min_length",
1526132718Skan      "*insn_variable_length_p",
1527132718Skan      "*insn_current_length"
1528132718Skan    };
1529169689Skan  static rtx (*const no_address_fn[]) (rtx)
1530169689Skan    = {identity_fn,identity_fn, zero_fn, zero_fn};
1531169689Skan  static rtx (*const address_fn[]) (rtx)
1532169689Skan    = {max_fn, min_fn, one_fn, identity_fn};
153350397Sobrien  size_t i;
153418334Speter  struct attr_desc *length_attr, *new_attr;
153518334Speter  struct attr_value *av, *new_av;
153618334Speter  struct insn_ent *ie, *new_ie;
153718334Speter
153818334Speter  /* See if length attribute is defined.  If so, it must be numeric.  Make
153918334Speter     it special so we don't output anything for it.  */
1540132718Skan  length_attr = find_attr (&length_str, 0);
154118334Speter  if (length_attr == 0)
154218334Speter    return;
154318334Speter
154418334Speter  if (! length_attr->is_numeric)
154590075Sobrien    fatal ("length attribute must be numeric");
154618334Speter
154718334Speter  length_attr->is_const = 0;
154818334Speter  length_attr->is_special = 1;
154918334Speter
155018334Speter  /* Make each new attribute, in turn.  */
155190075Sobrien  for (i = 0; i < ARRAY_SIZE (new_names); i++)
155218334Speter    {
155318334Speter      make_internal_attr (new_names[i],
155418334Speter			  substitute_address (length_attr->default_val->value,
155518334Speter					      no_address_fn[i], address_fn[i]),
1556132718Skan			  ATTR_NONE);
1557132718Skan      new_attr = find_attr (&new_names[i], 0);
155818334Speter      for (av = length_attr->first_value; av; av = av->next)
155918334Speter	for (ie = av->first_insn; ie; ie = ie->next)
156018334Speter	  {
156118334Speter	    new_av = get_attr_value (substitute_address (av->value,
156218334Speter							 no_address_fn[i],
156318334Speter							 address_fn[i]),
1564169689Skan				     new_attr, ie->def->insn_code);
1565132718Skan	    new_ie = oballoc (sizeof (struct insn_ent));
1566169689Skan	    new_ie->def = ie->def;
156718334Speter	    insert_insn_ent (new_av, new_ie);
156818334Speter	  }
156918334Speter    }
157018334Speter}
157118334Speter
157218334Speter/* Utility functions called from above routine.  */
157318334Speter
157418334Speterstatic rtx
1575132718Skanidentity_fn (rtx exp)
157618334Speter{
157718334Speter  return exp;
157818334Speter}
157918334Speter
158018334Speterstatic rtx
1581132718Skanzero_fn (rtx exp ATTRIBUTE_UNUSED)
158218334Speter{
158318334Speter  return make_numeric_value (0);
158418334Speter}
158518334Speter
158618334Speterstatic rtx
1587132718Skanone_fn (rtx exp ATTRIBUTE_UNUSED)
158818334Speter{
158918334Speter  return make_numeric_value (1);
159018334Speter}
159118334Speter
159218334Speterstatic rtx
1593132718Skanmax_fn (rtx exp)
159418334Speter{
159552284Sobrien  int unknown;
159652284Sobrien  return make_numeric_value (max_attr_value (exp, &unknown));
159718334Speter}
159850397Sobrien
1599169689Skanstatic rtx
1600169689Skanmin_fn (rtx exp)
1601169689Skan{
1602169689Skan  int unknown;
1603169689Skan  return make_numeric_value (min_attr_value (exp, &unknown));
1604169689Skan}
1605169689Skan
160650397Sobrienstatic void
1607132718Skanwrite_length_unit_log (void)
160850397Sobrien{
1609132718Skan  struct attr_desc *length_attr = find_attr (&length_str, 0);
161050397Sobrien  struct attr_value *av;
161150397Sobrien  struct insn_ent *ie;
161250397Sobrien  unsigned int length_unit_log, length_or;
161352284Sobrien  int unknown = 0;
161450397Sobrien
161550397Sobrien  if (length_attr == 0)
161650397Sobrien    return;
161752284Sobrien  length_or = or_attr_value (length_attr->default_val->value, &unknown);
161852284Sobrien  for (av = length_attr->first_value; av; av = av->next)
161952284Sobrien    for (ie = av->first_insn; ie; ie = ie->next)
162052284Sobrien      length_or |= or_attr_value (av->value, &unknown);
162152284Sobrien
162252284Sobrien  if (unknown)
162352284Sobrien    length_unit_log = 0;
162452284Sobrien  else
162552284Sobrien    {
162652284Sobrien      length_or = ~length_or;
162752284Sobrien      for (length_unit_log = 0; length_or & 1; length_or >>= 1)
162890075Sobrien	length_unit_log++;
162952284Sobrien    }
1630169689Skan  printf ("const int length_unit_log = %u;\n", length_unit_log);
163150397Sobrien}
1632132718Skan
163318334Speter/* Take a COND expression and see if any of the conditions in it can be
163418334Speter   simplified.  If any are known true or known false for the particular insn
163518334Speter   code, the COND can be further simplified.
163618334Speter
163718334Speter   Also call ourselves on any COND operations that are values of this COND.
163818334Speter
163918334Speter   We do not modify EXP; rather, we make and return a new rtx.  */
164018334Speter
164118334Speterstatic rtx
1642132718Skansimplify_cond (rtx exp, int insn_code, int insn_index)
164318334Speter{
164418334Speter  int i, j;
164518334Speter  /* We store the desired contents here,
164618334Speter     then build a new expression if they don't match EXP.  */
164718334Speter  rtx defval = XEXP (exp, 1);
164818334Speter  rtx new_defval = XEXP (exp, 1);
164918334Speter  int len = XVECLEN (exp, 0);
1650169689Skan  rtx *tests = XNEWVEC (rtx, len);
165118334Speter  int allsame = 1;
165290075Sobrien  rtx ret;
165318334Speter
165418334Speter  /* This lets us free all storage allocated below, if appropriate.  */
1655222097Sbenl  (void) obstack_finish (rtl_obstack);
165618334Speter
165790075Sobrien  memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
165818334Speter
165918334Speter  /* See if default value needs simplification.  */
166018334Speter  if (GET_CODE (defval) == COND)
166118334Speter    new_defval = simplify_cond (defval, insn_code, insn_index);
166218334Speter
166318334Speter  /* Simplify the subexpressions, and see what tests we can get rid of.  */
166418334Speter
166518334Speter  for (i = 0; i < len; i += 2)
166618334Speter    {
166718334Speter      rtx newtest, newval;
166818334Speter
166918334Speter      /* Simplify this test.  */
167090075Sobrien      newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
167190075Sobrien      tests[i] = newtest;
167218334Speter
167390075Sobrien      newval = tests[i + 1];
167418334Speter      /* See if this value may need simplification.  */
167518334Speter      if (GET_CODE (newval) == COND)
167618334Speter	newval = simplify_cond (newval, insn_code, insn_index);
167718334Speter
167818334Speter      /* Look for ways to delete or combine this test.  */
167918334Speter      if (newtest == true_rtx)
168018334Speter	{
168118334Speter	  /* If test is true, make this value the default
168218334Speter	     and discard this + any following tests.  */
168318334Speter	  len = i;
168490075Sobrien	  defval = tests[i + 1];
168518334Speter	  new_defval = newval;
168618334Speter	}
168718334Speter
168818334Speter      else if (newtest == false_rtx)
168918334Speter	{
169018334Speter	  /* If test is false, discard it and its value.  */
169118334Speter	  for (j = i; j < len - 2; j++)
169290075Sobrien	    tests[j] = tests[j + 2];
1693132718Skan	  i -= 2;
169418334Speter	  len -= 2;
169518334Speter	}
169618334Speter
169790075Sobrien      else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
169818334Speter	{
169918334Speter	  /* If this value and the value for the prev test are the same,
170018334Speter	     merge the tests.  */
170118334Speter
170290075Sobrien	  tests[i - 2]
170390075Sobrien	    = insert_right_side (IOR, tests[i - 2], newtest,
170418334Speter				 insn_code, insn_index);
170518334Speter
170618334Speter	  /* Delete this test/value.  */
170718334Speter	  for (j = i; j < len - 2; j++)
170890075Sobrien	    tests[j] = tests[j + 2];
170918334Speter	  len -= 2;
1710132718Skan	  i -= 2;
171118334Speter	}
171218334Speter
171318334Speter      else
171490075Sobrien	tests[i + 1] = newval;
171518334Speter    }
171618334Speter
171718334Speter  /* If the last test in a COND has the same value
171818334Speter     as the default value, that test isn't needed.  */
171918334Speter
172090075Sobrien  while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
172118334Speter    len -= 2;
172218334Speter
172318334Speter  /* See if we changed anything.  */
172418334Speter  if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
172518334Speter    allsame = 0;
172618334Speter  else
172718334Speter    for (i = 0; i < len; i++)
172890075Sobrien      if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
172918334Speter	{
173018334Speter	  allsame = 0;
173118334Speter	  break;
173218334Speter	}
173318334Speter
173418334Speter  if (len == 0)
173518334Speter    {
173618334Speter      if (GET_CODE (defval) == COND)
173790075Sobrien	ret = simplify_cond (defval, insn_code, insn_index);
173890075Sobrien      else
173990075Sobrien	ret = defval;
174018334Speter    }
174118334Speter  else if (allsame)
174290075Sobrien    ret = exp;
174318334Speter  else
174418334Speter    {
174518334Speter      rtx newexp = rtx_alloc (COND);
174618334Speter
174718334Speter      XVEC (newexp, 0) = rtvec_alloc (len);
174890075Sobrien      memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
174918334Speter      XEXP (newexp, 1) = new_defval;
175090075Sobrien      ret = newexp;
175118334Speter    }
175290075Sobrien  free (tests);
175390075Sobrien  return ret;
175418334Speter}
1755132718Skan
175618334Speter/* Remove an insn entry from an attribute value.  */
175718334Speter
175818334Speterstatic void
1759132718Skanremove_insn_ent (struct attr_value *av, struct insn_ent *ie)
176018334Speter{
176118334Speter  struct insn_ent *previe;
176218334Speter
176318334Speter  if (av->first_insn == ie)
176418334Speter    av->first_insn = ie->next;
176518334Speter  else
176618334Speter    {
176718334Speter      for (previe = av->first_insn; previe->next != ie; previe = previe->next)
176818334Speter	;
176918334Speter      previe->next = ie->next;
177018334Speter    }
177118334Speter
177218334Speter  av->num_insns--;
1773169689Skan  if (ie->def->insn_code == -1)
177418334Speter    av->has_asm_insn = 0;
177518334Speter
177618334Speter  num_insn_ents--;
177718334Speter}
177818334Speter
177918334Speter/* Insert an insn entry in an attribute value list.  */
178018334Speter
178118334Speterstatic void
1782132718Skaninsert_insn_ent (struct attr_value *av, struct insn_ent *ie)
178318334Speter{
178418334Speter  ie->next = av->first_insn;
178518334Speter  av->first_insn = ie;
178618334Speter  av->num_insns++;
1787169689Skan  if (ie->def->insn_code == -1)
178818334Speter    av->has_asm_insn = 1;
178918334Speter
179018334Speter  num_insn_ents++;
179118334Speter}
1792132718Skan
179318334Speter/* This is a utility routine to take an expression that is a tree of either
179418334Speter   AND or IOR expressions and insert a new term.  The new term will be
179518334Speter   inserted at the right side of the first node whose code does not match
179618334Speter   the root.  A new node will be created with the root's code.  Its left
179718334Speter   side will be the old right side and its right side will be the new
179818334Speter   term.
179918334Speter
180018334Speter   If the `term' is itself a tree, all its leaves will be inserted.  */
180118334Speter
180218334Speterstatic rtx
1803132718Skaninsert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index)
180418334Speter{
180518334Speter  rtx newexp;
180618334Speter
180718334Speter  /* Avoid consing in some special cases.  */
180818334Speter  if (code == AND && term == true_rtx)
180918334Speter    return exp;
181018334Speter  if (code == AND && term == false_rtx)
181118334Speter    return false_rtx;
181218334Speter  if (code == AND && exp == true_rtx)
181318334Speter    return term;
181418334Speter  if (code == AND && exp == false_rtx)
181518334Speter    return false_rtx;
181618334Speter  if (code == IOR && term == true_rtx)
181718334Speter    return true_rtx;
181818334Speter  if (code == IOR && term == false_rtx)
181918334Speter    return exp;
182018334Speter  if (code == IOR && exp == true_rtx)
182118334Speter    return true_rtx;
182218334Speter  if (code == IOR && exp == false_rtx)
182318334Speter    return term;
182418334Speter  if (attr_equal_p (exp, term))
182518334Speter    return exp;
182618334Speter
182718334Speter  if (GET_CODE (term) == code)
182818334Speter    {
182918334Speter      exp = insert_right_side (code, exp, XEXP (term, 0),
183018334Speter			       insn_code, insn_index);
183118334Speter      exp = insert_right_side (code, exp, XEXP (term, 1),
183218334Speter			       insn_code, insn_index);
183318334Speter
183418334Speter      return exp;
183518334Speter    }
183618334Speter
183718334Speter  if (GET_CODE (exp) == code)
183818334Speter    {
183918334Speter      rtx new = insert_right_side (code, XEXP (exp, 1),
184018334Speter				   term, insn_code, insn_index);
184118334Speter      if (new != XEXP (exp, 1))
184218334Speter	/* Make a copy of this expression and call recursively.  */
184318334Speter	newexp = attr_rtx (code, XEXP (exp, 0), new);
184418334Speter      else
184518334Speter	newexp = exp;
184618334Speter    }
184718334Speter  else
184818334Speter    {
184918334Speter      /* Insert the new term.  */
185018334Speter      newexp = attr_rtx (code, exp, term);
185118334Speter    }
185218334Speter
185390075Sobrien  return simplify_test_exp_in_temp (newexp, insn_code, insn_index);
185418334Speter}
1855132718Skan
185618334Speter/* If we have an expression which AND's a bunch of
185718334Speter	(not (eq_attrq "alternative" "n"))
185818334Speter   terms, we may have covered all or all but one of the possible alternatives.
185918334Speter   If so, we can optimize.  Similarly for IOR's of EQ_ATTR.
186018334Speter
186118334Speter   This routine is passed an expression and either AND or IOR.  It returns a
186218334Speter   bitmask indicating which alternatives are mentioned within EXP.  */
186318334Speter
186418334Speterstatic int
1865132718Skancompute_alternative_mask (rtx exp, enum rtx_code code)
186618334Speter{
186790075Sobrien  const char *string;
186818334Speter  if (GET_CODE (exp) == code)
186918334Speter    return compute_alternative_mask (XEXP (exp, 0), code)
187018334Speter	   | compute_alternative_mask (XEXP (exp, 1), code);
187118334Speter
187218334Speter  else if (code == AND && GET_CODE (exp) == NOT
187318334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
187418334Speter	   && XSTR (XEXP (exp, 0), 0) == alternative_name)
187518334Speter    string = XSTR (XEXP (exp, 0), 1);
187618334Speter
187718334Speter  else if (code == IOR && GET_CODE (exp) == EQ_ATTR
187818334Speter	   && XSTR (exp, 0) == alternative_name)
187918334Speter    string = XSTR (exp, 1);
188018334Speter
1881132718Skan  else if (GET_CODE (exp) == EQ_ATTR_ALT)
1882132718Skan    {
1883132718Skan      if (code == AND && XINT (exp, 1))
1884132718Skan	return XINT (exp, 0);
1885132718Skan
1886132718Skan      if (code == IOR && !XINT (exp, 1))
1887132718Skan	return XINT (exp, 0);
1888132718Skan
1889132718Skan      return 0;
1890132718Skan    }
189118334Speter  else
189218334Speter    return 0;
189318334Speter
189418334Speter  if (string[1] == 0)
189518334Speter    return 1 << (string[0] - '0');
189618334Speter  return 1 << atoi (string);
189718334Speter}
189818334Speter
189918334Speter/* Given I, a single-bit mask, return RTX to compare the `alternative'
190018334Speter   attribute with the value represented by that bit.  */
190118334Speter
190218334Speterstatic rtx
1903132718Skanmake_alternative_compare (int mask)
190418334Speter{
1905132718Skan  return mk_attr_alt (mask);
1906132718Skan}
190718334Speter
190818334Speter/* If we are processing an (eq_attr "attr" "value") test, we find the value
190918334Speter   of "attr" for this insn code.  From that value, we can compute a test
191018334Speter   showing when the EQ_ATTR will be true.  This routine performs that
191118334Speter   computation.  If a test condition involves an address, we leave the EQ_ATTR
191290075Sobrien   intact because addresses are only valid for the `length' attribute.
191318334Speter
191418334Speter   EXP is the EQ_ATTR expression and VALUE is the value of that attribute
191518334Speter   for the insn corresponding to INSN_CODE and INSN_INDEX.  */
191618334Speter
191718334Speterstatic rtx
1918132718Skanevaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
191918334Speter{
192018334Speter  rtx orexp, andexp;
192118334Speter  rtx right;
192218334Speter  rtx newexp;
192318334Speter  int i;
192418334Speter
1925169689Skan  switch (GET_CODE (value))
192618334Speter    {
1927169689Skan    case CONST_STRING:
1928132718Skan      if (! strcmp_check (XSTR (value, 0), XSTR (exp, 1)))
192918334Speter	newexp = true_rtx;
193018334Speter      else
193118334Speter	newexp = false_rtx;
1932169689Skan      break;
1933169689Skan
1934169689Skan    case SYMBOL_REF:
1935169689Skan      {
1936169689Skan	char *p;
1937169689Skan	char string[256];
1938169689Skan
1939169689Skan	gcc_assert (GET_CODE (exp) == EQ_ATTR);
1940169689Skan	gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2
1941169689Skan		    <= 256);
1942169689Skan
1943169689Skan	strcpy (string, XSTR (exp, 0));
1944169689Skan	strcat (string, "_");
1945169689Skan	strcat (string, XSTR (exp, 1));
1946169689Skan	for (p = string; *p; p++)
1947169689Skan	  *p = TOUPPER (*p);
1948169689Skan
1949169689Skan	newexp = attr_rtx (EQ, value,
1950169689Skan			   attr_rtx (SYMBOL_REF,
1951169689Skan				     DEF_ATTR_STRING (string)));
1952169689Skan	break;
1953169689Skan      }
195450397Sobrien
1955169689Skan    case COND:
1956169689Skan      /* We construct an IOR of all the cases for which the
1957169689Skan	 requested attribute value is present.  Since we start with
1958169689Skan	 FALSE, if it is not present, FALSE will be returned.
1959169689Skan
196018334Speter	 Each case is the AND of the NOT's of the previous conditions with the
196190075Sobrien	 current condition; in the default case the current condition is TRUE.
1962169689Skan
196318334Speter	 For each possible COND value, call ourselves recursively.
1964169689Skan
196518334Speter	 The extra TRUE and FALSE expressions will be eliminated by another
196650397Sobrien	 call to the simplification routine.  */
196718334Speter
196818334Speter      orexp = false_rtx;
196918334Speter      andexp = true_rtx;
197018334Speter
197118334Speter      for (i = 0; i < XVECLEN (value, 0); i += 2)
197218334Speter	{
197390075Sobrien	  rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i),
197490075Sobrien						insn_code, insn_index);
197518334Speter
197618334Speter	  right = insert_right_side (AND, andexp, this,
197718334Speter				     insn_code, insn_index);
197818334Speter	  right = insert_right_side (AND, right,
197918334Speter				     evaluate_eq_attr (exp,
198018334Speter						       XVECEXP (value, 0,
198118334Speter								i + 1),
198218334Speter						       insn_code, insn_index),
198318334Speter				     insn_code, insn_index);
198418334Speter	  orexp = insert_right_side (IOR, orexp, right,
198518334Speter				     insn_code, insn_index);
198618334Speter
198718334Speter	  /* Add this condition into the AND expression.  */
198818334Speter	  newexp = attr_rtx (NOT, this);
198918334Speter	  andexp = insert_right_side (AND, andexp, newexp,
199018334Speter				      insn_code, insn_index);
199118334Speter	}
199218334Speter
199318334Speter      /* Handle the default case.  */
199418334Speter      right = insert_right_side (AND, andexp,
199518334Speter				 evaluate_eq_attr (exp, XEXP (value, 1),
199618334Speter						   insn_code, insn_index),
199718334Speter				 insn_code, insn_index);
199818334Speter      newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
1999169689Skan      break;
2000169689Skan
2001169689Skan    default:
2002169689Skan      gcc_unreachable ();
200318334Speter    }
200418334Speter
200518334Speter  /* If uses an address, must return original expression.  But set the
2006117395Skan     ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again.  */
200718334Speter
200818334Speter  address_used = 0;
200918334Speter  walk_attr_value (newexp);
201018334Speter
201118334Speter  if (address_used)
201218334Speter    {
2013117395Skan      if (! ATTR_IND_SIMPLIFIED_P (exp))
201418334Speter	return copy_rtx_unchanging (exp);
201518334Speter      return exp;
201618334Speter    }
201718334Speter  else
201818334Speter    return newexp;
201918334Speter}
2020132718Skan
202118334Speter/* This routine is called when an AND of a term with a tree of AND's is
202218334Speter   encountered.  If the term or its complement is present in the tree, it
202318334Speter   can be replaced with TRUE or FALSE, respectively.
202418334Speter
202518334Speter   Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both
202690075Sobrien   be true and hence are complementary.
202718334Speter
202818334Speter   There is one special case:  If we see
202918334Speter	(and (not (eq_attr "att" "v1"))
203018334Speter	     (eq_attr "att" "v2"))
203118334Speter   this can be replaced by (eq_attr "att" "v2").  To do this we need to
203218334Speter   replace the term, not anything in the AND tree.  So we pass a pointer to
203318334Speter   the term.  */
203418334Speter
203518334Speterstatic rtx
2036132718Skansimplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
203718334Speter{
203818334Speter  rtx left, right;
203918334Speter  rtx newexp;
204018334Speter  rtx temp;
204118334Speter  int left_eliminates_term, right_eliminates_term;
204218334Speter
204318334Speter  if (GET_CODE (exp) == AND)
204418334Speter    {
204590075Sobrien      left  = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
204618334Speter      right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
204718334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
204818334Speter	{
2049132718Skan	  newexp = attr_rtx (AND, left, right);
205018334Speter
205190075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
205218334Speter	}
205318334Speter    }
205418334Speter
205518334Speter  else if (GET_CODE (exp) == IOR)
205618334Speter    {
205718334Speter      /* For the IOR case, we do the same as above, except that we can
205818334Speter         only eliminate `term' if both sides of the IOR would do so.  */
205918334Speter      temp = *pterm;
206090075Sobrien      left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
206118334Speter      left_eliminates_term = (temp == true_rtx);
206218334Speter
206318334Speter      temp = *pterm;
206418334Speter      right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
206518334Speter      right_eliminates_term = (temp == true_rtx);
206618334Speter
206718334Speter      if (left_eliminates_term && right_eliminates_term)
206818334Speter	*pterm = true_rtx;
206918334Speter
207018334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
207118334Speter	{
2072132718Skan	  newexp = attr_rtx (IOR, left, right);
207318334Speter
207490075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
207518334Speter	}
207618334Speter    }
207718334Speter
207818334Speter  /* Check for simplifications.  Do some extra checking here since this
207918334Speter     routine is called so many times.  */
208018334Speter
208118334Speter  if (exp == *pterm)
208218334Speter    return true_rtx;
208318334Speter
208418334Speter  else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
208518334Speter    return false_rtx;
208618334Speter
208718334Speter  else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
208818334Speter    return false_rtx;
208918334Speter
2090132718Skan  else if (GET_CODE (exp) == EQ_ATTR_ALT && GET_CODE (*pterm) == EQ_ATTR_ALT)
2091132718Skan    {
2092132718Skan      if (attr_alt_subset_p (*pterm, exp))
2093132718Skan	return true_rtx;
2094132718Skan
2095132718Skan      if (attr_alt_subset_of_compl_p (*pterm, exp))
2096132718Skan	return false_rtx;
2097132718Skan
2098132718Skan      if (attr_alt_subset_p (exp, *pterm))
2099132718Skan	*pterm = true_rtx;
2100132718Skan
2101132718Skan      return exp;
2102132718Skan    }
2103132718Skan
210418334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR)
210518334Speter    {
210618334Speter      if (XSTR (exp, 0) != XSTR (*pterm, 0))
210718334Speter	return exp;
210818334Speter
2109132718Skan      if (! strcmp_check (XSTR (exp, 1), XSTR (*pterm, 1)))
211018334Speter	return true_rtx;
211118334Speter      else
211218334Speter	return false_rtx;
211318334Speter    }
211418334Speter
211518334Speter  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
211618334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR)
211718334Speter    {
211818334Speter      if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0))
211918334Speter	return exp;
212018334Speter
2121132718Skan      if (! strcmp_check (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1)))
212218334Speter	return false_rtx;
212318334Speter      else
212418334Speter	return true_rtx;
212518334Speter    }
212618334Speter
212718334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
212818334Speter	   && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR)
212918334Speter    {
213018334Speter      if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0))
213118334Speter	return exp;
213218334Speter
2133132718Skan      if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1)))
213418334Speter	return false_rtx;
213518334Speter      else
213618334Speter	*pterm = true_rtx;
213718334Speter    }
213818334Speter
213918334Speter  else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT)
214018334Speter    {
214118334Speter      if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
214218334Speter	return true_rtx;
214318334Speter    }
214418334Speter
214518334Speter  else if (GET_CODE (exp) == NOT)
214618334Speter    {
214718334Speter      if (attr_equal_p (XEXP (exp, 0), *pterm))
214818334Speter	return false_rtx;
214918334Speter    }
215018334Speter
215118334Speter  else if (GET_CODE (*pterm) == NOT)
215218334Speter    {
215318334Speter      if (attr_equal_p (XEXP (*pterm, 0), exp))
215418334Speter	return false_rtx;
215518334Speter    }
215618334Speter
215718334Speter  else if (attr_equal_p (exp, *pterm))
215818334Speter    return true_rtx;
215918334Speter
216018334Speter  return exp;
216118334Speter}
2162132718Skan
216318334Speter/* Similar to `simplify_and_tree', but for IOR trees.  */
216418334Speter
216518334Speterstatic rtx
2166132718Skansimplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
216718334Speter{
216818334Speter  rtx left, right;
216918334Speter  rtx newexp;
217018334Speter  rtx temp;
217118334Speter  int left_eliminates_term, right_eliminates_term;
217218334Speter
217318334Speter  if (GET_CODE (exp) == IOR)
217418334Speter    {
217590075Sobrien      left  = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
217618334Speter      right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
217718334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
217818334Speter	{
217918334Speter	  newexp = attr_rtx (GET_CODE (exp), left, right);
218018334Speter
218190075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
218218334Speter	}
218318334Speter    }
218418334Speter
218518334Speter  else if (GET_CODE (exp) == AND)
218618334Speter    {
218718334Speter      /* For the AND case, we do the same as above, except that we can
218818334Speter         only eliminate `term' if both sides of the AND would do so.  */
218918334Speter      temp = *pterm;
219090075Sobrien      left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
219118334Speter      left_eliminates_term = (temp == false_rtx);
219218334Speter
219318334Speter      temp = *pterm;
219418334Speter      right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
219518334Speter      right_eliminates_term = (temp == false_rtx);
219618334Speter
219718334Speter      if (left_eliminates_term && right_eliminates_term)
219818334Speter	*pterm = false_rtx;
219918334Speter
220018334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
220118334Speter	{
220218334Speter	  newexp = attr_rtx (GET_CODE (exp), left, right);
220318334Speter
220490075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
220518334Speter	}
220618334Speter    }
220718334Speter
220818334Speter  if (attr_equal_p (exp, *pterm))
220918334Speter    return false_rtx;
221018334Speter
221118334Speter  else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
221218334Speter    return true_rtx;
221318334Speter
221418334Speter  else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
221518334Speter    return true_rtx;
221618334Speter
221718334Speter  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
221818334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
221918334Speter	   && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
222018334Speter    *pterm = false_rtx;
222118334Speter
222218334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
222318334Speter	   && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
222418334Speter	   && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
222518334Speter    return false_rtx;
222618334Speter
222718334Speter  return exp;
222818334Speter}
2229132718Skan
223090075Sobrien/* Compute approximate cost of the expression.  Used to decide whether
223190075Sobrien   expression is cheap enough for inline.  */
223290075Sobrienstatic int
2233132718Skanattr_rtx_cost (rtx x)
223490075Sobrien{
223590075Sobrien  int cost = 0;
223690075Sobrien  enum rtx_code code;
223790075Sobrien  if (!x)
223890075Sobrien    return 0;
223990075Sobrien  code = GET_CODE (x);
224090075Sobrien  switch (code)
224190075Sobrien    {
224290075Sobrien    case MATCH_OPERAND:
224390075Sobrien      if (XSTR (x, 1)[0])
224490075Sobrien	return 10;
224590075Sobrien      else
224690075Sobrien	return 0;
2247132718Skan
2248132718Skan    case EQ_ATTR_ALT:
2249132718Skan      return 0;
2250132718Skan
225190075Sobrien    case EQ_ATTR:
225290075Sobrien      /* Alternatives don't result into function call.  */
2253132718Skan      if (!strcmp_check (XSTR (x, 0), alternative_name))
225490075Sobrien	return 0;
225590075Sobrien      else
225690075Sobrien	return 5;
225790075Sobrien    default:
225890075Sobrien      {
225990075Sobrien	int i, j;
226090075Sobrien	const char *fmt = GET_RTX_FORMAT (code);
226190075Sobrien	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
226290075Sobrien	  {
226390075Sobrien	    switch (fmt[i])
226490075Sobrien	      {
226590075Sobrien	      case 'V':
226690075Sobrien	      case 'E':
226790075Sobrien		for (j = 0; j < XVECLEN (x, i); j++)
226890075Sobrien		  cost += attr_rtx_cost (XVECEXP (x, i, j));
226990075Sobrien		break;
227090075Sobrien	      case 'e':
227190075Sobrien		cost += attr_rtx_cost (XEXP (x, i));
227290075Sobrien		break;
227390075Sobrien	      }
227490075Sobrien	  }
227590075Sobrien      }
227690075Sobrien      break;
227790075Sobrien    }
227890075Sobrien  return cost;
227990075Sobrien}
228090075Sobrien
228190075Sobrien/* Simplify test expression and use temporary obstack in order to avoid
2282132718Skan   memory bloat.  Use ATTR_IND_SIMPLIFIED to avoid unnecessary simplifications
2283132718Skan   and avoid unnecessary copying if possible.  */
228490075Sobrien
228590075Sobrienstatic rtx
2286132718Skansimplify_test_exp_in_temp (rtx exp, int insn_code, int insn_index)
228790075Sobrien{
228890075Sobrien  rtx x;
228990075Sobrien  struct obstack *old;
2290117395Skan  if (ATTR_IND_SIMPLIFIED_P (exp))
229190075Sobrien    return exp;
229290075Sobrien  old = rtl_obstack;
229390075Sobrien  rtl_obstack = temp_obstack;
229490075Sobrien  x = simplify_test_exp (exp, insn_code, insn_index);
229590075Sobrien  rtl_obstack = old;
229690075Sobrien  if (x == exp || rtl_obstack == temp_obstack)
229790075Sobrien    return x;
229890075Sobrien  return attr_copy_rtx (x);
229990075Sobrien}
230090075Sobrien
2301132718Skan/* Returns true if S1 is a subset of S2.  */
2302132718Skan
2303132718Skanstatic bool
2304132718Skanattr_alt_subset_p (rtx s1, rtx s2)
2305132718Skan{
2306132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2307132718Skan    {
2308132718Skan    case (0 << 1) | 0:
2309132718Skan      return !(XINT (s1, 0) &~ XINT (s2, 0));
2310132718Skan
2311132718Skan    case (0 << 1) | 1:
2312132718Skan      return !(XINT (s1, 0) & XINT (s2, 0));
2313132718Skan
2314132718Skan    case (1 << 1) | 0:
2315132718Skan      return false;
2316132718Skan
2317132718Skan    case (1 << 1) | 1:
2318132718Skan      return !(XINT (s2, 0) &~ XINT (s1, 0));
2319132718Skan
2320132718Skan    default:
2321169689Skan      gcc_unreachable ();
2322132718Skan    }
2323132718Skan}
2324132718Skan
2325132718Skan/* Returns true if S1 is a subset of complement of S2.  */
2326132718Skan
2327169689Skanstatic bool
2328169689Skanattr_alt_subset_of_compl_p (rtx s1, rtx s2)
2329132718Skan{
2330132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2331132718Skan    {
2332132718Skan    case (0 << 1) | 0:
2333132718Skan      return !(XINT (s1, 0) & XINT (s2, 0));
2334132718Skan
2335132718Skan    case (0 << 1) | 1:
2336132718Skan      return !(XINT (s1, 0) & ~XINT (s2, 0));
2337132718Skan
2338132718Skan    case (1 << 1) | 0:
2339132718Skan      return !(XINT (s2, 0) &~ XINT (s1, 0));
2340132718Skan
2341132718Skan    case (1 << 1) | 1:
2342132718Skan      return false;
2343132718Skan
2344132718Skan    default:
2345169689Skan      gcc_unreachable ();
2346132718Skan    }
2347132718Skan}
2348132718Skan
2349132718Skan/* Return EQ_ATTR_ALT expression representing intersection of S1 and S2.  */
2350132718Skan
2351132718Skanstatic rtx
2352132718Skanattr_alt_intersection (rtx s1, rtx s2)
2353132718Skan{
2354132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2355132718Skan
2356132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2357132718Skan    {
2358132718Skan    case (0 << 1) | 0:
2359132718Skan      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
2360132718Skan      break;
2361132718Skan    case (0 << 1) | 1:
2362132718Skan      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
2363132718Skan      break;
2364132718Skan    case (1 << 1) | 0:
2365132718Skan      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
2366132718Skan      break;
2367132718Skan    case (1 << 1) | 1:
2368132718Skan      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
2369132718Skan      break;
2370132718Skan    default:
2371169689Skan      gcc_unreachable ();
2372132718Skan    }
2373132718Skan  XINT (result, 1) = XINT (s1, 1) & XINT (s2, 1);
2374132718Skan
2375132718Skan  return result;
2376132718Skan}
2377132718Skan
2378132718Skan/* Return EQ_ATTR_ALT expression representing union of S1 and S2.  */
2379132718Skan
2380132718Skanstatic rtx
2381132718Skanattr_alt_union (rtx s1, rtx s2)
2382132718Skan{
2383132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2384132718Skan
2385132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2386132718Skan    {
2387132718Skan    case (0 << 1) | 0:
2388132718Skan      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
2389132718Skan      break;
2390132718Skan    case (0 << 1) | 1:
2391132718Skan      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
2392132718Skan      break;
2393132718Skan    case (1 << 1) | 0:
2394132718Skan      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
2395132718Skan      break;
2396132718Skan    case (1 << 1) | 1:
2397132718Skan      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
2398132718Skan      break;
2399132718Skan    default:
2400169689Skan      gcc_unreachable ();
2401132718Skan    }
2402132718Skan
2403132718Skan  XINT (result, 1) = XINT (s1, 1) | XINT (s2, 1);
2404132718Skan  return result;
2405132718Skan}
2406132718Skan
2407132718Skan/* Return EQ_ATTR_ALT expression representing complement of S.  */
2408132718Skan
2409132718Skanstatic rtx
2410132718Skanattr_alt_complement (rtx s)
2411132718Skan{
2412132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2413132718Skan
2414132718Skan  XINT (result, 0) = XINT (s, 0);
2415132718Skan  XINT (result, 1) = 1 - XINT (s, 1);
2416132718Skan
2417132718Skan  return result;
2418132718Skan}
2419132718Skan
2420132718Skan/* Return EQ_ATTR_ALT expression representing set containing elements set
2421132718Skan   in E.  */
2422132718Skan
2423132718Skanstatic rtx
2424132718Skanmk_attr_alt (int e)
2425132718Skan{
2426132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2427132718Skan
2428132718Skan  XINT (result, 0) = e;
2429132718Skan  XINT (result, 1) = 0;
2430132718Skan
2431132718Skan  return result;
2432132718Skan}
2433132718Skan
243418334Speter/* Given an expression, see if it can be simplified for a particular insn
243518334Speter   code based on the values of other attributes being tested.  This can
243618334Speter   eliminate nested get_attr_... calls.
243718334Speter
243890075Sobrien   Note that if an endless recursion is specified in the patterns, the
243918334Speter   optimization will loop.  However, it will do so in precisely the cases where
244018334Speter   an infinite recursion loop could occur during compilation.  It's better that
244118334Speter   it occurs here!  */
244218334Speter
244318334Speterstatic rtx
2444132718Skansimplify_test_exp (rtx exp, int insn_code, int insn_index)
244518334Speter{
244618334Speter  rtx left, right;
244718334Speter  struct attr_desc *attr;
244818334Speter  struct attr_value *av;
244918334Speter  struct insn_ent *ie;
245018334Speter  int i;
245118334Speter  rtx newexp = exp;
2452132718Skan  bool left_alt, right_alt;
245318334Speter
245418334Speter  /* Don't re-simplify something we already simplified.  */
2455117395Skan  if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
245618334Speter    return exp;
245718334Speter
245818334Speter  switch (GET_CODE (exp))
245918334Speter    {
246018334Speter    case AND:
246118334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
246218334Speter      if (left == false_rtx)
246390075Sobrien	return false_rtx;
246418334Speter      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
2465169689Skan      if (right == false_rtx)
246690075Sobrien	return false_rtx;
246718334Speter
2468132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT
2469132718Skan	  && GET_CODE (right) == EQ_ATTR_ALT)
2470132718Skan	{
2471132718Skan	  exp = attr_alt_intersection (left, right);
2472132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2473132718Skan	}
2474132718Skan
247518334Speter      /* If either side is an IOR and we have (eq_attr "alternative" ..")
247618334Speter	 present on both sides, apply the distributive law since this will
247718334Speter	 yield simplifications.  */
247818334Speter      if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR)
247918334Speter	  && compute_alternative_mask (left, IOR)
248018334Speter	  && compute_alternative_mask (right, IOR))
248118334Speter	{
248218334Speter	  if (GET_CODE (left) == IOR)
248318334Speter	    {
248418334Speter	      rtx tem = left;
248518334Speter	      left = right;
248618334Speter	      right = tem;
248718334Speter	    }
248818334Speter
248918334Speter	  newexp = attr_rtx (IOR,
249018334Speter			     attr_rtx (AND, left, XEXP (right, 0)),
249118334Speter			     attr_rtx (AND, left, XEXP (right, 1)));
249218334Speter
249318334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
249418334Speter	}
249518334Speter
249618334Speter      /* Try with the term on both sides.  */
249718334Speter      right = simplify_and_tree (right, &left, insn_code, insn_index);
249818334Speter      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
249918334Speter	left = simplify_and_tree (left, &right, insn_code, insn_index);
250018334Speter
250118334Speter      if (left == false_rtx || right == false_rtx)
250290075Sobrien	return false_rtx;
250318334Speter      else if (left == true_rtx)
250418334Speter	{
250518334Speter	  return right;
250618334Speter	}
250718334Speter      else if (right == true_rtx)
250818334Speter	{
250918334Speter	  return left;
251018334Speter	}
251118334Speter      /* See if all or all but one of the insn's alternatives are specified
251218334Speter	 in this tree.  Optimize if so.  */
251318334Speter
2514132718Skan      if (GET_CODE (left) == NOT)
2515132718Skan	left_alt = (GET_CODE (XEXP (left, 0)) == EQ_ATTR
2516132718Skan		    && XSTR (XEXP (left, 0), 0) == alternative_name);
2517132718Skan      else
2518132718Skan	left_alt = (GET_CODE (left) == EQ_ATTR_ALT
2519132718Skan		    && XINT (left, 1));
2520132718Skan
2521132718Skan      if (GET_CODE (right) == NOT)
2522132718Skan	right_alt = (GET_CODE (XEXP (right, 0)) == EQ_ATTR
2523132718Skan		     && XSTR (XEXP (right, 0), 0) == alternative_name);
2524132718Skan      else
2525132718Skan	right_alt = (GET_CODE (right) == EQ_ATTR_ALT
2526132718Skan		     && XINT (right, 1));
2527132718Skan
2528132718Skan      if (insn_code >= 0
2529132718Skan	  && (GET_CODE (left) == AND
2530132718Skan	      || left_alt
2531132718Skan	      || GET_CODE (right) == AND
2532132718Skan	      || right_alt))
253318334Speter	{
253418334Speter	  i = compute_alternative_mask (exp, AND);
253518334Speter	  if (i & ~insn_alternatives[insn_code])
253690075Sobrien	    fatal ("invalid alternative specified for pattern number %d",
253718334Speter		   insn_index);
253818334Speter
253950397Sobrien	  /* If all alternatives are excluded, this is false.  */
254018334Speter	  i ^= insn_alternatives[insn_code];
254118334Speter	  if (i == 0)
254218334Speter	    return false_rtx;
254318334Speter	  else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
254418334Speter	    {
254518334Speter	      /* If just one excluded, AND a comparison with that one to the
254618334Speter		 front of the tree.  The others will be eliminated by
254718334Speter		 optimization.  We do not want to do this if the insn has one
254818334Speter		 alternative and we have tested none of them!  */
254918334Speter	      left = make_alternative_compare (i);
255018334Speter	      right = simplify_and_tree (exp, &left, insn_code, insn_index);
255118334Speter	      newexp = attr_rtx (AND, left, right);
255218334Speter
255318334Speter	      return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
255418334Speter	    }
255518334Speter	}
255618334Speter
255718334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
255818334Speter	{
255918334Speter	  newexp = attr_rtx (AND, left, right);
256018334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
256118334Speter	}
256218334Speter      break;
256318334Speter
256418334Speter    case IOR:
256518334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
256618334Speter      if (left == true_rtx)
256790075Sobrien	return true_rtx;
256818334Speter      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
256918334Speter      if (right == true_rtx)
257090075Sobrien	return true_rtx;
257118334Speter
2572132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT
2573132718Skan	  && GET_CODE (right) == EQ_ATTR_ALT)
2574132718Skan	{
2575132718Skan	  exp = attr_alt_union (left, right);
2576132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2577132718Skan	}
2578132718Skan
257918334Speter      right = simplify_or_tree (right, &left, insn_code, insn_index);
258018334Speter      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
258118334Speter	left = simplify_or_tree (left, &right, insn_code, insn_index);
258218334Speter
258318334Speter      if (right == true_rtx || left == true_rtx)
258490075Sobrien	return true_rtx;
258518334Speter      else if (left == false_rtx)
258618334Speter	{
258718334Speter	  return right;
258818334Speter	}
258918334Speter      else if (right == false_rtx)
259018334Speter	{
259118334Speter	  return left;
259218334Speter	}
259318334Speter
259418334Speter      /* Test for simple cases where the distributive law is useful.  I.e.,
259518334Speter	    convert (ior (and (x) (y))
259618334Speter			 (and (x) (z)))
259718334Speter	    to      (and (x)
259818334Speter			 (ior (y) (z)))
259918334Speter       */
260018334Speter
260118334Speter      else if (GET_CODE (left) == AND && GET_CODE (right) == AND
260290075Sobrien	       && attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
260318334Speter	{
260418334Speter	  newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
260518334Speter
260618334Speter	  left = XEXP (left, 0);
260718334Speter	  right = newexp;
260818334Speter	  newexp = attr_rtx (AND, left, right);
260918334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
261018334Speter	}
261118334Speter
261218334Speter      /* See if all or all but one of the insn's alternatives are specified
261318334Speter	 in this tree.  Optimize if so.  */
261418334Speter
261518334Speter      else if (insn_code >= 0
261690075Sobrien	       && (GET_CODE (left) == IOR
2617132718Skan		   || (GET_CODE (left) == EQ_ATTR_ALT
2618132718Skan		       && !XINT (left, 1))
261990075Sobrien		   || (GET_CODE (left) == EQ_ATTR
262090075Sobrien		       && XSTR (left, 0) == alternative_name)
262190075Sobrien		   || GET_CODE (right) == IOR
2622132718Skan		   || (GET_CODE (right) == EQ_ATTR_ALT
2623132718Skan		       && !XINT (right, 1))
262490075Sobrien		   || (GET_CODE (right) == EQ_ATTR
262590075Sobrien		       && XSTR (right, 0) == alternative_name)))
262618334Speter	{
262718334Speter	  i = compute_alternative_mask (exp, IOR);
262818334Speter	  if (i & ~insn_alternatives[insn_code])
262990075Sobrien	    fatal ("invalid alternative specified for pattern number %d",
263018334Speter		   insn_index);
263118334Speter
263250397Sobrien	  /* If all alternatives are included, this is true.  */
263318334Speter	  i ^= insn_alternatives[insn_code];
263418334Speter	  if (i == 0)
263518334Speter	    return true_rtx;
263618334Speter	  else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
263718334Speter	    {
263818334Speter	      /* If just one excluded, IOR a comparison with that one to the
263918334Speter		 front of the tree.  The others will be eliminated by
264018334Speter		 optimization.  We do not want to do this if the insn has one
264118334Speter		 alternative and we have tested none of them!  */
264218334Speter	      left = make_alternative_compare (i);
264318334Speter	      right = simplify_and_tree (exp, &left, insn_code, insn_index);
264418334Speter	      newexp = attr_rtx (IOR, attr_rtx (NOT, left), right);
264518334Speter
264618334Speter	      return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
264718334Speter	    }
264818334Speter	}
264918334Speter
265018334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
265118334Speter	{
265218334Speter	  newexp = attr_rtx (IOR, left, right);
265318334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
265418334Speter	}
265518334Speter      break;
265618334Speter
265718334Speter    case NOT:
265818334Speter      if (GET_CODE (XEXP (exp, 0)) == NOT)
265918334Speter	{
266018334Speter	  left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
266118334Speter				    insn_code, insn_index);
266218334Speter	  return left;
266318334Speter	}
266418334Speter
266518334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
266618334Speter      if (GET_CODE (left) == NOT)
266718334Speter	return XEXP (left, 0);
266818334Speter
266918334Speter      if (left == false_rtx)
267090075Sobrien	return true_rtx;
2671132718Skan      if (left == true_rtx)
267290075Sobrien	return false_rtx;
267318334Speter
2674132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT)
2675132718Skan	{
2676132718Skan	  exp = attr_alt_complement (left);
2677132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2678132718Skan	}
2679132718Skan
268018334Speter      /* Try to apply De`Morgan's laws.  */
2681132718Skan      if (GET_CODE (left) == IOR)
268218334Speter	{
268318334Speter	  newexp = attr_rtx (AND,
268418334Speter			     attr_rtx (NOT, XEXP (left, 0)),
268518334Speter			     attr_rtx (NOT, XEXP (left, 1)));
268618334Speter
268718334Speter	  newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
268818334Speter	}
268918334Speter      else if (GET_CODE (left) == AND)
269018334Speter	{
269118334Speter	  newexp = attr_rtx (IOR,
269218334Speter			     attr_rtx (NOT, XEXP (left, 0)),
269318334Speter			     attr_rtx (NOT, XEXP (left, 1)));
269418334Speter
269518334Speter	  newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
269618334Speter	}
269718334Speter      else if (left != XEXP (exp, 0))
269818334Speter	{
269918334Speter	  newexp = attr_rtx (NOT, left);
270018334Speter	}
270118334Speter      break;
270218334Speter
2703132718Skan    case EQ_ATTR_ALT:
2704132718Skan      if (!XINT (exp, 0))
2705132718Skan	return XINT (exp, 1) ? true_rtx : false_rtx;
2706132718Skan      break;
2707132718Skan
270818334Speter    case EQ_ATTR:
2709132718Skan      if (XSTR (exp, 0) == alternative_name)
2710132718Skan	{
2711132718Skan	  newexp = mk_attr_alt (1 << atoi (XSTR (exp, 1)));
2712132718Skan	  break;
2713132718Skan	}
2714132718Skan
271518334Speter      /* Look at the value for this insn code in the specified attribute.
271618334Speter	 We normally can replace this comparison with the condition that
271790075Sobrien	 would give this insn the values being tested for.  */
2718169689Skan      if (insn_code >= 0
2719132718Skan	  && (attr = find_attr (&XSTR (exp, 0), 0)) != NULL)
272018334Speter	for (av = attr->first_value; av; av = av->next)
272118334Speter	  for (ie = av->first_insn; ie; ie = ie->next)
2722169689Skan	    if (ie->def->insn_code == insn_code)
272390075Sobrien	      {
272490075Sobrien		rtx x;
272590075Sobrien		x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
272690075Sobrien		x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
272790075Sobrien		if (attr_rtx_cost(x) < 20)
272890075Sobrien		  return x;
272990075Sobrien	      }
273050397Sobrien      break;
273190075Sobrien
273250397Sobrien    default:
273350397Sobrien      break;
273418334Speter    }
273518334Speter
273618334Speter  /* We have already simplified this expression.  Simplifying it again
273718334Speter     won't buy anything unless we weren't given a valid insn code
273818334Speter     to process (i.e., we are canonicalizing something.).  */
2739169689Skan  if (insn_code != -2
2740117395Skan      && ! ATTR_IND_SIMPLIFIED_P (newexp))
274118334Speter    return copy_rtx_unchanging (newexp);
274218334Speter
274318334Speter  return newexp;
274418334Speter}
2745132718Skan
274618334Speter/* Optimize the attribute lists by seeing if we can determine conditional
274718334Speter   values from the known values of other attributes.  This will save subroutine
274818334Speter   calls during the compilation.  */
274918334Speter
275018334Speterstatic void
2751132718Skanoptimize_attrs (void)
275218334Speter{
275318334Speter  struct attr_desc *attr;
275418334Speter  struct attr_value *av;
275518334Speter  struct insn_ent *ie;
275618334Speter  rtx newexp;
275718334Speter  int i;
275890075Sobrien  struct attr_value_list
275990075Sobrien  {
276090075Sobrien    struct attr_value *av;
276190075Sobrien    struct insn_ent *ie;
276290075Sobrien    struct attr_desc *attr;
276390075Sobrien    struct attr_value_list *next;
276490075Sobrien  };
276518334Speter  struct attr_value_list **insn_code_values;
276618334Speter  struct attr_value_list *ivbuf;
276718334Speter  struct attr_value_list *iv;
276818334Speter
276918334Speter  /* For each insn code, make a list of all the insn_ent's for it,
277018334Speter     for all values for all attributes.  */
277118334Speter
277218334Speter  if (num_insn_ents == 0)
277318334Speter    return;
277418334Speter
277518334Speter  /* Make 2 extra elements, for "code" values -2 and -1.  */
2776169689Skan  insn_code_values = XCNEWVEC (struct attr_value_list *, insn_code_number + 2);
277718334Speter
277818334Speter  /* Offset the table address so we can index by -2 or -1.  */
277918334Speter  insn_code_values += 2;
278018334Speter
2781169689Skan  iv = ivbuf = XNEWVEC (struct attr_value_list, num_insn_ents);
278218334Speter
278318334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
278418334Speter    for (attr = attrs[i]; attr; attr = attr->next)
278518334Speter      for (av = attr->first_value; av; av = av->next)
278618334Speter	for (ie = av->first_insn; ie; ie = ie->next)
278718334Speter	  {
278818334Speter	    iv->attr = attr;
278918334Speter	    iv->av = av;
279018334Speter	    iv->ie = ie;
2791169689Skan	    iv->next = insn_code_values[ie->def->insn_code];
2792169689Skan	    insn_code_values[ie->def->insn_code] = iv;
279318334Speter	    iv++;
279418334Speter	  }
279518334Speter
279618334Speter  /* Sanity check on num_insn_ents.  */
2797169689Skan  gcc_assert (iv == ivbuf + num_insn_ents);
279818334Speter
279918334Speter  /* Process one insn code at a time.  */
280018334Speter  for (i = -2; i < insn_code_number; i++)
280118334Speter    {
2802117395Skan      /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant.
280318334Speter	 We use it to mean "already simplified for this insn".  */
280418334Speter      for (iv = insn_code_values[i]; iv; iv = iv->next)
280518334Speter	clear_struct_flag (iv->av->value);
280618334Speter
280790075Sobrien      for (iv = insn_code_values[i]; iv; iv = iv->next)
280818334Speter	{
280990075Sobrien	  struct obstack *old = rtl_obstack;
281018334Speter
281190075Sobrien	  attr = iv->attr;
281290075Sobrien	  av = iv->av;
281390075Sobrien	  ie = iv->ie;
281490075Sobrien	  if (GET_CODE (av->value) != COND)
281590075Sobrien	    continue;
281618334Speter
281790075Sobrien	  rtl_obstack = temp_obstack;
281890075Sobrien	  newexp = av->value;
281990075Sobrien	  while (GET_CODE (newexp) == COND)
282090075Sobrien	    {
2821169689Skan	      rtx newexp2 = simplify_cond (newexp, ie->def->insn_code,
2822169689Skan					   ie->def->insn_index);
282390075Sobrien	      if (newexp2 == newexp)
282490075Sobrien		break;
282590075Sobrien	      newexp = newexp2;
282690075Sobrien	    }
282718334Speter
282890075Sobrien	  rtl_obstack = old;
282990075Sobrien	  if (newexp != av->value)
283090075Sobrien	    {
283190075Sobrien	      newexp = attr_copy_rtx (newexp);
283290075Sobrien	      remove_insn_ent (av, ie);
2833169689Skan	      av = get_attr_value (newexp, attr, ie->def->insn_code);
283490075Sobrien	      iv->av = av;
283590075Sobrien	      insert_insn_ent (av, ie);
283618334Speter	    }
283718334Speter	}
283818334Speter    }
283918334Speter
284018334Speter  free (ivbuf);
284190075Sobrien  free (insn_code_values - 2);
284218334Speter}
284318334Speter
2844117395Skan/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions.  */
284518334Speter
284618334Speterstatic void
2847132718Skanclear_struct_flag (rtx x)
284818334Speter{
284990075Sobrien  int i;
285090075Sobrien  int j;
285190075Sobrien  enum rtx_code code;
285290075Sobrien  const char *fmt;
285318334Speter
2854117395Skan  ATTR_CURR_SIMPLIFIED_P (x) = 0;
2855117395Skan  if (ATTR_IND_SIMPLIFIED_P (x))
285618334Speter    return;
285718334Speter
285818334Speter  code = GET_CODE (x);
285918334Speter
286018334Speter  switch (code)
286118334Speter    {
286218334Speter    case REG:
286318334Speter    case CONST_INT:
286418334Speter    case CONST_DOUBLE:
286596263Sobrien    case CONST_VECTOR:
286618334Speter    case SYMBOL_REF:
286718334Speter    case CODE_LABEL:
286818334Speter    case PC:
286918334Speter    case CC0:
287018334Speter    case EQ_ATTR:
287118334Speter    case ATTR_FLAG:
287218334Speter      return;
287390075Sobrien
287450397Sobrien    default:
287550397Sobrien      break;
287618334Speter    }
287718334Speter
287818334Speter  /* Compare the elements.  If any pair of corresponding elements
287918334Speter     fail to match, return 0 for the whole things.  */
288018334Speter
288118334Speter  fmt = GET_RTX_FORMAT (code);
288218334Speter  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
288318334Speter    {
288418334Speter      switch (fmt[i])
288518334Speter	{
288618334Speter	case 'V':
288718334Speter	case 'E':
288818334Speter	  for (j = 0; j < XVECLEN (x, i); j++)
288918334Speter	    clear_struct_flag (XVECEXP (x, i, j));
289018334Speter	  break;
289118334Speter
289218334Speter	case 'e':
289318334Speter	  clear_struct_flag (XEXP (x, i));
289418334Speter	  break;
289518334Speter	}
289618334Speter    }
289718334Speter}
289818334Speter
289918334Speter/* Create table entries for DEFINE_ATTR.  */
290018334Speter
290118334Speterstatic void
2902132718Skangen_attr (rtx exp, int lineno)
290318334Speter{
290418334Speter  struct attr_desc *attr;
290518334Speter  struct attr_value *av;
290690075Sobrien  const char *name_ptr;
290718334Speter  char *p;
290818334Speter
290918334Speter  /* Make a new attribute structure.  Check for duplicate by looking at
291018334Speter     attr->default_val, since it is initialized by this routine.  */
2911132718Skan  attr = find_attr (&XSTR (exp, 0), 1);
291218334Speter  if (attr->default_val)
291390075Sobrien    {
291490075Sobrien      message_with_line (lineno, "duplicate definition for attribute %s",
291590075Sobrien			 attr->name);
291690075Sobrien      message_with_line (attr->lineno, "previous definition");
291790075Sobrien      have_error = 1;
291890075Sobrien      return;
291990075Sobrien    }
292090075Sobrien  attr->lineno = lineno;
292118334Speter
292218334Speter  if (*XSTR (exp, 1) == '\0')
292352284Sobrien    attr->is_numeric = 1;
292418334Speter  else
292518334Speter    {
292618334Speter      name_ptr = XSTR (exp, 1);
292718334Speter      while ((p = next_comma_elt (&name_ptr)) != NULL)
292818334Speter	{
2929132718Skan	  av = oballoc (sizeof (struct attr_value));
293018334Speter	  av->value = attr_rtx (CONST_STRING, p);
293118334Speter	  av->next = attr->first_value;
293218334Speter	  attr->first_value = av;
293318334Speter	  av->first_insn = NULL;
293418334Speter	  av->num_insns = 0;
293518334Speter	  av->has_asm_insn = 0;
293618334Speter	}
293718334Speter    }
293818334Speter
293918334Speter  if (GET_CODE (XEXP (exp, 2)) == CONST)
294018334Speter    {
294118334Speter      attr->is_const = 1;
294218334Speter      if (attr->is_numeric)
294390075Sobrien	{
294490075Sobrien	  message_with_line (lineno,
294590075Sobrien			     "constant attributes may not take numeric values");
294690075Sobrien	  have_error = 1;
294790075Sobrien	}
294890075Sobrien
294918334Speter      /* Get rid of the CONST node.  It is allowed only at top-level.  */
295018334Speter      XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
295118334Speter    }
295218334Speter
2953132718Skan  if (! strcmp_check (attr->name, length_str) && ! attr->is_numeric)
295490075Sobrien    {
295590075Sobrien      message_with_line (lineno,
295690075Sobrien			 "`length' attribute must take numeric values");
295790075Sobrien      have_error = 1;
295890075Sobrien    }
295918334Speter
296050397Sobrien  /* Set up the default value.  */
296118334Speter  XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
296218334Speter  attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
296318334Speter}
2964132718Skan
296518334Speter/* Given a pattern for DEFINE_PEEPHOLE or DEFINE_INSN, return the number of
296618334Speter   alternatives in the constraints.  Assume all MATCH_OPERANDs have the same
296718334Speter   number of alternatives as this should be checked elsewhere.  */
296818334Speter
296918334Speterstatic int
2970132718Skancount_alternatives (rtx exp)
297118334Speter{
297218334Speter  int i, j, n;
297390075Sobrien  const char *fmt;
297490075Sobrien
297518334Speter  if (GET_CODE (exp) == MATCH_OPERAND)
297618334Speter    return n_comma_elts (XSTR (exp, 2));
297718334Speter
297818334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
297918334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
298018334Speter    switch (*fmt++)
298118334Speter      {
298218334Speter      case 'e':
298318334Speter      case 'u':
298418334Speter	n = count_alternatives (XEXP (exp, i));
298518334Speter	if (n)
298618334Speter	  return n;
298718334Speter	break;
298818334Speter
298918334Speter      case 'E':
299018334Speter      case 'V':
299118334Speter	if (XVEC (exp, i) != NULL)
299218334Speter	  for (j = 0; j < XVECLEN (exp, i); j++)
299318334Speter	    {
299418334Speter	      n = count_alternatives (XVECEXP (exp, i, j));
299518334Speter	      if (n)
299618334Speter		return n;
299718334Speter	    }
299818334Speter      }
299918334Speter
300018334Speter  return 0;
300118334Speter}
3002132718Skan
3003117395Skan/* Returns nonzero if the given expression contains an EQ_ATTR with the
300418334Speter   `alternative' attribute.  */
300518334Speter
300618334Speterstatic int
3007132718Skancompares_alternatives_p (rtx exp)
300818334Speter{
300918334Speter  int i, j;
301090075Sobrien  const char *fmt;
301118334Speter
301218334Speter  if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name)
301318334Speter    return 1;
301418334Speter
301518334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
301618334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
301718334Speter    switch (*fmt++)
301818334Speter      {
301918334Speter      case 'e':
302018334Speter      case 'u':
302118334Speter	if (compares_alternatives_p (XEXP (exp, i)))
302218334Speter	  return 1;
302318334Speter	break;
302418334Speter
302518334Speter      case 'E':
302618334Speter	for (j = 0; j < XVECLEN (exp, i); j++)
302718334Speter	  if (compares_alternatives_p (XVECEXP (exp, i, j)))
302818334Speter	    return 1;
302918334Speter	break;
303018334Speter      }
303118334Speter
303218334Speter  return 0;
303318334Speter}
3034132718Skan
3035117395Skan/* Returns nonzero is INNER is contained in EXP.  */
303618334Speter
303718334Speterstatic int
3038132718Skancontained_in_p (rtx inner, rtx exp)
303918334Speter{
304018334Speter  int i, j;
304190075Sobrien  const char *fmt;
304218334Speter
304318334Speter  if (rtx_equal_p (inner, exp))
304418334Speter    return 1;
304518334Speter
304618334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
304718334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
304818334Speter    switch (*fmt++)
304918334Speter      {
305018334Speter      case 'e':
305118334Speter      case 'u':
305218334Speter	if (contained_in_p (inner, XEXP (exp, i)))
305318334Speter	  return 1;
305418334Speter	break;
305518334Speter
305618334Speter      case 'E':
305718334Speter	for (j = 0; j < XVECLEN (exp, i); j++)
305818334Speter	  if (contained_in_p (inner, XVECEXP (exp, i, j)))
305918334Speter	    return 1;
306018334Speter	break;
306118334Speter      }
306218334Speter
306318334Speter  return 0;
306418334Speter}
3065132718Skan
306618334Speter/* Process DEFINE_PEEPHOLE, DEFINE_INSN, and DEFINE_ASM_ATTRIBUTES.  */
306718334Speter
306818334Speterstatic void
3069132718Skangen_insn (rtx exp, int lineno)
307018334Speter{
307118334Speter  struct insn_def *id;
307218334Speter
3073132718Skan  id = oballoc (sizeof (struct insn_def));
307418334Speter  id->next = defs;
307518334Speter  defs = id;
307618334Speter  id->def = exp;
307790075Sobrien  id->lineno = lineno;
307818334Speter
307918334Speter  switch (GET_CODE (exp))
308018334Speter    {
308118334Speter    case DEFINE_INSN:
308290075Sobrien      id->insn_code = insn_code_number;
308390075Sobrien      id->insn_index = insn_index_number;
308418334Speter      id->num_alternatives = count_alternatives (exp);
308518334Speter      if (id->num_alternatives == 0)
308618334Speter	id->num_alternatives = 1;
308718334Speter      id->vec_idx = 4;
308818334Speter      break;
308918334Speter
309018334Speter    case DEFINE_PEEPHOLE:
309190075Sobrien      id->insn_code = insn_code_number;
309290075Sobrien      id->insn_index = insn_index_number;
309318334Speter      id->num_alternatives = count_alternatives (exp);
309418334Speter      if (id->num_alternatives == 0)
309518334Speter	id->num_alternatives = 1;
309618334Speter      id->vec_idx = 3;
309718334Speter      break;
309818334Speter
309918334Speter    case DEFINE_ASM_ATTRIBUTES:
310018334Speter      id->insn_code = -1;
310118334Speter      id->insn_index = -1;
310218334Speter      id->num_alternatives = 1;
310318334Speter      id->vec_idx = 0;
310418334Speter      got_define_asm_attributes = 1;
310518334Speter      break;
310690075Sobrien
310750397Sobrien    default:
3108169689Skan      gcc_unreachable ();
310918334Speter    }
311018334Speter}
3111132718Skan
311218334Speter/* Process a DEFINE_DELAY.  Validate the vector length, check if annul
311318334Speter   true or annul false is specified, and make a `struct delay_desc'.  */
311418334Speter
311518334Speterstatic void
3116132718Skangen_delay (rtx def, int lineno)
311718334Speter{
311818334Speter  struct delay_desc *delay;
311918334Speter  int i;
312018334Speter
312118334Speter  if (XVECLEN (def, 1) % 3 != 0)
312290075Sobrien    {
312390075Sobrien      message_with_line (lineno,
312490075Sobrien			 "number of elements in DEFINE_DELAY must be multiple of three");
312590075Sobrien      have_error = 1;
312690075Sobrien      return;
312790075Sobrien    }
312818334Speter
312918334Speter  for (i = 0; i < XVECLEN (def, 1); i += 3)
313018334Speter    {
313118334Speter      if (XVECEXP (def, 1, i + 1))
313218334Speter	have_annul_true = 1;
313318334Speter      if (XVECEXP (def, 1, i + 2))
313418334Speter	have_annul_false = 1;
313518334Speter    }
313690075Sobrien
3137132718Skan  delay = oballoc (sizeof (struct delay_desc));
313818334Speter  delay->def = def;
313918334Speter  delay->num = ++num_delays;
314018334Speter  delay->next = delays;
314190075Sobrien  delay->lineno = lineno;
314218334Speter  delays = delay;
314318334Speter}
3144132718Skan
314550397Sobrien/* Given a piece of RTX, print a C expression to test its truth value.
314690075Sobrien   We use AND and IOR both for logical and bit-wise operations, so
314718334Speter   interpret them as logical unless they are inside a comparison expression.
3148117395Skan   The first bit of FLAGS will be nonzero in that case.
314918334Speter
315050397Sobrien   Set the second bit of FLAGS to make references to attribute values use
315150397Sobrien   a cached local variable instead of calling a function.  */
315250397Sobrien
315318334Speterstatic void
3154132718Skanwrite_test_expr (rtx exp, int flags)
315518334Speter{
315618334Speter  int comparison_operator = 0;
315718334Speter  RTX_CODE code;
315818334Speter  struct attr_desc *attr;
315918334Speter
316018334Speter  /* In order not to worry about operator precedence, surround our part of
316118334Speter     the expression with parentheses.  */
316218334Speter
316318334Speter  printf ("(");
316418334Speter  code = GET_CODE (exp);
316518334Speter  switch (code)
316618334Speter    {
316718334Speter    /* Binary operators.  */
3168169689Skan    case GEU: case GTU:
3169169689Skan    case LEU: case LTU:
3170169689Skan      printf ("(unsigned) ");
3171169689Skan      /* Fall through.  */
3172169689Skan
317318334Speter    case EQ: case NE:
3174169689Skan    case GE: case GT:
3175169689Skan    case LE: case LT:
317618334Speter      comparison_operator = 1;
317718334Speter
317818334Speter    case PLUS:   case MINUS:  case MULT:     case DIV:      case MOD:
317918334Speter    case AND:    case IOR:    case XOR:
318018334Speter    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
318150397Sobrien      write_test_expr (XEXP (exp, 0), flags | comparison_operator);
318218334Speter      switch (code)
318390075Sobrien	{
318418334Speter	case EQ:
318518334Speter	  printf (" == ");
318618334Speter	  break;
318718334Speter	case NE:
318818334Speter	  printf (" != ");
318918334Speter	  break;
319018334Speter	case GE:
319118334Speter	  printf (" >= ");
319218334Speter	  break;
319318334Speter	case GT:
319418334Speter	  printf (" > ");
319518334Speter	  break;
319618334Speter	case GEU:
319718334Speter	  printf (" >= (unsigned) ");
319818334Speter	  break;
319918334Speter	case GTU:
320018334Speter	  printf (" > (unsigned) ");
320118334Speter	  break;
320218334Speter	case LE:
320318334Speter	  printf (" <= ");
320418334Speter	  break;
320518334Speter	case LT:
320618334Speter	  printf (" < ");
320718334Speter	  break;
320818334Speter	case LEU:
320918334Speter	  printf (" <= (unsigned) ");
321018334Speter	  break;
321118334Speter	case LTU:
321218334Speter	  printf (" < (unsigned) ");
321318334Speter	  break;
321418334Speter	case PLUS:
321518334Speter	  printf (" + ");
321618334Speter	  break;
321718334Speter	case MINUS:
321818334Speter	  printf (" - ");
321918334Speter	  break;
322018334Speter	case MULT:
322118334Speter	  printf (" * ");
322218334Speter	  break;
322318334Speter	case DIV:
322418334Speter	  printf (" / ");
322518334Speter	  break;
322618334Speter	case MOD:
322718334Speter	  printf (" %% ");
322818334Speter	  break;
322918334Speter	case AND:
323050397Sobrien	  if (flags & 1)
323118334Speter	    printf (" & ");
323218334Speter	  else
323318334Speter	    printf (" && ");
323418334Speter	  break;
323518334Speter	case IOR:
323650397Sobrien	  if (flags & 1)
323718334Speter	    printf (" | ");
323818334Speter	  else
323918334Speter	    printf (" || ");
324018334Speter	  break;
324118334Speter	case XOR:
324218334Speter	  printf (" ^ ");
324318334Speter	  break;
324418334Speter	case ASHIFT:
324518334Speter	  printf (" << ");
324618334Speter	  break;
324718334Speter	case LSHIFTRT:
324818334Speter	case ASHIFTRT:
324918334Speter	  printf (" >> ");
325018334Speter	  break;
325150397Sobrien	default:
3252169689Skan	  gcc_unreachable ();
325390075Sobrien	}
325418334Speter
325550397Sobrien      write_test_expr (XEXP (exp, 1), flags | comparison_operator);
325618334Speter      break;
325718334Speter
325818334Speter    case NOT:
325918334Speter      /* Special-case (not (eq_attrq "alternative" "x")) */
326050397Sobrien      if (! (flags & 1) && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
326118334Speter	  && XSTR (XEXP (exp, 0), 0) == alternative_name)
326218334Speter	{
326318334Speter	  printf ("which_alternative != %s", XSTR (XEXP (exp, 0), 1));
326418334Speter	  break;
326518334Speter	}
326618334Speter
326718334Speter      /* Otherwise, fall through to normal unary operator.  */
326818334Speter
326990075Sobrien    /* Unary operators.  */
327018334Speter    case ABS:  case NEG:
327118334Speter      switch (code)
327218334Speter	{
327318334Speter	case NOT:
327450397Sobrien	  if (flags & 1)
327518334Speter	    printf ("~ ");
327618334Speter	  else
327718334Speter	    printf ("! ");
327818334Speter	  break;
327918334Speter	case ABS:
328018334Speter	  printf ("abs ");
328118334Speter	  break;
328218334Speter	case NEG:
328318334Speter	  printf ("-");
328418334Speter	  break;
328550397Sobrien	default:
3286169689Skan	  gcc_unreachable ();
328718334Speter	}
328818334Speter
328950397Sobrien      write_test_expr (XEXP (exp, 0), flags);
329018334Speter      break;
329118334Speter
3292132718Skan    case EQ_ATTR_ALT:
3293132718Skan	{
3294132718Skan	  int set = XINT (exp, 0), bit = 0;
3295132718Skan
3296132718Skan	  if (flags & 1)
3297132718Skan	    fatal ("EQ_ATTR_ALT not valid inside comparison");
3298132718Skan
3299132718Skan	  if (!set)
3300132718Skan	    fatal ("Empty EQ_ATTR_ALT should be optimized out");
3301132718Skan
3302132718Skan	  if (!(set & (set - 1)))
3303132718Skan	    {
3304132718Skan	      if (!(set & 0xffff))
3305132718Skan		{
3306132718Skan		  bit += 16;
3307132718Skan		  set >>= 16;
3308132718Skan		}
3309132718Skan	      if (!(set & 0xff))
3310132718Skan		{
3311132718Skan		  bit += 8;
3312132718Skan		  set >>= 8;
3313132718Skan		}
3314132718Skan	      if (!(set & 0xf))
3315132718Skan		{
3316132718Skan		  bit += 4;
3317132718Skan		  set >>= 4;
3318132718Skan		}
3319132718Skan	      if (!(set & 0x3))
3320132718Skan		{
3321132718Skan		  bit += 2;
3322132718Skan		  set >>= 2;
3323132718Skan		}
3324132718Skan	      if (!(set & 1))
3325132718Skan		bit++;
3326132718Skan
3327132718Skan	      printf ("which_alternative %s= %d",
3328132718Skan		      XINT (exp, 1) ? "!" : "=", bit);
3329132718Skan	    }
3330132718Skan	  else
3331132718Skan	    {
3332132718Skan	      printf ("%s((1 << which_alternative) & 0x%x)",
3333132718Skan		      XINT (exp, 1) ? "!" : "", set);
3334132718Skan	    }
3335132718Skan	}
3336132718Skan      break;
3337132718Skan
333818334Speter    /* Comparison test of an attribute with a value.  Most of these will
333918334Speter       have been removed by optimization.   Handle "alternative"
334018334Speter       specially and give error if EQ_ATTR present inside a comparison.  */
334118334Speter    case EQ_ATTR:
334250397Sobrien      if (flags & 1)
334318334Speter	fatal ("EQ_ATTR not valid inside comparison");
334418334Speter
334518334Speter      if (XSTR (exp, 0) == alternative_name)
334618334Speter	{
334718334Speter	  printf ("which_alternative == %s", XSTR (exp, 1));
334818334Speter	  break;
334918334Speter	}
335018334Speter
3351132718Skan      attr = find_attr (&XSTR (exp, 0), 0);
3352169689Skan      gcc_assert (attr);
335318334Speter
335418334Speter      /* Now is the time to expand the value of a constant attribute.  */
335518334Speter      if (attr->is_const)
335618334Speter	{
335718334Speter	  write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
335818334Speter					     -2, -2),
335950397Sobrien			   flags);
336018334Speter	}
336118334Speter      else
336218334Speter	{
336350397Sobrien	  if (flags & 2)
336450397Sobrien	    printf ("attr_%s", attr->name);
336550397Sobrien	  else
336650397Sobrien	    printf ("get_attr_%s (insn)", attr->name);
336750397Sobrien	  printf (" == ");
336850397Sobrien	  write_attr_valueq (attr, XSTR (exp, 1));
336918334Speter	}
337018334Speter      break;
337118334Speter
337218334Speter    /* Comparison test of flags for define_delays.  */
337318334Speter    case ATTR_FLAG:
337450397Sobrien      if (flags & 1)
337518334Speter	fatal ("ATTR_FLAG not valid inside comparison");
337618334Speter      printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
337718334Speter      break;
337818334Speter
337918334Speter    /* See if an operand matches a predicate.  */
338018334Speter    case MATCH_OPERAND:
338118334Speter      /* If only a mode is given, just ensure the mode matches the operand.
338218334Speter	 If neither a mode nor predicate is given, error.  */
338390075Sobrien      if (XSTR (exp, 1) == NULL || *XSTR (exp, 1) == '\0')
338418334Speter	{
338518334Speter	  if (GET_MODE (exp) == VOIDmode)
338690075Sobrien	    fatal ("null MATCH_OPERAND specified as test");
338718334Speter	  else
338818334Speter	    printf ("GET_MODE (operands[%d]) == %smode",
338918334Speter		    XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
339018334Speter	}
339118334Speter      else
339218334Speter	printf ("%s (operands[%d], %smode)",
339318334Speter		XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
339418334Speter      break;
339518334Speter
339650397Sobrien    /* Constant integer.  */
339718334Speter    case CONST_INT:
339850397Sobrien      printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
339918334Speter      break;
340018334Speter
340150397Sobrien    /* A random C expression.  */
340218334Speter    case SYMBOL_REF:
3403169689Skan      print_c_condition (XSTR (exp, 0));
340418334Speter      break;
340518334Speter
340618334Speter    /* The address of the branch target.  */
340718334Speter    case MATCH_DUP:
340890075Sobrien      printf ("INSN_ADDRESSES_SET_P () ? INSN_ADDRESSES (INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])) : 0",
340950397Sobrien	      XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
341018334Speter      break;
341118334Speter
341218334Speter    case PC:
341350397Sobrien      /* The address of the current insn.  We implement this actually as the
341450397Sobrien	 address of the current insn for backward branches, but the last
341550397Sobrien	 address of the next insn for forward branches, and both with
341650397Sobrien	 adjustments that account for the worst-case possible stretching of
341750397Sobrien	 intervening alignments between this insn and its destination.  */
341890075Sobrien      printf ("insn_current_reference_address (insn)");
341918334Speter      break;
342018334Speter
342150397Sobrien    case CONST_STRING:
342250397Sobrien      printf ("%s", XSTR (exp, 0));
342350397Sobrien      break;
342450397Sobrien
342550397Sobrien    case IF_THEN_ELSE:
342650397Sobrien      write_test_expr (XEXP (exp, 0), flags & 2);
342750397Sobrien      printf (" ? ");
342850397Sobrien      write_test_expr (XEXP (exp, 1), flags | 1);
342950397Sobrien      printf (" : ");
343050397Sobrien      write_test_expr (XEXP (exp, 2), flags | 1);
343150397Sobrien      break;
343250397Sobrien
343318334Speter    default:
343418334Speter      fatal ("bad RTX code `%s' in attribute calculation\n",
343518334Speter	     GET_RTX_NAME (code));
343618334Speter    }
343718334Speter
343818334Speter  printf (")");
343918334Speter}
3440132718Skan
344118334Speter/* Given an attribute value, return the maximum CONST_STRING argument
344252284Sobrien   encountered.  Set *UNKNOWNP and return INT_MAX if the value is unknown.  */
344318334Speter
344418334Speterstatic int
3445132718Skanmax_attr_value (rtx exp, int *unknownp)
344618334Speter{
344752284Sobrien  int current_max;
344852284Sobrien  int i, n;
344918334Speter
345052284Sobrien  switch (GET_CODE (exp))
345152284Sobrien    {
345252284Sobrien    case CONST_STRING:
345352284Sobrien      current_max = atoi (XSTR (exp, 0));
345452284Sobrien      break;
345518334Speter
345652284Sobrien    case COND:
345752284Sobrien      current_max = max_attr_value (XEXP (exp, 1), unknownp);
345818334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
345918334Speter	{
346052284Sobrien	  n = max_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
346118334Speter	  if (n > current_max)
346218334Speter	    current_max = n;
346318334Speter	}
346452284Sobrien      break;
346518334Speter
346652284Sobrien    case IF_THEN_ELSE:
346752284Sobrien      current_max = max_attr_value (XEXP (exp, 1), unknownp);
346852284Sobrien      n = max_attr_value (XEXP (exp, 2), unknownp);
346918334Speter      if (n > current_max)
347018334Speter	current_max = n;
347152284Sobrien      break;
347218334Speter
347352284Sobrien    default:
347452284Sobrien      *unknownp = 1;
347552284Sobrien      current_max = INT_MAX;
347652284Sobrien      break;
347718334Speter    }
347818334Speter
347918334Speter  return current_max;
348018334Speter}
348150397Sobrien
3482169689Skan/* Given an attribute value, return the minimum CONST_STRING argument
3483169689Skan   encountered.  Set *UNKNOWNP and return 0 if the value is unknown.  */
3484169689Skan
3485169689Skanstatic int
3486169689Skanmin_attr_value (rtx exp, int *unknownp)
3487169689Skan{
3488169689Skan  int current_min;
3489169689Skan  int i, n;
3490169689Skan
3491169689Skan  switch (GET_CODE (exp))
3492169689Skan    {
3493169689Skan    case CONST_STRING:
3494169689Skan      current_min = atoi (XSTR (exp, 0));
3495169689Skan      break;
3496169689Skan
3497169689Skan    case COND:
3498169689Skan      current_min = min_attr_value (XEXP (exp, 1), unknownp);
3499169689Skan      for (i = 0; i < XVECLEN (exp, 0); i += 2)
3500169689Skan	{
3501169689Skan	  n = min_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
3502169689Skan	  if (n < current_min)
3503169689Skan	    current_min = n;
3504169689Skan	}
3505169689Skan      break;
3506169689Skan
3507169689Skan    case IF_THEN_ELSE:
3508169689Skan      current_min = min_attr_value (XEXP (exp, 1), unknownp);
3509169689Skan      n = min_attr_value (XEXP (exp, 2), unknownp);
3510169689Skan      if (n < current_min)
3511169689Skan	current_min = n;
3512169689Skan      break;
3513169689Skan
3514169689Skan    default:
3515169689Skan      *unknownp = 1;
3516169689Skan      current_min = INT_MAX;
3517169689Skan      break;
3518169689Skan    }
3519169689Skan
3520169689Skan  return current_min;
3521169689Skan}
3522169689Skan
352350397Sobrien/* Given an attribute value, return the result of ORing together all
352452284Sobrien   CONST_STRING arguments encountered.  Set *UNKNOWNP and return -1
352552284Sobrien   if the numeric value is not known.  */
352650397Sobrien
352750397Sobrienstatic int
3528132718Skanor_attr_value (rtx exp, int *unknownp)
352950397Sobrien{
353052284Sobrien  int current_or;
353150397Sobrien  int i;
353250397Sobrien
353352284Sobrien  switch (GET_CODE (exp))
353452284Sobrien    {
353552284Sobrien    case CONST_STRING:
353652284Sobrien      current_or = atoi (XSTR (exp, 0));
353752284Sobrien      break;
353850397Sobrien
353952284Sobrien    case COND:
354052284Sobrien      current_or = or_attr_value (XEXP (exp, 1), unknownp);
354150397Sobrien      for (i = 0; i < XVECLEN (exp, 0); i += 2)
354252284Sobrien	current_or |= or_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
354352284Sobrien      break;
354450397Sobrien
354552284Sobrien    case IF_THEN_ELSE:
354652284Sobrien      current_or = or_attr_value (XEXP (exp, 1), unknownp);
354752284Sobrien      current_or |= or_attr_value (XEXP (exp, 2), unknownp);
354852284Sobrien      break;
354950397Sobrien
355052284Sobrien    default:
355152284Sobrien      *unknownp = 1;
355252284Sobrien      current_or = -1;
355352284Sobrien      break;
355450397Sobrien    }
355550397Sobrien
355650397Sobrien  return current_or;
355750397Sobrien}
3558132718Skan
355918334Speter/* Scan an attribute value, possibly a conditional, and record what actions
356018334Speter   will be required to do any conditional tests in it.
356118334Speter
356218334Speter   Specifically, set
356318334Speter	`must_extract'	  if we need to extract the insn operands
356418334Speter	`must_constrain'  if we must compute `which_alternative'
356518334Speter	`address_used'	  if an address expression was used
356618334Speter	`length_used'	  if an (eq_attr "length" ...) was used
356718334Speter */
356818334Speter
356918334Speterstatic void
3570132718Skanwalk_attr_value (rtx exp)
357118334Speter{
357290075Sobrien  int i, j;
357390075Sobrien  const char *fmt;
357418334Speter  RTX_CODE code;
357518334Speter
357618334Speter  if (exp == NULL)
357718334Speter    return;
357818334Speter
357918334Speter  code = GET_CODE (exp);
358018334Speter  switch (code)
358118334Speter    {
358218334Speter    case SYMBOL_REF:
3583117395Skan      if (! ATTR_IND_SIMPLIFIED_P (exp))
358418334Speter	/* Since this is an arbitrary expression, it can look at anything.
358518334Speter	   However, constant expressions do not depend on any particular
358618334Speter	   insn.  */
358718334Speter	must_extract = must_constrain = 1;
358818334Speter      return;
358918334Speter
359018334Speter    case MATCH_OPERAND:
359118334Speter      must_extract = 1;
359218334Speter      return;
359318334Speter
3594132718Skan    case EQ_ATTR_ALT:
3595132718Skan      must_extract = must_constrain = 1;
3596132718Skan      break;
3597132718Skan
359818334Speter    case EQ_ATTR:
359918334Speter      if (XSTR (exp, 0) == alternative_name)
360018334Speter	must_extract = must_constrain = 1;
3601132718Skan      else if (strcmp_check (XSTR (exp, 0), length_str) == 0)
360218334Speter	length_used = 1;
360318334Speter      return;
360418334Speter
360518334Speter    case MATCH_DUP:
360618334Speter      must_extract = 1;
360718334Speter      address_used = 1;
360818334Speter      return;
360918334Speter
361018334Speter    case PC:
361118334Speter      address_used = 1;
361218334Speter      return;
361318334Speter
361418334Speter    case ATTR_FLAG:
361518334Speter      return;
361650397Sobrien
361750397Sobrien    default:
361850397Sobrien      break;
361918334Speter    }
362018334Speter
362118334Speter  for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
362218334Speter    switch (*fmt++)
362318334Speter      {
362418334Speter      case 'e':
362518334Speter      case 'u':
362618334Speter	walk_attr_value (XEXP (exp, i));
362718334Speter	break;
362818334Speter
362918334Speter      case 'E':
363018334Speter	if (XVEC (exp, i) != NULL)
363118334Speter	  for (j = 0; j < XVECLEN (exp, i); j++)
363218334Speter	    walk_attr_value (XVECEXP (exp, i, j));
363318334Speter	break;
363418334Speter      }
363518334Speter}
3636132718Skan
363718334Speter/* Write out a function to obtain the attribute for a given INSN.  */
363818334Speter
363918334Speterstatic void
3640132718Skanwrite_attr_get (struct attr_desc *attr)
364118334Speter{
364218334Speter  struct attr_value *av, *common_av;
364318334Speter
364418334Speter  /* Find the most used attribute value.  Handle that as the `default' of the
364550397Sobrien     switch we will generate.  */
364618334Speter  common_av = find_most_used (attr);
364718334Speter
364818334Speter  /* Write out start of function, then all values with explicit `case' lines,
364918334Speter     then a `default', then the value with the most uses.  */
365018334Speter  if (!attr->is_numeric)
365118334Speter    printf ("enum attr_%s\n", attr->name);
365218334Speter  else
365318334Speter    printf ("int\n");
365418334Speter
365518334Speter  /* If the attribute name starts with a star, the remainder is the name of
365618334Speter     the subroutine to use, instead of `get_attr_...'.  */
365718334Speter  if (attr->name[0] == '*')
3658132718Skan    printf ("%s (rtx insn ATTRIBUTE_UNUSED)\n", &attr->name[1]);
365918334Speter  else if (attr->is_const == 0)
3660132718Skan    printf ("get_attr_%s (rtx insn ATTRIBUTE_UNUSED)\n", attr->name);
366118334Speter  else
366218334Speter    {
3663132718Skan      printf ("get_attr_%s (void)\n", attr->name);
366418334Speter      printf ("{\n");
366518334Speter
366618334Speter      for (av = attr->first_value; av; av = av->next)
3667169689Skan	if (av->num_insns == 1)
366818334Speter	  write_attr_set (attr, 2, av->value, "return", ";",
3669169689Skan			  true_rtx, av->first_insn->def->insn_code,
3670169689Skan			  av->first_insn->def->insn_index);
3671169689Skan	else if (av->num_insns != 0)
3672169689Skan	  write_attr_set (attr, 2, av->value, "return", ";",
3673169689Skan			  true_rtx, -2, 0);
367418334Speter
367518334Speter      printf ("}\n\n");
367618334Speter      return;
367718334Speter    }
367850397Sobrien
367918334Speter  printf ("{\n");
3680169689Skan  printf ("  switch (recog_memoized (insn))\n");
3681169689Skan  printf ("    {\n");
368218334Speter
3683169689Skan  for (av = attr->first_value; av; av = av->next)
3684169689Skan    if (av != common_av)
3685169689Skan      write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
368618334Speter
3687169689Skan  write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
3688169689Skan  printf ("    }\n}\n\n");
368918334Speter}
3690132718Skan
369118334Speter/* Given an AND tree of known true terms (because we are inside an `if' with
369218334Speter   that as the condition or are in an `else' clause) and an expression,
369318334Speter   replace any known true terms with TRUE.  Use `simplify_and_tree' to do
369418334Speter   the bulk of the work.  */
369518334Speter
369618334Speterstatic rtx
3697132718Skaneliminate_known_true (rtx known_true, rtx exp, int insn_code, int insn_index)
369818334Speter{
369918334Speter  rtx term;
370018334Speter
370118334Speter  known_true = SIMPLIFY_TEST_EXP (known_true, insn_code, insn_index);
370218334Speter
370318334Speter  if (GET_CODE (known_true) == AND)
370418334Speter    {
370518334Speter      exp = eliminate_known_true (XEXP (known_true, 0), exp,
370618334Speter				  insn_code, insn_index);
370718334Speter      exp = eliminate_known_true (XEXP (known_true, 1), exp,
370818334Speter				  insn_code, insn_index);
370918334Speter    }
371018334Speter  else
371118334Speter    {
371218334Speter      term = known_true;
371318334Speter      exp = simplify_and_tree (exp, &term, insn_code, insn_index);
371418334Speter    }
371518334Speter
371618334Speter  return exp;
371718334Speter}
3718132718Skan
371918334Speter/* Write out a series of tests and assignment statements to perform tests and
372018334Speter   sets of an attribute value.  We are passed an indentation amount and prefix
372118334Speter   and suffix strings to write around each attribute value (e.g., "return"
372218334Speter   and ";").  */
372318334Speter
372418334Speterstatic void
3725132718Skanwrite_attr_set (struct attr_desc *attr, int indent, rtx value,
3726132718Skan		const char *prefix, const char *suffix, rtx known_true,
3727132718Skan		int insn_code, int insn_index)
372818334Speter{
372952284Sobrien  if (GET_CODE (value) == COND)
373018334Speter    {
373118334Speter      /* Assume the default value will be the default of the COND unless we
373218334Speter	 find an always true expression.  */
373318334Speter      rtx default_val = XEXP (value, 1);
373418334Speter      rtx our_known_true = known_true;
373518334Speter      rtx newexp;
373618334Speter      int first_if = 1;
373718334Speter      int i;
373818334Speter
373918334Speter      for (i = 0; i < XVECLEN (value, 0); i += 2)
374018334Speter	{
374118334Speter	  rtx testexp;
374218334Speter	  rtx inner_true;
374318334Speter
374418334Speter	  testexp = eliminate_known_true (our_known_true,
374518334Speter					  XVECEXP (value, 0, i),
374618334Speter					  insn_code, insn_index);
374718334Speter	  newexp = attr_rtx (NOT, testexp);
374890075Sobrien	  newexp = insert_right_side (AND, our_known_true, newexp,
374990075Sobrien				      insn_code, insn_index);
375018334Speter
375118334Speter	  /* If the test expression is always true or if the next `known_true'
375218334Speter	     expression is always false, this is the last case, so break
375318334Speter	     out and let this value be the `else' case.  */
375418334Speter	  if (testexp == true_rtx || newexp == false_rtx)
375518334Speter	    {
375618334Speter	      default_val = XVECEXP (value, 0, i + 1);
375718334Speter	      break;
375818334Speter	    }
375918334Speter
376018334Speter	  /* Compute the expression to pass to our recursive call as being
376118334Speter	     known true.  */
376218334Speter	  inner_true = insert_right_side (AND, our_known_true,
376318334Speter					  testexp, insn_code, insn_index);
376418334Speter
376518334Speter	  /* If this is always false, skip it.  */
376618334Speter	  if (inner_true == false_rtx)
376718334Speter	    continue;
376818334Speter
376918334Speter	  write_indent (indent);
377018334Speter	  printf ("%sif ", first_if ? "" : "else ");
377118334Speter	  first_if = 0;
377218334Speter	  write_test_expr (testexp, 0);
377318334Speter	  printf ("\n");
377418334Speter	  write_indent (indent + 2);
377518334Speter	  printf ("{\n");
377618334Speter
377790075Sobrien	  write_attr_set (attr, indent + 4,
377818334Speter			  XVECEXP (value, 0, i + 1), prefix, suffix,
377918334Speter			  inner_true, insn_code, insn_index);
378018334Speter	  write_indent (indent + 2);
378118334Speter	  printf ("}\n");
378218334Speter	  our_known_true = newexp;
378318334Speter	}
378418334Speter
378518334Speter      if (! first_if)
378618334Speter	{
378718334Speter	  write_indent (indent);
378818334Speter	  printf ("else\n");
378918334Speter	  write_indent (indent + 2);
379018334Speter	  printf ("{\n");
379118334Speter	}
379218334Speter
379318334Speter      write_attr_set (attr, first_if ? indent : indent + 4, default_val,
379418334Speter		      prefix, suffix, our_known_true, insn_code, insn_index);
379518334Speter
379618334Speter      if (! first_if)
379718334Speter	{
379818334Speter	  write_indent (indent + 2);
379918334Speter	  printf ("}\n");
380018334Speter	}
380118334Speter    }
380218334Speter  else
380352284Sobrien    {
380452284Sobrien      write_indent (indent);
380552284Sobrien      printf ("%s ", prefix);
380652284Sobrien      write_attr_value (attr, value);
380752284Sobrien      printf ("%s\n", suffix);
380852284Sobrien    }
380918334Speter}
3810132718Skan
3811169689Skan/* Write a series of case statements for every instruction in list IE.
3812169689Skan   INDENT is the amount of indentation to write before each case.  */
3813169689Skan
3814169689Skanstatic void
3815169689Skanwrite_insn_cases (struct insn_ent *ie, int indent)
3816169689Skan{
3817169689Skan  for (; ie != 0; ie = ie->next)
3818169689Skan    if (ie->def->insn_code != -1)
3819169689Skan      {
3820169689Skan	write_indent (indent);
3821169689Skan	if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE)
3822169689Skan	  printf ("case %d:  /* define_peephole, line %d */\n",
3823169689Skan		  ie->def->insn_code, ie->def->lineno);
3824169689Skan	else
3825169689Skan	  printf ("case %d:  /* %s */\n",
3826169689Skan		  ie->def->insn_code, XSTR (ie->def->def, 0));
3827169689Skan      }
3828169689Skan}
3829169689Skan
383018334Speter/* Write out the computation for one attribute value.  */
383118334Speter
383218334Speterstatic void
3833132718Skanwrite_attr_case (struct attr_desc *attr, struct attr_value *av,
3834132718Skan		 int write_case_lines, const char *prefix, const char *suffix,
3835132718Skan		 int indent, rtx known_true)
383618334Speter{
383718334Speter  if (av->num_insns == 0)
383818334Speter    return;
383918334Speter
384018334Speter  if (av->has_asm_insn)
384118334Speter    {
384218334Speter      write_indent (indent);
384318334Speter      printf ("case -1:\n");
384418334Speter      write_indent (indent + 2);
384518334Speter      printf ("if (GET_CODE (PATTERN (insn)) != ASM_INPUT\n");
384618334Speter      write_indent (indent + 2);
384718334Speter      printf ("    && asm_noperands (PATTERN (insn)) < 0)\n");
384818334Speter      write_indent (indent + 2);
384918334Speter      printf ("  fatal_insn_not_found (insn);\n");
385018334Speter    }
385118334Speter
385218334Speter  if (write_case_lines)
3853169689Skan    write_insn_cases (av->first_insn, indent);
385418334Speter  else
385518334Speter    {
385618334Speter      write_indent (indent);
385718334Speter      printf ("default:\n");
385818334Speter    }
385918334Speter
386018334Speter  /* See what we have to do to output this value.  */
386118334Speter  must_extract = must_constrain = address_used = 0;
386218334Speter  walk_attr_value (av->value);
386318334Speter
386490075Sobrien  if (must_constrain)
386518334Speter    {
386618334Speter      write_indent (indent + 2);
386790075Sobrien      printf ("extract_constrain_insn_cached (insn);\n");
386818334Speter    }
386990075Sobrien  else if (must_extract)
387018334Speter    {
387118334Speter      write_indent (indent + 2);
387290075Sobrien      printf ("extract_insn_cached (insn);\n");
387318334Speter    }
387418334Speter
3875169689Skan  if (av->num_insns == 1)
3876169689Skan    write_attr_set (attr, indent + 2, av->value, prefix, suffix,
3877169689Skan		    known_true, av->first_insn->def->insn_code,
3878169689Skan		    av->first_insn->def->insn_index);
3879169689Skan  else
3880169689Skan    write_attr_set (attr, indent + 2, av->value, prefix, suffix,
3881169689Skan		    known_true, -2, 0);
388218334Speter
388318334Speter  if (strncmp (prefix, "return", 6))
388418334Speter    {
388518334Speter      write_indent (indent + 2);
388618334Speter      printf ("break;\n");
388718334Speter    }
388818334Speter  printf ("\n");
388918334Speter}
3890132718Skan
389150397Sobrien/* Search for uses of non-const attributes and write code to cache them.  */
389250397Sobrien
389350397Sobrienstatic int
3894132718Skanwrite_expr_attr_cache (rtx p, struct attr_desc *attr)
389550397Sobrien{
389690075Sobrien  const char *fmt;
389750397Sobrien  int i, ie, j, je;
389850397Sobrien
389950397Sobrien  if (GET_CODE (p) == EQ_ATTR)
390050397Sobrien    {
390150397Sobrien      if (XSTR (p, 0) != attr->name)
390250397Sobrien	return 0;
390350397Sobrien
390450397Sobrien      if (!attr->is_numeric)
390590075Sobrien	printf ("  enum attr_%s ", attr->name);
390650397Sobrien      else
390790075Sobrien	printf ("  int ");
390850397Sobrien
390950397Sobrien      printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
391050397Sobrien      return 1;
391150397Sobrien    }
391250397Sobrien
391350397Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (p));
391450397Sobrien  ie = GET_RTX_LENGTH (GET_CODE (p));
391550397Sobrien  for (i = 0; i < ie; i++)
391650397Sobrien    {
391750397Sobrien      switch (*fmt++)
391850397Sobrien	{
391950397Sobrien	case 'e':
392050397Sobrien	  if (write_expr_attr_cache (XEXP (p, i), attr))
392150397Sobrien	    return 1;
392250397Sobrien	  break;
392350397Sobrien
392450397Sobrien	case 'E':
392550397Sobrien	  je = XVECLEN (p, i);
392650397Sobrien	  for (j = 0; j < je; ++j)
392750397Sobrien	    if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
392850397Sobrien	      return 1;
392950397Sobrien	  break;
393050397Sobrien	}
393150397Sobrien    }
393250397Sobrien
393350397Sobrien  return 0;
393450397Sobrien}
393550397Sobrien
3936169689Skan/* Utilities to write in various forms.  */
393750397Sobrien
393850397Sobrienstatic void
3939132718Skanwrite_attr_valueq (struct attr_desc *attr, const char *s)
394018334Speter{
394118334Speter  if (attr->is_numeric)
394218334Speter    {
394350397Sobrien      int num = atoi (s);
394450397Sobrien
394550397Sobrien      printf ("%d", num);
394650397Sobrien
3947169689Skan      if (num > 9 || num < 0)
394850397Sobrien	printf (" /* 0x%x */", num);
394918334Speter    }
395018334Speter  else
395118334Speter    {
395218334Speter      write_upcase (attr->name);
395318334Speter      printf ("_");
395418334Speter      write_upcase (s);
395518334Speter    }
395618334Speter}
395718334Speter
395818334Speterstatic void
3959132718Skanwrite_attr_value (struct attr_desc *attr, rtx value)
396018334Speter{
396152284Sobrien  int op;
396218334Speter
396352284Sobrien  switch (GET_CODE (value))
396452284Sobrien    {
396552284Sobrien    case CONST_STRING:
396652284Sobrien      write_attr_valueq (attr, XSTR (value, 0));
396752284Sobrien      break;
396852284Sobrien
396990075Sobrien    case CONST_INT:
397090075Sobrien      printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (value));
397190075Sobrien      break;
397290075Sobrien
397352284Sobrien    case SYMBOL_REF:
3974169689Skan      print_c_condition (XSTR (value, 0));
397552284Sobrien      break;
397652284Sobrien
397752284Sobrien    case ATTR:
397852284Sobrien      {
3979132718Skan	struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0);
398090075Sobrien	printf ("get_attr_%s (%s)", attr2->name,
398152284Sobrien		(attr2->is_const ? "" : "insn"));
398252284Sobrien      }
398352284Sobrien      break;
398452284Sobrien
398552284Sobrien    case PLUS:
398652284Sobrien      op = '+';
398752284Sobrien      goto do_operator;
398852284Sobrien    case MINUS:
398952284Sobrien      op = '-';
399052284Sobrien      goto do_operator;
399152284Sobrien    case MULT:
399252284Sobrien      op = '*';
399352284Sobrien      goto do_operator;
399452284Sobrien    case DIV:
399552284Sobrien      op = '/';
399652284Sobrien      goto do_operator;
399752284Sobrien    case MOD:
399852284Sobrien      op = '%';
399952284Sobrien      goto do_operator;
400052284Sobrien
400152284Sobrien    do_operator:
400252284Sobrien      write_attr_value (attr, XEXP (value, 0));
400352284Sobrien      putchar (' ');
400452284Sobrien      putchar (op);
400552284Sobrien      putchar (' ');
400652284Sobrien      write_attr_value (attr, XEXP (value, 1));
400752284Sobrien      break;
400852284Sobrien
400952284Sobrien    default:
4010169689Skan      gcc_unreachable ();
401152284Sobrien    }
401218334Speter}
401318334Speter
401418334Speterstatic void
4015132718Skanwrite_upcase (const char *str)
401618334Speter{
401718334Speter  while (*str)
401890075Sobrien    {
401990075Sobrien      /* The argument of TOUPPER should not have side effects.  */
402090075Sobrien      putchar (TOUPPER(*str));
402190075Sobrien      str++;
402290075Sobrien    }
402318334Speter}
402418334Speter
402518334Speterstatic void
4026132718Skanwrite_indent (int indent)
402718334Speter{
402818334Speter  for (; indent > 8; indent -= 8)
402918334Speter    printf ("\t");
403018334Speter
403118334Speter  for (; indent; indent--)
403218334Speter    printf (" ");
403318334Speter}
4034132718Skan
403518334Speter/* Write a subroutine that is given an insn that requires a delay slot, a
4036117395Skan   delay slot ordinal, and a candidate insn.  It returns nonzero if the
403718334Speter   candidate can be placed in the specified delay slot of the insn.
403818334Speter
403918334Speter   We can write as many as three subroutines.  `eligible_for_delay'
404018334Speter   handles normal delay slots, `eligible_for_annul_true' indicates that
404118334Speter   the specified insn can be annulled if the branch is true, and likewise
404218334Speter   for `eligible_for_annul_false'.
404318334Speter
404418334Speter   KIND is a string distinguishing these three cases ("delay", "annul_true",
404518334Speter   or "annul_false").  */
404618334Speter
404718334Speterstatic void
4048132718Skanwrite_eligible_delay (const char *kind)
404918334Speter{
405018334Speter  struct delay_desc *delay;
405118334Speter  int max_slots;
405218334Speter  char str[50];
4053132718Skan  const char *pstr;
405418334Speter  struct attr_desc *attr;
405518334Speter  struct attr_value *av, *common_av;
405618334Speter  int i;
405718334Speter
405818334Speter  /* Compute the maximum number of delay slots required.  We use the delay
405918334Speter     ordinal times this number plus one, plus the slot number as an index into
406018334Speter     the appropriate predicate to test.  */
406118334Speter
406218334Speter  for (delay = delays, max_slots = 0; delay; delay = delay->next)
406318334Speter    if (XVECLEN (delay->def, 1) / 3 > max_slots)
406418334Speter      max_slots = XVECLEN (delay->def, 1) / 3;
406518334Speter
406618334Speter  /* Write function prelude.  */
406718334Speter
406818334Speter  printf ("int\n");
4069132718Skan  printf ("eligible_for_%s (rtx delay_insn ATTRIBUTE_UNUSED, int slot, rtx candidate_insn, int flags ATTRIBUTE_UNUSED)\n",
407090075Sobrien	  kind);
407118334Speter  printf ("{\n");
407218334Speter  printf ("  rtx insn;\n");
407318334Speter  printf ("\n");
4074169689Skan  printf ("  gcc_assert (slot < %d);\n", max_slots);
407518334Speter  printf ("\n");
4076169689Skan  /* Allow dbr_schedule to pass labels, etc.  This can happen if try_split
4077169689Skan     converts a compound instruction into a loop.  */
4078169689Skan  printf ("  if (!INSN_P (candidate_insn))\n");
4079169689Skan  printf ("    return 0;\n");
4080169689Skan  printf ("\n");
408118334Speter
408218334Speter  /* If more than one delay type, find out which type the delay insn is.  */
408318334Speter
408418334Speter  if (num_delays > 1)
408518334Speter    {
4086132718Skan      attr = find_attr (&delay_type_str, 0);
4087169689Skan      gcc_assert (attr);
408818334Speter      common_av = find_most_used (attr);
408918334Speter
409018334Speter      printf ("  insn = delay_insn;\n");
409118334Speter      printf ("  switch (recog_memoized (insn))\n");
409218334Speter      printf ("    {\n");
409318334Speter
409418334Speter      sprintf (str, " * %d;\n      break;", max_slots);
409518334Speter      for (av = attr->first_value; av; av = av->next)
409618334Speter	if (av != common_av)
409718334Speter	  write_attr_case (attr, av, 1, "slot +=", str, 4, true_rtx);
409818334Speter
409918334Speter      write_attr_case (attr, common_av, 0, "slot +=", str, 4, true_rtx);
410018334Speter      printf ("    }\n\n");
410118334Speter
410218334Speter      /* Ensure matched.  Otherwise, shouldn't have been called.  */
4103169689Skan      printf ("  gcc_assert (slot >= %d);\n\n", max_slots);
410418334Speter    }
410518334Speter
410618334Speter  /* If just one type of delay slot, write simple switch.  */
410718334Speter  if (num_delays == 1 && max_slots == 1)
410818334Speter    {
410918334Speter      printf ("  insn = candidate_insn;\n");
411018334Speter      printf ("  switch (recog_memoized (insn))\n");
411118334Speter      printf ("    {\n");
411218334Speter
4113132718Skan      attr = find_attr (&delay_1_0_str, 0);
4114169689Skan      gcc_assert (attr);
411518334Speter      common_av = find_most_used (attr);
411618334Speter
411718334Speter      for (av = attr->first_value; av; av = av->next)
411818334Speter	if (av != common_av)
411918334Speter	  write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
412018334Speter
412118334Speter      write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
412218334Speter      printf ("    }\n");
412318334Speter    }
412418334Speter
412518334Speter  else
412618334Speter    {
412718334Speter      /* Write a nested CASE.  The first indicates which condition we need to
412818334Speter	 test, and the inner CASE tests the condition.  */
412918334Speter      printf ("  insn = candidate_insn;\n");
413018334Speter      printf ("  switch (slot)\n");
413118334Speter      printf ("    {\n");
413218334Speter
413318334Speter      for (delay = delays; delay; delay = delay->next)
413418334Speter	for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
413518334Speter	  {
413618334Speter	    printf ("    case %d:\n",
413718334Speter		    (i / 3) + (num_delays == 1 ? 0 : delay->num * max_slots));
413818334Speter	    printf ("      switch (recog_memoized (insn))\n");
413918334Speter	    printf ("\t{\n");
414018334Speter
414118334Speter	    sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3);
4142132718Skan	    pstr = str;
4143132718Skan	    attr = find_attr (&pstr, 0);
4144169689Skan	    gcc_assert (attr);
414518334Speter	    common_av = find_most_used (attr);
414618334Speter
414718334Speter	    for (av = attr->first_value; av; av = av->next)
414818334Speter	      if (av != common_av)
414918334Speter		write_attr_case (attr, av, 1, "return", ";", 8, true_rtx);
415018334Speter
415118334Speter	    write_attr_case (attr, common_av, 0, "return", ";", 8, true_rtx);
415218334Speter	    printf ("      }\n");
415318334Speter	  }
415418334Speter
415518334Speter      printf ("    default:\n");
4156169689Skan      printf ("      gcc_unreachable ();\n");
415718334Speter      printf ("    }\n");
415818334Speter    }
415918334Speter
416018334Speter  printf ("}\n\n");
416118334Speter}
4162132718Skan
416318334Speter/* This page contains miscellaneous utility routines.  */
416418334Speter
416518334Speter/* Given a pointer to a (char *), return a malloc'ed string containing the
416618334Speter   next comma-separated element.  Advance the pointer to after the string
416718334Speter   scanned, or the end-of-string.  Return NULL if at end of string.  */
416818334Speter
416918334Speterstatic char *
4170132718Skannext_comma_elt (const char **pstr)
417118334Speter{
4172117395Skan  const char *start;
417318334Speter
4174117395Skan  start = scan_comma_elt (pstr);
4175117395Skan
4176117395Skan  if (start == NULL)
417718334Speter    return NULL;
417818334Speter
4179117395Skan  return attr_string (start, *pstr - start);
418018334Speter}
418118334Speter
418218334Speter/* Return a `struct attr_desc' pointer for a given named attribute.  If CREATE
4183132718Skan   is nonzero, build a new attribute, if one does not exist.  *NAME_P is
4184132718Skan   replaced by a pointer to a canonical copy of the string.  */
418518334Speter
418618334Speterstatic struct attr_desc *
4187132718Skanfind_attr (const char **name_p, int create)
418818334Speter{
418918334Speter  struct attr_desc *attr;
419018334Speter  int index;
4191132718Skan  const char *name = *name_p;
419218334Speter
419318334Speter  /* Before we resort to using `strcmp', see if the string address matches
419418334Speter     anywhere.  In most cases, it should have been canonicalized to do so.  */
419518334Speter  if (name == alternative_name)
419618334Speter    return NULL;
419718334Speter
419818334Speter  index = name[0] & (MAX_ATTRS_INDEX - 1);
419918334Speter  for (attr = attrs[index]; attr; attr = attr->next)
420018334Speter    if (name == attr->name)
420118334Speter      return attr;
420218334Speter
420318334Speter  /* Otherwise, do it the slow way.  */
420418334Speter  for (attr = attrs[index]; attr; attr = attr->next)
420518334Speter    if (name[0] == attr->name[0] && ! strcmp (name, attr->name))
4206132718Skan      {
4207132718Skan	*name_p = attr->name;
4208132718Skan	return attr;
4209132718Skan      }
421018334Speter
421118334Speter  if (! create)
421218334Speter    return NULL;
421318334Speter
4214132718Skan  attr = oballoc (sizeof (struct attr_desc));
4215132718Skan  attr->name = DEF_ATTR_STRING (name);
421618334Speter  attr->first_value = attr->default_val = NULL;
4217169689Skan  attr->is_numeric = attr->is_const = attr->is_special = 0;
421818334Speter  attr->next = attrs[index];
421918334Speter  attrs[index] = attr;
422018334Speter
4221132718Skan  *name_p = attr->name;
4222132718Skan
422318334Speter  return attr;
422418334Speter}
422518334Speter
422618334Speter/* Create internal attribute with the given default value.  */
422718334Speter
4228169689Skanstatic void
4229132718Skanmake_internal_attr (const char *name, rtx value, int special)
423018334Speter{
423118334Speter  struct attr_desc *attr;
423218334Speter
4233132718Skan  attr = find_attr (&name, 1);
4234169689Skan  gcc_assert (!attr->default_val);
423518334Speter
423618334Speter  attr->is_numeric = 1;
423718334Speter  attr->is_const = 0;
4238132718Skan  attr->is_special = (special & ATTR_SPECIAL) != 0;
423918334Speter  attr->default_val = get_attr_value (value, attr, -2);
424018334Speter}
424118334Speter
424218334Speter/* Find the most used value of an attribute.  */
424318334Speter
424418334Speterstatic struct attr_value *
4245132718Skanfind_most_used (struct attr_desc *attr)
424618334Speter{
424718334Speter  struct attr_value *av;
424818334Speter  struct attr_value *most_used;
424918334Speter  int nuses;
425018334Speter
425118334Speter  most_used = NULL;
425218334Speter  nuses = -1;
425318334Speter
425418334Speter  for (av = attr->first_value; av; av = av->next)
425518334Speter    if (av->num_insns > nuses)
425618334Speter      nuses = av->num_insns, most_used = av;
425718334Speter
425818334Speter  return most_used;
425918334Speter}
426018334Speter
4261169689Skan/* Return (attr_value "n") */
426218334Speter
426318334Speterstatic rtx
4264132718Skanmake_numeric_value (int n)
426518334Speter{
426618334Speter  static rtx int_values[20];
426718334Speter  rtx exp;
426818334Speter  char *p;
426918334Speter
4270169689Skan  gcc_assert (n >= 0);
427118334Speter
427218334Speter  if (n < 20 && int_values[n])
427318334Speter    return int_values[n];
427418334Speter
427518334Speter  p = attr_printf (MAX_DIGITS, "%d", n);
427618334Speter  exp = attr_rtx (CONST_STRING, p);
427718334Speter
427818334Speter  if (n < 20)
427918334Speter    int_values[n] = exp;
428018334Speter
428118334Speter  return exp;
428218334Speter}
4283132718Skan
428418334Speterstatic rtx
4285132718Skancopy_rtx_unchanging (rtx orig)
428618334Speter{
4287117395Skan  if (ATTR_IND_SIMPLIFIED_P (orig) || ATTR_CURR_SIMPLIFIED_P (orig))
428818334Speter    return orig;
428918334Speter
4290117395Skan  ATTR_CURR_SIMPLIFIED_P (orig) = 1;
429118334Speter  return orig;
429218334Speter}
429318334Speter
429418334Speter/* Determine if an insn has a constant number of delay slots, i.e., the
429518334Speter   number of delay slots is not a function of the length of the insn.  */
429618334Speter
429790075Sobrienstatic void
4298132718Skanwrite_const_num_delay_slots (void)
429918334Speter{
4300132718Skan  struct attr_desc *attr = find_attr (&num_delay_slots_str, 0);
430118334Speter  struct attr_value *av;
430218334Speter
430318334Speter  if (attr)
430418334Speter    {
4305132718Skan      printf ("int\nconst_num_delay_slots (rtx insn)\n");
430618334Speter      printf ("{\n");
430718334Speter      printf ("  switch (recog_memoized (insn))\n");
430818334Speter      printf ("    {\n");
430918334Speter
431018334Speter      for (av = attr->first_value; av; av = av->next)
431118334Speter	{
431218334Speter	  length_used = 0;
431318334Speter	  walk_attr_value (av->value);
431418334Speter	  if (length_used)
4315169689Skan	    write_insn_cases (av->first_insn, 4);
431618334Speter	}
431718334Speter
431818334Speter      printf ("    default:\n");
431918334Speter      printf ("      return 1;\n");
432050397Sobrien      printf ("    }\n}\n\n");
432118334Speter    }
432218334Speter}
4323169689Skan
4324169689Skan/* Synthetic attributes used by insn-automata.c and the scheduler.
4325169689Skan   These are primarily concerned with (define_insn_reservation)
4326169689Skan   patterns.  */
432718334Speter
4328169689Skanstruct insn_reserv
4329169689Skan{
4330169689Skan  struct insn_reserv *next;
4331169689Skan
4332169689Skan  const char *name;
4333169689Skan  int default_latency;
4334169689Skan  rtx condexp;
4335169689Skan
4336169689Skan  /* Sequence number of this insn.  */
4337169689Skan  int insn_num;
4338169689Skan
4339169689Skan  /* Whether a (define_bypass) construct names this insn in its
4340169689Skan     output list.  */
4341169689Skan  bool bypassed;
4342169689Skan};
4343169689Skan
4344169689Skanstatic struct insn_reserv *all_insn_reservs = 0;
4345169689Skanstatic struct insn_reserv **last_insn_reserv_p = &all_insn_reservs;
4346169689Skanstatic size_t n_insn_reservs;
4347169689Skan
4348169689Skan/* Store information from a DEFINE_INSN_RESERVATION for future
4349169689Skan   attribute generation.  */
4350169689Skanstatic void
4351169689Skangen_insn_reserv (rtx def)
4352169689Skan{
4353169689Skan  struct insn_reserv *decl = oballoc (sizeof (struct insn_reserv));
4354169689Skan
4355169689Skan  decl->name            = DEF_ATTR_STRING (XSTR (def, 0));
4356169689Skan  decl->default_latency = XINT (def, 1);
4357169689Skan  decl->condexp         = check_attr_test (XEXP (def, 2), 0, 0);
4358169689Skan  decl->insn_num        = n_insn_reservs;
4359169689Skan  decl->bypassed	= false;
4360169689Skan  decl->next            = 0;
4361169689Skan
4362169689Skan  *last_insn_reserv_p = decl;
4363169689Skan  last_insn_reserv_p  = &decl->next;
4364169689Skan  n_insn_reservs++;
4365169689Skan}
4366169689Skan
4367169689Skan/* Store information from a DEFINE_BYPASS for future attribute
4368169689Skan   generation.  The only thing we care about is the list of output
4369169689Skan   insns, which will later be used to tag reservation structures with
4370169689Skan   a 'bypassed' bit.  */
4371169689Skan
4372169689Skanstruct bypass_list
4373169689Skan{
4374169689Skan  struct bypass_list *next;
4375169689Skan  const char *insn;
4376169689Skan};
4377169689Skan
4378169689Skanstatic struct bypass_list *all_bypasses;
4379169689Skanstatic size_t n_bypasses;
4380169689Skan
4381169689Skanstatic void
4382169689Skangen_bypass_1 (const char *s, size_t len)
4383169689Skan{
4384169689Skan  struct bypass_list *b;
4385169689Skan
4386169689Skan  if (len == 0)
4387169689Skan    return;
4388169689Skan
4389169689Skan  s = attr_string (s, len);
4390169689Skan  for (b = all_bypasses; b; b = b->next)
4391169689Skan    if (s == b->insn)
4392169689Skan      return;  /* already got that one */
4393169689Skan
4394169689Skan  b = oballoc (sizeof (struct bypass_list));
4395169689Skan  b->insn = s;
4396169689Skan  b->next = all_bypasses;
4397169689Skan  all_bypasses = b;
4398169689Skan  n_bypasses++;
4399169689Skan}
4400169689Skan
4401169689Skanstatic void
4402169689Skangen_bypass (rtx def)
4403169689Skan{
4404169689Skan  const char *p, *base;
4405169689Skan
4406169689Skan  for (p = base = XSTR (def, 1); *p; p++)
4407169689Skan    if (*p == ',')
4408169689Skan      {
4409169689Skan	gen_bypass_1 (base, p - base);
4410169689Skan	do
4411169689Skan	  p++;
4412169689Skan	while (ISSPACE (*p));
4413169689Skan	base = p;
4414169689Skan      }
4415169689Skan  gen_bypass_1 (base, p - base);
4416169689Skan}
4417169689Skan
4418169689Skan/* Find and mark all of the bypassed insns.  */
4419169689Skanstatic void
4420169689Skanprocess_bypasses (void)
4421169689Skan{
4422169689Skan  struct bypass_list *b;
4423169689Skan  struct insn_reserv *r;
4424169689Skan
4425169689Skan  /* The reservation list is likely to be much longer than the bypass
4426169689Skan     list.  */
4427169689Skan  for (r = all_insn_reservs; r; r = r->next)
4428169689Skan    for (b = all_bypasses; b; b = b->next)
4429169689Skan      if (r->name == b->insn)
4430169689Skan	r->bypassed = true;
4431169689Skan}
4432169689Skan
4433169689Skan/* Create all of the attributes that describe automaton properties.  */
4434169689Skanstatic void
4435169689Skanmake_automaton_attrs (void)
4436169689Skan{
4437169689Skan  int i;
4438169689Skan  struct insn_reserv *decl;
4439169689Skan  rtx code_exp, lats_exp, byps_exp;
4440169689Skan
4441169689Skan  if (n_insn_reservs == 0)
4442169689Skan    return;
4443169689Skan
4444169689Skan  code_exp = rtx_alloc (COND);
4445169689Skan  lats_exp = rtx_alloc (COND);
4446169689Skan
4447169689Skan  XVEC (code_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
4448169689Skan  XVEC (lats_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
4449169689Skan
4450169689Skan  XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
4451169689Skan  XEXP (lats_exp, 1) = make_numeric_value (0);
4452169689Skan
4453169689Skan  for (decl = all_insn_reservs, i = 0;
4454169689Skan       decl;
4455169689Skan       decl = decl->next, i += 2)
4456169689Skan    {
4457169689Skan      XVECEXP (code_exp, 0, i)   = decl->condexp;
4458169689Skan      XVECEXP (lats_exp, 0, i)   = decl->condexp;
4459169689Skan
4460169689Skan      XVECEXP (code_exp, 0, i+1) = make_numeric_value (decl->insn_num);
4461169689Skan      XVECEXP (lats_exp, 0, i+1) = make_numeric_value (decl->default_latency);
4462169689Skan    }
4463169689Skan
4464169689Skan  if (n_bypasses == 0)
4465169689Skan    byps_exp = make_numeric_value (0);
4466169689Skan  else
4467169689Skan    {
4468169689Skan      process_bypasses ();
4469169689Skan
4470169689Skan      byps_exp = rtx_alloc (COND);
4471169689Skan      XVEC (byps_exp, 0) = rtvec_alloc (n_bypasses * 2);
4472169689Skan      XEXP (byps_exp, 1) = make_numeric_value (0);
4473169689Skan      for (decl = all_insn_reservs, i = 0;
4474169689Skan	   decl;
4475169689Skan	   decl = decl->next)
4476169689Skan	if (decl->bypassed)
4477169689Skan	  {
4478169689Skan	    XVECEXP (byps_exp, 0, i)   = decl->condexp;
4479169689Skan	    XVECEXP (byps_exp, 0, i+1) = make_numeric_value (1);
4480169689Skan	    i += 2;
4481169689Skan	  }
4482169689Skan    }
4483169689Skan
4484169689Skan  make_internal_attr ("*internal_dfa_insn_code", code_exp, ATTR_NONE);
4485169689Skan  make_internal_attr ("*insn_default_latency",   lats_exp, ATTR_NONE);
4486169689Skan  make_internal_attr ("*bypass_p",               byps_exp, ATTR_NONE);
4487169689Skan}
4488169689Skan
448918334Speterint
4490132718Skanmain (int argc, char **argv)
449118334Speter{
449218334Speter  rtx desc;
449318334Speter  struct attr_desc *attr;
449418334Speter  struct insn_def *id;
449518334Speter  rtx tem;
449618334Speter  int i;
449718334Speter
449890075Sobrien  progname = "genattrtab";
449918334Speter
450090075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
450190075Sobrien    return (FATAL_EXIT_CODE);
450290075Sobrien
450318334Speter  obstack_init (hash_obstack);
450418334Speter  obstack_init (temp_obstack);
450518334Speter
450618334Speter  /* Set up true and false rtx's */
450718334Speter  true_rtx = rtx_alloc (CONST_INT);
450818334Speter  XWINT (true_rtx, 0) = 1;
450918334Speter  false_rtx = rtx_alloc (CONST_INT);
451018334Speter  XWINT (false_rtx, 0) = 0;
4511117395Skan  ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1;
4512117395Skan  ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1;
451318334Speter
4514132718Skan  alternative_name = DEF_ATTR_STRING ("alternative");
4515132718Skan  length_str = DEF_ATTR_STRING ("length");
4516132718Skan  delay_type_str = DEF_ATTR_STRING ("*delay_type");
4517132718Skan  delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0");
4518132718Skan  num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots");
451918334Speter
452018334Speter  printf ("/* Generated automatically by the program `genattrtab'\n\
452118334Speterfrom the machine description file `md'.  */\n\n");
452218334Speter
452318334Speter  /* Read the machine description.  */
452418334Speter
452518334Speter  while (1)
452618334Speter    {
452790075Sobrien      int lineno;
452890075Sobrien
452990075Sobrien      desc = read_md_rtx (&lineno, &insn_code_number);
453090075Sobrien      if (desc == NULL)
453118334Speter	break;
453218334Speter
453390075Sobrien      switch (GET_CODE (desc))
453490075Sobrien	{
453590075Sobrien	case DEFINE_INSN:
453690075Sobrien	case DEFINE_PEEPHOLE:
453790075Sobrien	case DEFINE_ASM_ATTRIBUTES:
453890075Sobrien	  gen_insn (desc, lineno);
453990075Sobrien	  break;
454018334Speter
454190075Sobrien	case DEFINE_ATTR:
454290075Sobrien	  gen_attr (desc, lineno);
454390075Sobrien	  break;
454418334Speter
454590075Sobrien	case DEFINE_DELAY:
454690075Sobrien	  gen_delay (desc, lineno);
454790075Sobrien	  break;
454818334Speter
4549169689Skan	case DEFINE_INSN_RESERVATION:
4550169689Skan	  gen_insn_reserv (desc);
455190075Sobrien	  break;
455218334Speter
4553117395Skan	case DEFINE_BYPASS:
4554117395Skan	  gen_bypass (desc);
4555117395Skan	  break;
4556132718Skan
455790075Sobrien	default:
455890075Sobrien	  break;
455918334Speter	}
456090075Sobrien      if (GET_CODE (desc) != DEFINE_ASM_ATTRIBUTES)
456190075Sobrien	insn_index_number++;
456218334Speter    }
456318334Speter
456490075Sobrien  if (have_error)
456590075Sobrien    return FATAL_EXIT_CODE;
456690075Sobrien
456790075Sobrien  insn_code_number++;
456890075Sobrien
456918334Speter  /* If we didn't have a DEFINE_ASM_ATTRIBUTES, make a null one.  */
457018334Speter  if (! got_define_asm_attributes)
457118334Speter    {
457218334Speter      tem = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
457318334Speter      XVEC (tem, 0) = rtvec_alloc (0);
457490075Sobrien      gen_insn (tem, 0);
457518334Speter    }
457618334Speter
457718334Speter  /* Expand DEFINE_DELAY information into new attribute.  */
457818334Speter  if (num_delays)
457918334Speter    expand_delays ();
458018334Speter
458118334Speter  printf ("#include \"config.h\"\n");
458250397Sobrien  printf ("#include \"system.h\"\n");
4583132718Skan  printf ("#include \"coretypes.h\"\n");
4584132718Skan  printf ("#include \"tm.h\"\n");
458518334Speter  printf ("#include \"rtl.h\"\n");
458690075Sobrien  printf ("#include \"tm_p.h\"\n");
458718334Speter  printf ("#include \"insn-config.h\"\n");
458818334Speter  printf ("#include \"recog.h\"\n");
458918334Speter  printf ("#include \"regs.h\"\n");
459018334Speter  printf ("#include \"real.h\"\n");
459118334Speter  printf ("#include \"output.h\"\n");
459218334Speter  printf ("#include \"insn-attr.h\"\n");
459352284Sobrien  printf ("#include \"toplev.h\"\n");
459490075Sobrien  printf ("#include \"flags.h\"\n");
4595117395Skan  printf ("#include \"function.h\"\n");
459690075Sobrien  printf ("\n");
459790075Sobrien  printf ("#define operands recog_data.operand\n\n");
459818334Speter
459918334Speter  /* Make `insn_alternatives'.  */
4600132718Skan  insn_alternatives = oballoc (insn_code_number * sizeof (int));
460118334Speter  for (id = defs; id; id = id->next)
460218334Speter    if (id->insn_code >= 0)
460318334Speter      insn_alternatives[id->insn_code] = (1 << id->num_alternatives) - 1;
460418334Speter
460518334Speter  /* Make `insn_n_alternatives'.  */
4606132718Skan  insn_n_alternatives = oballoc (insn_code_number * sizeof (int));
460718334Speter  for (id = defs; id; id = id->next)
460818334Speter    if (id->insn_code >= 0)
460918334Speter      insn_n_alternatives[id->insn_code] = id->num_alternatives;
461018334Speter
4611169689Skan  /* Construct extra attributes for automata.  */
4612169689Skan  make_automaton_attrs ();
4613169689Skan
461418334Speter  /* Prepare to write out attribute subroutines by checking everything stored
461518334Speter     away and building the attribute cases.  */
461618334Speter
461718334Speter  check_defs ();
461890075Sobrien
461918334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
462018334Speter    for (attr = attrs[i]; attr; attr = attr->next)
462190075Sobrien      attr->default_val->value
462290075Sobrien	= check_attr_value (attr->default_val->value, attr);
462318334Speter
462490075Sobrien  if (have_error)
462590075Sobrien    return FATAL_EXIT_CODE;
462690075Sobrien
462790075Sobrien  for (i = 0; i < MAX_ATTRS_INDEX; i++)
462890075Sobrien    for (attr = attrs[i]; attr; attr = attr->next)
462990075Sobrien      fill_attr (attr);
463090075Sobrien
463118334Speter  /* Construct extra attributes for `length'.  */
463218334Speter  make_length_attrs ();
463318334Speter
463450397Sobrien  /* Perform any possible optimizations to speed up compilation.  */
463518334Speter  optimize_attrs ();
463618334Speter
463718334Speter  /* Now write out all the `gen_attr_...' routines.  Do these before the
4638169689Skan     special routines so that they get defined before they are used.  */
463918334Speter
464018334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
464118334Speter    for (attr = attrs[i]; attr; attr = attr->next)
464218334Speter      {
464350397Sobrien	if (! attr->is_special && ! attr->is_const)
4644169689Skan	  write_attr_get (attr);
464518334Speter      }
464618334Speter
464718334Speter  /* Write out delay eligibility information, if DEFINE_DELAY present.
464818334Speter     (The function to compute the number of delay slots will be written
464918334Speter     below.)  */
465018334Speter  if (num_delays)
465118334Speter    {
465218334Speter      write_eligible_delay ("delay");
465318334Speter      if (have_annul_true)
465418334Speter	write_eligible_delay ("annul_true");
465518334Speter      if (have_annul_false)
465618334Speter	write_eligible_delay ("annul_false");
465718334Speter    }
465818334Speter
4659132718Skan  /* Write out constant delay slot info.  */
466018334Speter  write_const_num_delay_slots ();
466118334Speter
466250397Sobrien  write_length_unit_log ();
466350397Sobrien
466418334Speter  fflush (stdout);
466590075Sobrien  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
466618334Speter}
4667