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:
962259563Spfg    case BSWAP:
96350397Sobrien      XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
96450397Sobrien      break;
96550397Sobrien
96618334Speter    case COND:
96718334Speter      if (XVECLEN (exp, 0) % 2 != 0)
96890075Sobrien	{
96990075Sobrien	  message_with_line (attr->lineno,
97090075Sobrien			     "first operand of COND must have even length");
97190075Sobrien	  have_error = 1;
97290075Sobrien	  break;
97390075Sobrien	}
97418334Speter
97518334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
97618334Speter	{
97718334Speter	  XVECEXP (exp, 0, i) = check_attr_test (XVECEXP (exp, 0, i),
97890075Sobrien						 attr ? attr->is_const : 0,
97990075Sobrien						 attr ? attr->lineno : 0);
98018334Speter	  XVECEXP (exp, 0, i + 1)
98118334Speter	    = check_attr_value (XVECEXP (exp, 0, i + 1), attr);
98218334Speter	}
98318334Speter
98418334Speter      XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
98518334Speter      break;
98618334Speter
98752284Sobrien    case ATTR:
98852284Sobrien      {
989132718Skan	struct attr_desc *attr2 = find_attr (&XSTR (exp, 0), 0);
99052284Sobrien	if (attr2 == NULL)
99190075Sobrien	  {
99290075Sobrien	    message_with_line (attr ? attr->lineno : 0,
99390075Sobrien			       "unknown attribute `%s' in ATTR",
99490075Sobrien			       XSTR (exp, 0));
99590075Sobrien	    have_error = 1;
99690075Sobrien	  }
99790075Sobrien	else if (attr && attr->is_const && ! attr2->is_const)
99890075Sobrien	  {
99990075Sobrien	    message_with_line (attr->lineno,
100090075Sobrien		"non-constant attribute `%s' referenced from `%s'",
100190075Sobrien		XSTR (exp, 0), attr->name);
100290075Sobrien	    have_error = 1;
100390075Sobrien	  }
100490075Sobrien	else if (attr
1005169689Skan		 && attr->is_numeric != attr2->is_numeric)
100690075Sobrien	  {
100790075Sobrien	    message_with_line (attr->lineno,
100890075Sobrien		"numeric attribute mismatch calling `%s' from `%s'",
100990075Sobrien		XSTR (exp, 0), attr->name);
101090075Sobrien	    have_error = 1;
101190075Sobrien	  }
101252284Sobrien      }
101352284Sobrien      break;
101452284Sobrien
101518334Speter    case SYMBOL_REF:
101652284Sobrien      /* A constant SYMBOL_REF is valid as a constant attribute test and
101752284Sobrien         is expanded later by make_canonical into a COND.  In a non-constant
101852284Sobrien         attribute test, it is left be.  */
101952284Sobrien      return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
102018334Speter
102118334Speter    default:
102290075Sobrien      message_with_line (attr ? attr->lineno : 0,
102390075Sobrien			 "invalid operation `%s' for attribute value",
102490075Sobrien			 GET_RTX_NAME (GET_CODE (exp)));
102590075Sobrien      have_error = 1;
102690075Sobrien      break;
102718334Speter    }
102818334Speter
102918334Speter  return exp;
103018334Speter}
1031132718Skan
103218334Speter/* Given an SET_ATTR_ALTERNATIVE expression, convert to the canonical SET.
1033169689Skan   It becomes a COND with each test being (eq_attr "alternative" "n") */
103418334Speter
103518334Speterstatic rtx
1036132718Skanconvert_set_attr_alternative (rtx exp, struct insn_def *id)
103718334Speter{
103890075Sobrien  int num_alt = id->num_alternatives;
103918334Speter  rtx condexp;
104018334Speter  int i;
104118334Speter
104218334Speter  if (XVECLEN (exp, 1) != num_alt)
104390075Sobrien    {
104490075Sobrien      message_with_line (id->lineno,
104590075Sobrien			 "bad number of entries in SET_ATTR_ALTERNATIVE");
104690075Sobrien      have_error = 1;
104790075Sobrien      return NULL_RTX;
104890075Sobrien    }
104918334Speter
105018334Speter  /* Make a COND with all tests but the last.  Select the last value via the
105118334Speter     default.  */
105218334Speter  condexp = rtx_alloc (COND);
105318334Speter  XVEC (condexp, 0) = rtvec_alloc ((num_alt - 1) * 2);
105418334Speter
105518334Speter  for (i = 0; i < num_alt - 1; i++)
105618334Speter    {
105790075Sobrien      const char *p;
105818334Speter      p = attr_numeral (i);
105918334Speter
106018334Speter      XVECEXP (condexp, 0, 2 * i) = attr_eq (alternative_name, p);
106118334Speter      XVECEXP (condexp, 0, 2 * i + 1) = XVECEXP (exp, 1, i);
106218334Speter    }
106318334Speter
106418334Speter  XEXP (condexp, 1) = XVECEXP (exp, 1, i);
106518334Speter
106618334Speter  return attr_rtx (SET, attr_rtx (ATTR, XSTR (exp, 0)), condexp);
106718334Speter}
1068132718Skan
106918334Speter/* Given a SET_ATTR, convert to the appropriate SET.  If a comma-separated
107018334Speter   list of values is given, convert to SET_ATTR_ALTERNATIVE first.  */
107118334Speter
107218334Speterstatic rtx
1073132718Skanconvert_set_attr (rtx exp, struct insn_def *id)
107418334Speter{
107518334Speter  rtx newexp;
107690075Sobrien  const char *name_ptr;
107718334Speter  char *p;
107818334Speter  int n;
107918334Speter
108018334Speter  /* See how many alternative specified.  */
108118334Speter  n = n_comma_elts (XSTR (exp, 1));
108218334Speter  if (n == 1)
108318334Speter    return attr_rtx (SET,
108418334Speter		     attr_rtx (ATTR, XSTR (exp, 0)),
108518334Speter		     attr_rtx (CONST_STRING, XSTR (exp, 1)));
108618334Speter
108718334Speter  newexp = rtx_alloc (SET_ATTR_ALTERNATIVE);
108818334Speter  XSTR (newexp, 0) = XSTR (exp, 0);
108918334Speter  XVEC (newexp, 1) = rtvec_alloc (n);
109018334Speter
109118334Speter  /* Process each comma-separated name.  */
109218334Speter  name_ptr = XSTR (exp, 1);
109318334Speter  n = 0;
109418334Speter  while ((p = next_comma_elt (&name_ptr)) != NULL)
109518334Speter    XVECEXP (newexp, 1, n++) = attr_rtx (CONST_STRING, p);
109618334Speter
109790075Sobrien  return convert_set_attr_alternative (newexp, id);
109818334Speter}
1099132718Skan
110018334Speter/* Scan all definitions, checking for validity.  Also, convert any SET_ATTR
110118334Speter   and SET_ATTR_ALTERNATIVE expressions to the corresponding SET
110250397Sobrien   expressions.  */
110318334Speter
110418334Speterstatic void
1105132718Skancheck_defs (void)
110618334Speter{
110718334Speter  struct insn_def *id;
110818334Speter  struct attr_desc *attr;
110918334Speter  int i;
111018334Speter  rtx value;
111118334Speter
111218334Speter  for (id = defs; id; id = id->next)
111318334Speter    {
111418334Speter      if (XVEC (id->def, id->vec_idx) == NULL)
111518334Speter	continue;
111618334Speter
111718334Speter      for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
111818334Speter	{
111918334Speter	  value = XVECEXP (id->def, id->vec_idx, i);
112018334Speter	  switch (GET_CODE (value))
112118334Speter	    {
112218334Speter	    case SET:
112318334Speter	      if (GET_CODE (XEXP (value, 0)) != ATTR)
112490075Sobrien		{
112590075Sobrien		  message_with_line (id->lineno, "bad attribute set");
112690075Sobrien		  have_error = 1;
112790075Sobrien		  value = NULL_RTX;
112890075Sobrien		}
112918334Speter	      break;
113018334Speter
113118334Speter	    case SET_ATTR_ALTERNATIVE:
113290075Sobrien	      value = convert_set_attr_alternative (value, id);
113318334Speter	      break;
113418334Speter
113518334Speter	    case SET_ATTR:
113690075Sobrien	      value = convert_set_attr (value, id);
113718334Speter	      break;
113818334Speter
113918334Speter	    default:
114090075Sobrien	      message_with_line (id->lineno, "invalid attribute code %s",
114190075Sobrien				 GET_RTX_NAME (GET_CODE (value)));
114290075Sobrien	      have_error = 1;
114390075Sobrien	      value = NULL_RTX;
114418334Speter	    }
114590075Sobrien	  if (value == NULL_RTX)
114690075Sobrien	    continue;
114718334Speter
1148132718Skan	  if ((attr = find_attr (&XSTR (XEXP (value, 0), 0), 0)) == NULL)
114990075Sobrien	    {
115090075Sobrien	      message_with_line (id->lineno, "unknown attribute %s",
115190075Sobrien				 XSTR (XEXP (value, 0), 0));
115290075Sobrien	      have_error = 1;
115390075Sobrien	      continue;
115490075Sobrien	    }
115518334Speter
115618334Speter	  XVECEXP (id->def, id->vec_idx, i) = value;
115718334Speter	  XEXP (value, 1) = check_attr_value (XEXP (value, 1), attr);
115818334Speter	}
115918334Speter    }
116018334Speter}
116118334Speter
116218334Speter/* Given a valid expression for an attribute value, remove any IF_THEN_ELSE
116318334Speter   expressions by converting them into a COND.  This removes cases from this
116418334Speter   program.  Also, replace an attribute value of "*" with the default attribute
116518334Speter   value.  */
116618334Speter
116718334Speterstatic rtx
1168132718Skanmake_canonical (struct attr_desc *attr, rtx exp)
116918334Speter{
117018334Speter  int i;
117118334Speter  rtx newexp;
117218334Speter
117318334Speter  switch (GET_CODE (exp))
117418334Speter    {
117518334Speter    case CONST_INT:
117618334Speter      exp = make_numeric_value (INTVAL (exp));
117718334Speter      break;
117818334Speter
117918334Speter    case CONST_STRING:
118018334Speter      if (! strcmp (XSTR (exp, 0), "*"))
118118334Speter	{
118218334Speter	  if (attr == 0 || attr->default_val == 0)
118390075Sobrien	    fatal ("(attr_value \"*\") used in invalid context");
118418334Speter	  exp = attr->default_val->value;
118518334Speter	}
1186132718Skan      else
1187132718Skan	XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
118818334Speter
118918334Speter      break;
119018334Speter
119118334Speter    case SYMBOL_REF:
1192117395Skan      if (!attr->is_const || ATTR_IND_SIMPLIFIED_P (exp))
119318334Speter	break;
119418334Speter      /* The SYMBOL_REF is constant for a given run, so mark it as unchanging.
119518334Speter	 This makes the COND something that won't be considered an arbitrary
119618334Speter	 expression by walk_attr_value.  */
1197117395Skan      ATTR_IND_SIMPLIFIED_P (exp) = 1;
119818334Speter      exp = check_attr_value (exp, attr);
119950397Sobrien      break;
120018334Speter
120118334Speter    case IF_THEN_ELSE:
120218334Speter      newexp = rtx_alloc (COND);
120318334Speter      XVEC (newexp, 0) = rtvec_alloc (2);
120418334Speter      XVECEXP (newexp, 0, 0) = XEXP (exp, 0);
120518334Speter      XVECEXP (newexp, 0, 1) = XEXP (exp, 1);
120618334Speter
120718334Speter      XEXP (newexp, 1) = XEXP (exp, 2);
120818334Speter
120918334Speter      exp = newexp;
121018334Speter      /* Fall through to COND case since this is now a COND.  */
121118334Speter
121218334Speter    case COND:
121318334Speter      {
121418334Speter	int allsame = 1;
121518334Speter	rtx defval;
121618334Speter
121750397Sobrien	/* First, check for degenerate COND.  */
121818334Speter	if (XVECLEN (exp, 0) == 0)
121918334Speter	  return make_canonical (attr, XEXP (exp, 1));
122018334Speter	defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
122118334Speter
122218334Speter	for (i = 0; i < XVECLEN (exp, 0); i += 2)
122318334Speter	  {
122418334Speter	    XVECEXP (exp, 0, i) = copy_boolean (XVECEXP (exp, 0, i));
122518334Speter	    XVECEXP (exp, 0, i + 1)
122618334Speter	      = make_canonical (attr, XVECEXP (exp, 0, i + 1));
122718334Speter	    if (! rtx_equal_p (XVECEXP (exp, 0, i + 1), defval))
122818334Speter	      allsame = 0;
122918334Speter	  }
123018334Speter	if (allsame)
123118334Speter	  return defval;
123218334Speter      }
123350397Sobrien      break;
123450397Sobrien
123550397Sobrien    default:
123650397Sobrien      break;
123718334Speter    }
123818334Speter
123918334Speter  return exp;
124018334Speter}
124118334Speter
124218334Speterstatic rtx
1243132718Skancopy_boolean (rtx exp)
124418334Speter{
124518334Speter  if (GET_CODE (exp) == AND || GET_CODE (exp) == IOR)
124618334Speter    return attr_rtx (GET_CODE (exp), copy_boolean (XEXP (exp, 0)),
124718334Speter		     copy_boolean (XEXP (exp, 1)));
1248132718Skan  if (GET_CODE (exp) == MATCH_OPERAND)
1249132718Skan    {
1250132718Skan      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1251132718Skan      XSTR (exp, 2) = DEF_ATTR_STRING (XSTR (exp, 2));
1252132718Skan    }
1253132718Skan  else if (GET_CODE (exp) == EQ_ATTR)
1254132718Skan    {
1255132718Skan      XSTR (exp, 0) = DEF_ATTR_STRING (XSTR (exp, 0));
1256132718Skan      XSTR (exp, 1) = DEF_ATTR_STRING (XSTR (exp, 1));
1257132718Skan    }
1258132718Skan
125918334Speter  return exp;
126018334Speter}
1261132718Skan
126218334Speter/* Given a value and an attribute description, return a `struct attr_value *'
126318334Speter   that represents that value.  This is either an existing structure, if the
126418334Speter   value has been previously encountered, or a newly-created structure.
126518334Speter
126618334Speter   `insn_code' is the code of an insn whose attribute has the specified
126718334Speter   value (-2 if not processing an insn).  We ensure that all insns for
126818334Speter   a given value have the same number of alternatives if the value checks
126918334Speter   alternatives.  */
127018334Speter
127118334Speterstatic struct attr_value *
1272132718Skanget_attr_value (rtx value, struct attr_desc *attr, int insn_code)
127318334Speter{
127418334Speter  struct attr_value *av;
127518334Speter  int num_alt = 0;
127618334Speter
127718334Speter  value = make_canonical (attr, value);
127818334Speter  if (compares_alternatives_p (value))
127918334Speter    {
128018334Speter      if (insn_code < 0 || insn_alternatives == NULL)
128118334Speter	fatal ("(eq_attr \"alternatives\" ...) used in non-insn context");
128218334Speter      else
128318334Speter	num_alt = insn_alternatives[insn_code];
128418334Speter    }
128518334Speter
128618334Speter  for (av = attr->first_value; av; av = av->next)
128718334Speter    if (rtx_equal_p (value, av->value)
128818334Speter	&& (num_alt == 0 || av->first_insn == NULL
1289169689Skan	    || insn_alternatives[av->first_insn->def->insn_code]))
129018334Speter      return av;
129118334Speter
1292132718Skan  av = oballoc (sizeof (struct attr_value));
129318334Speter  av->value = value;
129418334Speter  av->next = attr->first_value;
129518334Speter  attr->first_value = av;
129618334Speter  av->first_insn = NULL;
129718334Speter  av->num_insns = 0;
129818334Speter  av->has_asm_insn = 0;
129918334Speter
130018334Speter  return av;
130118334Speter}
1302132718Skan
130318334Speter/* After all DEFINE_DELAYs have been read in, create internal attributes
130418334Speter   to generate the required routines.
130518334Speter
130618334Speter   First, we compute the number of delay slots for each insn (as a COND of
130718334Speter   each of the test expressions in DEFINE_DELAYs).  Then, if more than one
130818334Speter   delay type is specified, we compute a similar function giving the
130918334Speter   DEFINE_DELAY ordinal for each insn.
131018334Speter
131118334Speter   Finally, for each [DEFINE_DELAY, slot #] pair, we compute an attribute that
131218334Speter   tells whether a given insn can be in that delay slot.
131318334Speter
131418334Speter   Normal attribute filling and optimization expands these to contain the
131518334Speter   information needed to handle delay slots.  */
131618334Speter
131718334Speterstatic void
1318132718Skanexpand_delays (void)
131918334Speter{
132018334Speter  struct delay_desc *delay;
132118334Speter  rtx condexp;
132218334Speter  rtx newexp;
132318334Speter  int i;
132418334Speter  char *p;
132518334Speter
132618334Speter  /* First, generate data for `num_delay_slots' function.  */
132718334Speter
132818334Speter  condexp = rtx_alloc (COND);
132918334Speter  XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
133018334Speter  XEXP (condexp, 1) = make_numeric_value (0);
133118334Speter
133218334Speter  for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
133318334Speter    {
133418334Speter      XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
133518334Speter      XVECEXP (condexp, 0, i + 1)
133618334Speter	= make_numeric_value (XVECLEN (delay->def, 1) / 3);
133718334Speter    }
133818334Speter
1339132718Skan  make_internal_attr (num_delay_slots_str, condexp, ATTR_NONE);
134018334Speter
134118334Speter  /* If more than one delay type, do the same for computing the delay type.  */
134218334Speter  if (num_delays > 1)
134318334Speter    {
134418334Speter      condexp = rtx_alloc (COND);
134518334Speter      XVEC (condexp, 0) = rtvec_alloc (num_delays * 2);
134618334Speter      XEXP (condexp, 1) = make_numeric_value (0);
134718334Speter
134818334Speter      for (i = 0, delay = delays; delay; i += 2, delay = delay->next)
134918334Speter	{
135018334Speter	  XVECEXP (condexp, 0, i) = XEXP (delay->def, 0);
135118334Speter	  XVECEXP (condexp, 0, i + 1) = make_numeric_value (delay->num);
135218334Speter	}
135318334Speter
1354132718Skan      make_internal_attr (delay_type_str, condexp, ATTR_SPECIAL);
135518334Speter    }
135618334Speter
135718334Speter  /* For each delay possibility and delay slot, compute an eligibility
135818334Speter     attribute for non-annulled insns and for each type of annulled (annul
135918334Speter     if true and annul if false).  */
136090075Sobrien  for (delay = delays; delay; delay = delay->next)
136190075Sobrien    {
136290075Sobrien      for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
136390075Sobrien	{
136490075Sobrien	  condexp = XVECEXP (delay->def, 1, i);
136590075Sobrien	  if (condexp == 0)
136690075Sobrien	    condexp = false_rtx;
136790075Sobrien	  newexp = attr_rtx (IF_THEN_ELSE, condexp,
136890075Sobrien			     make_numeric_value (1), make_numeric_value (0));
136918334Speter
137090075Sobrien	  p = attr_printf (sizeof "*delay__" + MAX_DIGITS * 2,
137190075Sobrien			   "*delay_%d_%d", delay->num, i / 3);
1372132718Skan	  make_internal_attr (p, newexp, ATTR_SPECIAL);
137318334Speter
137490075Sobrien	  if (have_annul_true)
137590075Sobrien	    {
137690075Sobrien	      condexp = XVECEXP (delay->def, 1, i + 1);
137790075Sobrien	      if (condexp == 0) condexp = false_rtx;
137890075Sobrien	      newexp = attr_rtx (IF_THEN_ELSE, condexp,
137990075Sobrien				 make_numeric_value (1),
138090075Sobrien				 make_numeric_value (0));
138190075Sobrien	      p = attr_printf (sizeof "*annul_true__" + MAX_DIGITS * 2,
138290075Sobrien			       "*annul_true_%d_%d", delay->num, i / 3);
1383132718Skan	      make_internal_attr (p, newexp, ATTR_SPECIAL);
138490075Sobrien	    }
138518334Speter
138690075Sobrien	  if (have_annul_false)
138790075Sobrien	    {
138890075Sobrien	      condexp = XVECEXP (delay->def, 1, i + 2);
138990075Sobrien	      if (condexp == 0) condexp = false_rtx;
139090075Sobrien	      newexp = attr_rtx (IF_THEN_ELSE, condexp,
139190075Sobrien				 make_numeric_value (1),
139290075Sobrien				 make_numeric_value (0));
139390075Sobrien	      p = attr_printf (sizeof "*annul_false__" + MAX_DIGITS * 2,
139490075Sobrien			       "*annul_false_%d_%d", delay->num, i / 3);
1395132718Skan	      make_internal_attr (p, newexp, ATTR_SPECIAL);
139690075Sobrien	    }
139790075Sobrien	}
139890075Sobrien    }
139918334Speter}
1400132718Skan
140118334Speter/* Once all attributes and insns have been read and checked, we construct for
140218334Speter   each attribute value a list of all the insns that have that value for
140318334Speter   the attribute.  */
140418334Speter
140518334Speterstatic void
1406132718Skanfill_attr (struct attr_desc *attr)
140718334Speter{
140818334Speter  struct attr_value *av;
140918334Speter  struct insn_ent *ie;
141018334Speter  struct insn_def *id;
141118334Speter  int i;
141218334Speter  rtx value;
141318334Speter
141418334Speter  /* Don't fill constant attributes.  The value is independent of
141518334Speter     any particular insn.  */
141618334Speter  if (attr->is_const)
141718334Speter    return;
141818334Speter
141918334Speter  for (id = defs; id; id = id->next)
142018334Speter    {
142118334Speter      /* If no value is specified for this insn for this attribute, use the
142218334Speter	 default.  */
142318334Speter      value = NULL;
142418334Speter      if (XVEC (id->def, id->vec_idx))
142518334Speter	for (i = 0; i < XVECLEN (id->def, id->vec_idx); i++)
1426132718Skan	  if (! strcmp_check (XSTR (XEXP (XVECEXP (id->def, id->vec_idx, i), 0), 0),
1427132718Skan			      attr->name))
142818334Speter	    value = XEXP (XVECEXP (id->def, id->vec_idx, i), 1);
142918334Speter
143018334Speter      if (value == NULL)
143118334Speter	av = attr->default_val;
143218334Speter      else
143318334Speter	av = get_attr_value (value, attr, id->insn_code);
143418334Speter
1435132718Skan      ie = oballoc (sizeof (struct insn_ent));
1436169689Skan      ie->def = id;
143718334Speter      insert_insn_ent (av, ie);
143818334Speter    }
143918334Speter}
1440132718Skan
144118334Speter/* Given an expression EXP, see if it is a COND or IF_THEN_ELSE that has a
144218334Speter   test that checks relative positions of insns (uses MATCH_DUP or PC).
144318334Speter   If so, replace it with what is obtained by passing the expression to
144418334Speter   ADDRESS_FN.  If not but it is a COND or IF_THEN_ELSE, call this routine
144518334Speter   recursively on each value (including the default value).  Otherwise,
144618334Speter   return the value returned by NO_ADDRESS_FN applied to EXP.  */
144718334Speter
144818334Speterstatic rtx
1449132718Skansubstitute_address (rtx exp, rtx (*no_address_fn) (rtx),
1450132718Skan		    rtx (*address_fn) (rtx))
145118334Speter{
145218334Speter  int i;
145318334Speter  rtx newexp;
145418334Speter
145518334Speter  if (GET_CODE (exp) == COND)
145618334Speter    {
145718334Speter      /* See if any tests use addresses.  */
145818334Speter      address_used = 0;
145918334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
146018334Speter	walk_attr_value (XVECEXP (exp, 0, i));
146118334Speter
146218334Speter      if (address_used)
146318334Speter	return (*address_fn) (exp);
146418334Speter
146518334Speter      /* Make a new copy of this COND, replacing each element.  */
146618334Speter      newexp = rtx_alloc (COND);
146718334Speter      XVEC (newexp, 0) = rtvec_alloc (XVECLEN (exp, 0));
146818334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
146918334Speter	{
147018334Speter	  XVECEXP (newexp, 0, i) = XVECEXP (exp, 0, i);
147118334Speter	  XVECEXP (newexp, 0, i + 1)
147218334Speter	    = substitute_address (XVECEXP (exp, 0, i + 1),
147318334Speter				  no_address_fn, address_fn);
147418334Speter	}
147518334Speter
147618334Speter      XEXP (newexp, 1) = substitute_address (XEXP (exp, 1),
147718334Speter					     no_address_fn, address_fn);
147818334Speter
147918334Speter      return newexp;
148018334Speter    }
148118334Speter
148218334Speter  else if (GET_CODE (exp) == IF_THEN_ELSE)
148318334Speter    {
148418334Speter      address_used = 0;
148518334Speter      walk_attr_value (XEXP (exp, 0));
148618334Speter      if (address_used)
148718334Speter	return (*address_fn) (exp);
148818334Speter
148918334Speter      return attr_rtx (IF_THEN_ELSE,
149018334Speter		       substitute_address (XEXP (exp, 0),
149118334Speter					   no_address_fn, address_fn),
149218334Speter		       substitute_address (XEXP (exp, 1),
149318334Speter					   no_address_fn, address_fn),
149418334Speter		       substitute_address (XEXP (exp, 2),
149518334Speter					   no_address_fn, address_fn));
149618334Speter    }
149718334Speter
149818334Speter  return (*no_address_fn) (exp);
149918334Speter}
1500132718Skan
150118334Speter/* Make new attributes from the `length' attribute.  The following are made,
150218334Speter   each corresponding to a function called from `shorten_branches' or
150318334Speter   `get_attr_length':
150418334Speter
150518334Speter   *insn_default_length		This is the length of the insn to be returned
150618334Speter				by `get_attr_length' before `shorten_branches'
150718334Speter				has been called.  In each case where the length
150818334Speter				depends on relative addresses, the largest
150918334Speter				possible is used.  This routine is also used
151018334Speter				to compute the initial size of the insn.
151118334Speter
151218334Speter   *insn_variable_length_p	This returns 1 if the insn's length depends
151318334Speter				on relative addresses, zero otherwise.
151418334Speter
151518334Speter   *insn_current_length		This is only called when it is known that the
151618334Speter				insn has a variable length and returns the
151718334Speter				current length, based on relative addresses.
151818334Speter  */
151918334Speter
152018334Speterstatic void
1521132718Skanmake_length_attrs (void)
152218334Speter{
1523132718Skan  static const char *new_names[] =
1524132718Skan    {
1525132718Skan      "*insn_default_length",
1526169689Skan      "*insn_min_length",
1527132718Skan      "*insn_variable_length_p",
1528132718Skan      "*insn_current_length"
1529132718Skan    };
1530169689Skan  static rtx (*const no_address_fn[]) (rtx)
1531169689Skan    = {identity_fn,identity_fn, zero_fn, zero_fn};
1532169689Skan  static rtx (*const address_fn[]) (rtx)
1533169689Skan    = {max_fn, min_fn, one_fn, identity_fn};
153450397Sobrien  size_t i;
153518334Speter  struct attr_desc *length_attr, *new_attr;
153618334Speter  struct attr_value *av, *new_av;
153718334Speter  struct insn_ent *ie, *new_ie;
153818334Speter
153918334Speter  /* See if length attribute is defined.  If so, it must be numeric.  Make
154018334Speter     it special so we don't output anything for it.  */
1541132718Skan  length_attr = find_attr (&length_str, 0);
154218334Speter  if (length_attr == 0)
154318334Speter    return;
154418334Speter
154518334Speter  if (! length_attr->is_numeric)
154690075Sobrien    fatal ("length attribute must be numeric");
154718334Speter
154818334Speter  length_attr->is_const = 0;
154918334Speter  length_attr->is_special = 1;
155018334Speter
155118334Speter  /* Make each new attribute, in turn.  */
155290075Sobrien  for (i = 0; i < ARRAY_SIZE (new_names); i++)
155318334Speter    {
155418334Speter      make_internal_attr (new_names[i],
155518334Speter			  substitute_address (length_attr->default_val->value,
155618334Speter					      no_address_fn[i], address_fn[i]),
1557132718Skan			  ATTR_NONE);
1558132718Skan      new_attr = find_attr (&new_names[i], 0);
155918334Speter      for (av = length_attr->first_value; av; av = av->next)
156018334Speter	for (ie = av->first_insn; ie; ie = ie->next)
156118334Speter	  {
156218334Speter	    new_av = get_attr_value (substitute_address (av->value,
156318334Speter							 no_address_fn[i],
156418334Speter							 address_fn[i]),
1565169689Skan				     new_attr, ie->def->insn_code);
1566132718Skan	    new_ie = oballoc (sizeof (struct insn_ent));
1567169689Skan	    new_ie->def = ie->def;
156818334Speter	    insert_insn_ent (new_av, new_ie);
156918334Speter	  }
157018334Speter    }
157118334Speter}
157218334Speter
157318334Speter/* Utility functions called from above routine.  */
157418334Speter
157518334Speterstatic rtx
1576132718Skanidentity_fn (rtx exp)
157718334Speter{
157818334Speter  return exp;
157918334Speter}
158018334Speter
158118334Speterstatic rtx
1582132718Skanzero_fn (rtx exp ATTRIBUTE_UNUSED)
158318334Speter{
158418334Speter  return make_numeric_value (0);
158518334Speter}
158618334Speter
158718334Speterstatic rtx
1588132718Skanone_fn (rtx exp ATTRIBUTE_UNUSED)
158918334Speter{
159018334Speter  return make_numeric_value (1);
159118334Speter}
159218334Speter
159318334Speterstatic rtx
1594132718Skanmax_fn (rtx exp)
159518334Speter{
159652284Sobrien  int unknown;
159752284Sobrien  return make_numeric_value (max_attr_value (exp, &unknown));
159818334Speter}
159950397Sobrien
1600169689Skanstatic rtx
1601169689Skanmin_fn (rtx exp)
1602169689Skan{
1603169689Skan  int unknown;
1604169689Skan  return make_numeric_value (min_attr_value (exp, &unknown));
1605169689Skan}
1606169689Skan
160750397Sobrienstatic void
1608132718Skanwrite_length_unit_log (void)
160950397Sobrien{
1610132718Skan  struct attr_desc *length_attr = find_attr (&length_str, 0);
161150397Sobrien  struct attr_value *av;
161250397Sobrien  struct insn_ent *ie;
161350397Sobrien  unsigned int length_unit_log, length_or;
161452284Sobrien  int unknown = 0;
161550397Sobrien
161650397Sobrien  if (length_attr == 0)
161750397Sobrien    return;
161852284Sobrien  length_or = or_attr_value (length_attr->default_val->value, &unknown);
161952284Sobrien  for (av = length_attr->first_value; av; av = av->next)
162052284Sobrien    for (ie = av->first_insn; ie; ie = ie->next)
162152284Sobrien      length_or |= or_attr_value (av->value, &unknown);
162252284Sobrien
162352284Sobrien  if (unknown)
162452284Sobrien    length_unit_log = 0;
162552284Sobrien  else
162652284Sobrien    {
162752284Sobrien      length_or = ~length_or;
162852284Sobrien      for (length_unit_log = 0; length_or & 1; length_or >>= 1)
162990075Sobrien	length_unit_log++;
163052284Sobrien    }
1631169689Skan  printf ("const int length_unit_log = %u;\n", length_unit_log);
163250397Sobrien}
1633132718Skan
163418334Speter/* Take a COND expression and see if any of the conditions in it can be
163518334Speter   simplified.  If any are known true or known false for the particular insn
163618334Speter   code, the COND can be further simplified.
163718334Speter
163818334Speter   Also call ourselves on any COND operations that are values of this COND.
163918334Speter
164018334Speter   We do not modify EXP; rather, we make and return a new rtx.  */
164118334Speter
164218334Speterstatic rtx
1643132718Skansimplify_cond (rtx exp, int insn_code, int insn_index)
164418334Speter{
164518334Speter  int i, j;
164618334Speter  /* We store the desired contents here,
164718334Speter     then build a new expression if they don't match EXP.  */
164818334Speter  rtx defval = XEXP (exp, 1);
164918334Speter  rtx new_defval = XEXP (exp, 1);
165018334Speter  int len = XVECLEN (exp, 0);
1651169689Skan  rtx *tests = XNEWVEC (rtx, len);
165218334Speter  int allsame = 1;
165390075Sobrien  rtx ret;
165418334Speter
165518334Speter  /* This lets us free all storage allocated below, if appropriate.  */
1656222097Sbenl  (void) obstack_finish (rtl_obstack);
165718334Speter
165890075Sobrien  memcpy (tests, XVEC (exp, 0)->elem, len * sizeof (rtx));
165918334Speter
166018334Speter  /* See if default value needs simplification.  */
166118334Speter  if (GET_CODE (defval) == COND)
166218334Speter    new_defval = simplify_cond (defval, insn_code, insn_index);
166318334Speter
166418334Speter  /* Simplify the subexpressions, and see what tests we can get rid of.  */
166518334Speter
166618334Speter  for (i = 0; i < len; i += 2)
166718334Speter    {
166818334Speter      rtx newtest, newval;
166918334Speter
167018334Speter      /* Simplify this test.  */
167190075Sobrien      newtest = simplify_test_exp_in_temp (tests[i], insn_code, insn_index);
167290075Sobrien      tests[i] = newtest;
167318334Speter
167490075Sobrien      newval = tests[i + 1];
167518334Speter      /* See if this value may need simplification.  */
167618334Speter      if (GET_CODE (newval) == COND)
167718334Speter	newval = simplify_cond (newval, insn_code, insn_index);
167818334Speter
167918334Speter      /* Look for ways to delete or combine this test.  */
168018334Speter      if (newtest == true_rtx)
168118334Speter	{
168218334Speter	  /* If test is true, make this value the default
168318334Speter	     and discard this + any following tests.  */
168418334Speter	  len = i;
168590075Sobrien	  defval = tests[i + 1];
168618334Speter	  new_defval = newval;
168718334Speter	}
168818334Speter
168918334Speter      else if (newtest == false_rtx)
169018334Speter	{
169118334Speter	  /* If test is false, discard it and its value.  */
169218334Speter	  for (j = i; j < len - 2; j++)
169390075Sobrien	    tests[j] = tests[j + 2];
1694132718Skan	  i -= 2;
169518334Speter	  len -= 2;
169618334Speter	}
169718334Speter
169890075Sobrien      else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
169918334Speter	{
170018334Speter	  /* If this value and the value for the prev test are the same,
170118334Speter	     merge the tests.  */
170218334Speter
170390075Sobrien	  tests[i - 2]
170490075Sobrien	    = insert_right_side (IOR, tests[i - 2], newtest,
170518334Speter				 insn_code, insn_index);
170618334Speter
170718334Speter	  /* Delete this test/value.  */
170818334Speter	  for (j = i; j < len - 2; j++)
170990075Sobrien	    tests[j] = tests[j + 2];
171018334Speter	  len -= 2;
1711132718Skan	  i -= 2;
171218334Speter	}
171318334Speter
171418334Speter      else
171590075Sobrien	tests[i + 1] = newval;
171618334Speter    }
171718334Speter
171818334Speter  /* If the last test in a COND has the same value
171918334Speter     as the default value, that test isn't needed.  */
172018334Speter
172190075Sobrien  while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
172218334Speter    len -= 2;
172318334Speter
172418334Speter  /* See if we changed anything.  */
172518334Speter  if (len != XVECLEN (exp, 0) || new_defval != XEXP (exp, 1))
172618334Speter    allsame = 0;
172718334Speter  else
172818334Speter    for (i = 0; i < len; i++)
172990075Sobrien      if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
173018334Speter	{
173118334Speter	  allsame = 0;
173218334Speter	  break;
173318334Speter	}
173418334Speter
173518334Speter  if (len == 0)
173618334Speter    {
173718334Speter      if (GET_CODE (defval) == COND)
173890075Sobrien	ret = simplify_cond (defval, insn_code, insn_index);
173990075Sobrien      else
174090075Sobrien	ret = defval;
174118334Speter    }
174218334Speter  else if (allsame)
174390075Sobrien    ret = exp;
174418334Speter  else
174518334Speter    {
174618334Speter      rtx newexp = rtx_alloc (COND);
174718334Speter
174818334Speter      XVEC (newexp, 0) = rtvec_alloc (len);
174990075Sobrien      memcpy (XVEC (newexp, 0)->elem, tests, len * sizeof (rtx));
175018334Speter      XEXP (newexp, 1) = new_defval;
175190075Sobrien      ret = newexp;
175218334Speter    }
175390075Sobrien  free (tests);
175490075Sobrien  return ret;
175518334Speter}
1756132718Skan
175718334Speter/* Remove an insn entry from an attribute value.  */
175818334Speter
175918334Speterstatic void
1760132718Skanremove_insn_ent (struct attr_value *av, struct insn_ent *ie)
176118334Speter{
176218334Speter  struct insn_ent *previe;
176318334Speter
176418334Speter  if (av->first_insn == ie)
176518334Speter    av->first_insn = ie->next;
176618334Speter  else
176718334Speter    {
176818334Speter      for (previe = av->first_insn; previe->next != ie; previe = previe->next)
176918334Speter	;
177018334Speter      previe->next = ie->next;
177118334Speter    }
177218334Speter
177318334Speter  av->num_insns--;
1774169689Skan  if (ie->def->insn_code == -1)
177518334Speter    av->has_asm_insn = 0;
177618334Speter
177718334Speter  num_insn_ents--;
177818334Speter}
177918334Speter
178018334Speter/* Insert an insn entry in an attribute value list.  */
178118334Speter
178218334Speterstatic void
1783132718Skaninsert_insn_ent (struct attr_value *av, struct insn_ent *ie)
178418334Speter{
178518334Speter  ie->next = av->first_insn;
178618334Speter  av->first_insn = ie;
178718334Speter  av->num_insns++;
1788169689Skan  if (ie->def->insn_code == -1)
178918334Speter    av->has_asm_insn = 1;
179018334Speter
179118334Speter  num_insn_ents++;
179218334Speter}
1793132718Skan
179418334Speter/* This is a utility routine to take an expression that is a tree of either
179518334Speter   AND or IOR expressions and insert a new term.  The new term will be
179618334Speter   inserted at the right side of the first node whose code does not match
179718334Speter   the root.  A new node will be created with the root's code.  Its left
179818334Speter   side will be the old right side and its right side will be the new
179918334Speter   term.
180018334Speter
180118334Speter   If the `term' is itself a tree, all its leaves will be inserted.  */
180218334Speter
180318334Speterstatic rtx
1804132718Skaninsert_right_side (enum rtx_code code, rtx exp, rtx term, int insn_code, int insn_index)
180518334Speter{
180618334Speter  rtx newexp;
180718334Speter
180818334Speter  /* Avoid consing in some special cases.  */
180918334Speter  if (code == AND && term == true_rtx)
181018334Speter    return exp;
181118334Speter  if (code == AND && term == false_rtx)
181218334Speter    return false_rtx;
181318334Speter  if (code == AND && exp == true_rtx)
181418334Speter    return term;
181518334Speter  if (code == AND && exp == false_rtx)
181618334Speter    return false_rtx;
181718334Speter  if (code == IOR && term == true_rtx)
181818334Speter    return true_rtx;
181918334Speter  if (code == IOR && term == false_rtx)
182018334Speter    return exp;
182118334Speter  if (code == IOR && exp == true_rtx)
182218334Speter    return true_rtx;
182318334Speter  if (code == IOR && exp == false_rtx)
182418334Speter    return term;
182518334Speter  if (attr_equal_p (exp, term))
182618334Speter    return exp;
182718334Speter
182818334Speter  if (GET_CODE (term) == code)
182918334Speter    {
183018334Speter      exp = insert_right_side (code, exp, XEXP (term, 0),
183118334Speter			       insn_code, insn_index);
183218334Speter      exp = insert_right_side (code, exp, XEXP (term, 1),
183318334Speter			       insn_code, insn_index);
183418334Speter
183518334Speter      return exp;
183618334Speter    }
183718334Speter
183818334Speter  if (GET_CODE (exp) == code)
183918334Speter    {
184018334Speter      rtx new = insert_right_side (code, XEXP (exp, 1),
184118334Speter				   term, insn_code, insn_index);
184218334Speter      if (new != XEXP (exp, 1))
184318334Speter	/* Make a copy of this expression and call recursively.  */
184418334Speter	newexp = attr_rtx (code, XEXP (exp, 0), new);
184518334Speter      else
184618334Speter	newexp = exp;
184718334Speter    }
184818334Speter  else
184918334Speter    {
185018334Speter      /* Insert the new term.  */
185118334Speter      newexp = attr_rtx (code, exp, term);
185218334Speter    }
185318334Speter
185490075Sobrien  return simplify_test_exp_in_temp (newexp, insn_code, insn_index);
185518334Speter}
1856132718Skan
185718334Speter/* If we have an expression which AND's a bunch of
185818334Speter	(not (eq_attrq "alternative" "n"))
185918334Speter   terms, we may have covered all or all but one of the possible alternatives.
186018334Speter   If so, we can optimize.  Similarly for IOR's of EQ_ATTR.
186118334Speter
186218334Speter   This routine is passed an expression and either AND or IOR.  It returns a
186318334Speter   bitmask indicating which alternatives are mentioned within EXP.  */
186418334Speter
186518334Speterstatic int
1866132718Skancompute_alternative_mask (rtx exp, enum rtx_code code)
186718334Speter{
186890075Sobrien  const char *string;
186918334Speter  if (GET_CODE (exp) == code)
187018334Speter    return compute_alternative_mask (XEXP (exp, 0), code)
187118334Speter	   | compute_alternative_mask (XEXP (exp, 1), code);
187218334Speter
187318334Speter  else if (code == AND && GET_CODE (exp) == NOT
187418334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
187518334Speter	   && XSTR (XEXP (exp, 0), 0) == alternative_name)
187618334Speter    string = XSTR (XEXP (exp, 0), 1);
187718334Speter
187818334Speter  else if (code == IOR && GET_CODE (exp) == EQ_ATTR
187918334Speter	   && XSTR (exp, 0) == alternative_name)
188018334Speter    string = XSTR (exp, 1);
188118334Speter
1882132718Skan  else if (GET_CODE (exp) == EQ_ATTR_ALT)
1883132718Skan    {
1884132718Skan      if (code == AND && XINT (exp, 1))
1885132718Skan	return XINT (exp, 0);
1886132718Skan
1887132718Skan      if (code == IOR && !XINT (exp, 1))
1888132718Skan	return XINT (exp, 0);
1889132718Skan
1890132718Skan      return 0;
1891132718Skan    }
189218334Speter  else
189318334Speter    return 0;
189418334Speter
189518334Speter  if (string[1] == 0)
189618334Speter    return 1 << (string[0] - '0');
189718334Speter  return 1 << atoi (string);
189818334Speter}
189918334Speter
190018334Speter/* Given I, a single-bit mask, return RTX to compare the `alternative'
190118334Speter   attribute with the value represented by that bit.  */
190218334Speter
190318334Speterstatic rtx
1904132718Skanmake_alternative_compare (int mask)
190518334Speter{
1906132718Skan  return mk_attr_alt (mask);
1907132718Skan}
190818334Speter
190918334Speter/* If we are processing an (eq_attr "attr" "value") test, we find the value
191018334Speter   of "attr" for this insn code.  From that value, we can compute a test
191118334Speter   showing when the EQ_ATTR will be true.  This routine performs that
191218334Speter   computation.  If a test condition involves an address, we leave the EQ_ATTR
191390075Sobrien   intact because addresses are only valid for the `length' attribute.
191418334Speter
191518334Speter   EXP is the EQ_ATTR expression and VALUE is the value of that attribute
191618334Speter   for the insn corresponding to INSN_CODE and INSN_INDEX.  */
191718334Speter
191818334Speterstatic rtx
1919132718Skanevaluate_eq_attr (rtx exp, rtx value, int insn_code, int insn_index)
192018334Speter{
192118334Speter  rtx orexp, andexp;
192218334Speter  rtx right;
192318334Speter  rtx newexp;
192418334Speter  int i;
192518334Speter
1926169689Skan  switch (GET_CODE (value))
192718334Speter    {
1928169689Skan    case CONST_STRING:
1929132718Skan      if (! strcmp_check (XSTR (value, 0), XSTR (exp, 1)))
193018334Speter	newexp = true_rtx;
193118334Speter      else
193218334Speter	newexp = false_rtx;
1933169689Skan      break;
1934169689Skan
1935169689Skan    case SYMBOL_REF:
1936169689Skan      {
1937169689Skan	char *p;
1938169689Skan	char string[256];
1939169689Skan
1940169689Skan	gcc_assert (GET_CODE (exp) == EQ_ATTR);
1941169689Skan	gcc_assert (strlen (XSTR (exp, 0)) + strlen (XSTR (exp, 1)) + 2
1942169689Skan		    <= 256);
1943169689Skan
1944169689Skan	strcpy (string, XSTR (exp, 0));
1945169689Skan	strcat (string, "_");
1946169689Skan	strcat (string, XSTR (exp, 1));
1947169689Skan	for (p = string; *p; p++)
1948169689Skan	  *p = TOUPPER (*p);
1949169689Skan
1950169689Skan	newexp = attr_rtx (EQ, value,
1951169689Skan			   attr_rtx (SYMBOL_REF,
1952169689Skan				     DEF_ATTR_STRING (string)));
1953169689Skan	break;
1954169689Skan      }
195550397Sobrien
1956169689Skan    case COND:
1957169689Skan      /* We construct an IOR of all the cases for which the
1958169689Skan	 requested attribute value is present.  Since we start with
1959169689Skan	 FALSE, if it is not present, FALSE will be returned.
1960169689Skan
196118334Speter	 Each case is the AND of the NOT's of the previous conditions with the
196290075Sobrien	 current condition; in the default case the current condition is TRUE.
1963169689Skan
196418334Speter	 For each possible COND value, call ourselves recursively.
1965169689Skan
196618334Speter	 The extra TRUE and FALSE expressions will be eliminated by another
196750397Sobrien	 call to the simplification routine.  */
196818334Speter
196918334Speter      orexp = false_rtx;
197018334Speter      andexp = true_rtx;
197118334Speter
197218334Speter      for (i = 0; i < XVECLEN (value, 0); i += 2)
197318334Speter	{
197490075Sobrien	  rtx this = simplify_test_exp_in_temp (XVECEXP (value, 0, i),
197590075Sobrien						insn_code, insn_index);
197618334Speter
197718334Speter	  right = insert_right_side (AND, andexp, this,
197818334Speter				     insn_code, insn_index);
197918334Speter	  right = insert_right_side (AND, right,
198018334Speter				     evaluate_eq_attr (exp,
198118334Speter						       XVECEXP (value, 0,
198218334Speter								i + 1),
198318334Speter						       insn_code, insn_index),
198418334Speter				     insn_code, insn_index);
198518334Speter	  orexp = insert_right_side (IOR, orexp, right,
198618334Speter				     insn_code, insn_index);
198718334Speter
198818334Speter	  /* Add this condition into the AND expression.  */
198918334Speter	  newexp = attr_rtx (NOT, this);
199018334Speter	  andexp = insert_right_side (AND, andexp, newexp,
199118334Speter				      insn_code, insn_index);
199218334Speter	}
199318334Speter
199418334Speter      /* Handle the default case.  */
199518334Speter      right = insert_right_side (AND, andexp,
199618334Speter				 evaluate_eq_attr (exp, XEXP (value, 1),
199718334Speter						   insn_code, insn_index),
199818334Speter				 insn_code, insn_index);
199918334Speter      newexp = insert_right_side (IOR, orexp, right, insn_code, insn_index);
2000169689Skan      break;
2001169689Skan
2002169689Skan    default:
2003169689Skan      gcc_unreachable ();
200418334Speter    }
200518334Speter
200618334Speter  /* If uses an address, must return original expression.  But set the
2007117395Skan     ATTR_IND_SIMPLIFIED_P bit so we don't try to simplify it again.  */
200818334Speter
200918334Speter  address_used = 0;
201018334Speter  walk_attr_value (newexp);
201118334Speter
201218334Speter  if (address_used)
201318334Speter    {
2014117395Skan      if (! ATTR_IND_SIMPLIFIED_P (exp))
201518334Speter	return copy_rtx_unchanging (exp);
201618334Speter      return exp;
201718334Speter    }
201818334Speter  else
201918334Speter    return newexp;
202018334Speter}
2021132718Skan
202218334Speter/* This routine is called when an AND of a term with a tree of AND's is
202318334Speter   encountered.  If the term or its complement is present in the tree, it
202418334Speter   can be replaced with TRUE or FALSE, respectively.
202518334Speter
202618334Speter   Note that (eq_attr "att" "v1") and (eq_attr "att" "v2") cannot both
202790075Sobrien   be true and hence are complementary.
202818334Speter
202918334Speter   There is one special case:  If we see
203018334Speter	(and (not (eq_attr "att" "v1"))
203118334Speter	     (eq_attr "att" "v2"))
203218334Speter   this can be replaced by (eq_attr "att" "v2").  To do this we need to
203318334Speter   replace the term, not anything in the AND tree.  So we pass a pointer to
203418334Speter   the term.  */
203518334Speter
203618334Speterstatic rtx
2037132718Skansimplify_and_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
203818334Speter{
203918334Speter  rtx left, right;
204018334Speter  rtx newexp;
204118334Speter  rtx temp;
204218334Speter  int left_eliminates_term, right_eliminates_term;
204318334Speter
204418334Speter  if (GET_CODE (exp) == AND)
204518334Speter    {
204690075Sobrien      left  = simplify_and_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
204718334Speter      right = simplify_and_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
204818334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
204918334Speter	{
2050132718Skan	  newexp = attr_rtx (AND, left, right);
205118334Speter
205290075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
205318334Speter	}
205418334Speter    }
205518334Speter
205618334Speter  else if (GET_CODE (exp) == IOR)
205718334Speter    {
205818334Speter      /* For the IOR case, we do the same as above, except that we can
205918334Speter         only eliminate `term' if both sides of the IOR would do so.  */
206018334Speter      temp = *pterm;
206190075Sobrien      left = simplify_and_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
206218334Speter      left_eliminates_term = (temp == true_rtx);
206318334Speter
206418334Speter      temp = *pterm;
206518334Speter      right = simplify_and_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
206618334Speter      right_eliminates_term = (temp == true_rtx);
206718334Speter
206818334Speter      if (left_eliminates_term && right_eliminates_term)
206918334Speter	*pterm = true_rtx;
207018334Speter
207118334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
207218334Speter	{
2073132718Skan	  newexp = attr_rtx (IOR, left, right);
207418334Speter
207590075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
207618334Speter	}
207718334Speter    }
207818334Speter
207918334Speter  /* Check for simplifications.  Do some extra checking here since this
208018334Speter     routine is called so many times.  */
208118334Speter
208218334Speter  if (exp == *pterm)
208318334Speter    return true_rtx;
208418334Speter
208518334Speter  else if (GET_CODE (exp) == NOT && XEXP (exp, 0) == *pterm)
208618334Speter    return false_rtx;
208718334Speter
208818334Speter  else if (GET_CODE (*pterm) == NOT && exp == XEXP (*pterm, 0))
208918334Speter    return false_rtx;
209018334Speter
2091132718Skan  else if (GET_CODE (exp) == EQ_ATTR_ALT && GET_CODE (*pterm) == EQ_ATTR_ALT)
2092132718Skan    {
2093132718Skan      if (attr_alt_subset_p (*pterm, exp))
2094132718Skan	return true_rtx;
2095132718Skan
2096132718Skan      if (attr_alt_subset_of_compl_p (*pterm, exp))
2097132718Skan	return false_rtx;
2098132718Skan
2099132718Skan      if (attr_alt_subset_p (exp, *pterm))
2100132718Skan	*pterm = true_rtx;
2101132718Skan
2102132718Skan      return exp;
2103132718Skan    }
2104132718Skan
210518334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == EQ_ATTR)
210618334Speter    {
210718334Speter      if (XSTR (exp, 0) != XSTR (*pterm, 0))
210818334Speter	return exp;
210918334Speter
2110132718Skan      if (! strcmp_check (XSTR (exp, 1), XSTR (*pterm, 1)))
211118334Speter	return true_rtx;
211218334Speter      else
211318334Speter	return false_rtx;
211418334Speter    }
211518334Speter
211618334Speter  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
211718334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR)
211818334Speter    {
211918334Speter      if (XSTR (*pterm, 0) != XSTR (XEXP (exp, 0), 0))
212018334Speter	return exp;
212118334Speter
2122132718Skan      if (! strcmp_check (XSTR (*pterm, 1), XSTR (XEXP (exp, 0), 1)))
212318334Speter	return false_rtx;
212418334Speter      else
212518334Speter	return true_rtx;
212618334Speter    }
212718334Speter
212818334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
212918334Speter	   && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR)
213018334Speter    {
213118334Speter      if (XSTR (exp, 0) != XSTR (XEXP (*pterm, 0), 0))
213218334Speter	return exp;
213318334Speter
2134132718Skan      if (! strcmp_check (XSTR (exp, 1), XSTR (XEXP (*pterm, 0), 1)))
213518334Speter	return false_rtx;
213618334Speter      else
213718334Speter	*pterm = true_rtx;
213818334Speter    }
213918334Speter
214018334Speter  else if (GET_CODE (exp) == NOT && GET_CODE (*pterm) == NOT)
214118334Speter    {
214218334Speter      if (attr_equal_p (XEXP (exp, 0), XEXP (*pterm, 0)))
214318334Speter	return true_rtx;
214418334Speter    }
214518334Speter
214618334Speter  else if (GET_CODE (exp) == NOT)
214718334Speter    {
214818334Speter      if (attr_equal_p (XEXP (exp, 0), *pterm))
214918334Speter	return false_rtx;
215018334Speter    }
215118334Speter
215218334Speter  else if (GET_CODE (*pterm) == NOT)
215318334Speter    {
215418334Speter      if (attr_equal_p (XEXP (*pterm, 0), exp))
215518334Speter	return false_rtx;
215618334Speter    }
215718334Speter
215818334Speter  else if (attr_equal_p (exp, *pterm))
215918334Speter    return true_rtx;
216018334Speter
216118334Speter  return exp;
216218334Speter}
2163132718Skan
216418334Speter/* Similar to `simplify_and_tree', but for IOR trees.  */
216518334Speter
216618334Speterstatic rtx
2167132718Skansimplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
216818334Speter{
216918334Speter  rtx left, right;
217018334Speter  rtx newexp;
217118334Speter  rtx temp;
217218334Speter  int left_eliminates_term, right_eliminates_term;
217318334Speter
217418334Speter  if (GET_CODE (exp) == IOR)
217518334Speter    {
217690075Sobrien      left  = simplify_or_tree (XEXP (exp, 0), pterm, insn_code, insn_index);
217718334Speter      right = simplify_or_tree (XEXP (exp, 1), pterm, insn_code, insn_index);
217818334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
217918334Speter	{
218018334Speter	  newexp = attr_rtx (GET_CODE (exp), left, right);
218118334Speter
218290075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
218318334Speter	}
218418334Speter    }
218518334Speter
218618334Speter  else if (GET_CODE (exp) == AND)
218718334Speter    {
218818334Speter      /* For the AND case, we do the same as above, except that we can
218918334Speter         only eliminate `term' if both sides of the AND would do so.  */
219018334Speter      temp = *pterm;
219190075Sobrien      left = simplify_or_tree (XEXP (exp, 0), &temp, insn_code, insn_index);
219218334Speter      left_eliminates_term = (temp == false_rtx);
219318334Speter
219418334Speter      temp = *pterm;
219518334Speter      right = simplify_or_tree (XEXP (exp, 1), &temp, insn_code, insn_index);
219618334Speter      right_eliminates_term = (temp == false_rtx);
219718334Speter
219818334Speter      if (left_eliminates_term && right_eliminates_term)
219918334Speter	*pterm = false_rtx;
220018334Speter
220118334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
220218334Speter	{
220318334Speter	  newexp = attr_rtx (GET_CODE (exp), left, right);
220418334Speter
220590075Sobrien	  exp = simplify_test_exp_in_temp (newexp, insn_code, insn_index);
220618334Speter	}
220718334Speter    }
220818334Speter
220918334Speter  if (attr_equal_p (exp, *pterm))
221018334Speter    return false_rtx;
221118334Speter
221218334Speter  else if (GET_CODE (exp) == NOT && attr_equal_p (XEXP (exp, 0), *pterm))
221318334Speter    return true_rtx;
221418334Speter
221518334Speter  else if (GET_CODE (*pterm) == NOT && attr_equal_p (XEXP (*pterm, 0), exp))
221618334Speter    return true_rtx;
221718334Speter
221818334Speter  else if (GET_CODE (*pterm) == EQ_ATTR && GET_CODE (exp) == NOT
221918334Speter	   && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
222018334Speter	   && XSTR (*pterm, 0) == XSTR (XEXP (exp, 0), 0))
222118334Speter    *pterm = false_rtx;
222218334Speter
222318334Speter  else if (GET_CODE (exp) == EQ_ATTR && GET_CODE (*pterm) == NOT
222418334Speter	   && GET_CODE (XEXP (*pterm, 0)) == EQ_ATTR
222518334Speter	   && XSTR (exp, 0) == XSTR (XEXP (*pterm, 0), 0))
222618334Speter    return false_rtx;
222718334Speter
222818334Speter  return exp;
222918334Speter}
2230132718Skan
223190075Sobrien/* Compute approximate cost of the expression.  Used to decide whether
223290075Sobrien   expression is cheap enough for inline.  */
223390075Sobrienstatic int
2234132718Skanattr_rtx_cost (rtx x)
223590075Sobrien{
223690075Sobrien  int cost = 0;
223790075Sobrien  enum rtx_code code;
223890075Sobrien  if (!x)
223990075Sobrien    return 0;
224090075Sobrien  code = GET_CODE (x);
224190075Sobrien  switch (code)
224290075Sobrien    {
224390075Sobrien    case MATCH_OPERAND:
224490075Sobrien      if (XSTR (x, 1)[0])
224590075Sobrien	return 10;
224690075Sobrien      else
224790075Sobrien	return 0;
2248132718Skan
2249132718Skan    case EQ_ATTR_ALT:
2250132718Skan      return 0;
2251132718Skan
225290075Sobrien    case EQ_ATTR:
225390075Sobrien      /* Alternatives don't result into function call.  */
2254132718Skan      if (!strcmp_check (XSTR (x, 0), alternative_name))
225590075Sobrien	return 0;
225690075Sobrien      else
225790075Sobrien	return 5;
225890075Sobrien    default:
225990075Sobrien      {
226090075Sobrien	int i, j;
226190075Sobrien	const char *fmt = GET_RTX_FORMAT (code);
226290075Sobrien	for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
226390075Sobrien	  {
226490075Sobrien	    switch (fmt[i])
226590075Sobrien	      {
226690075Sobrien	      case 'V':
226790075Sobrien	      case 'E':
226890075Sobrien		for (j = 0; j < XVECLEN (x, i); j++)
226990075Sobrien		  cost += attr_rtx_cost (XVECEXP (x, i, j));
227090075Sobrien		break;
227190075Sobrien	      case 'e':
227290075Sobrien		cost += attr_rtx_cost (XEXP (x, i));
227390075Sobrien		break;
227490075Sobrien	      }
227590075Sobrien	  }
227690075Sobrien      }
227790075Sobrien      break;
227890075Sobrien    }
227990075Sobrien  return cost;
228090075Sobrien}
228190075Sobrien
228290075Sobrien/* Simplify test expression and use temporary obstack in order to avoid
2283132718Skan   memory bloat.  Use ATTR_IND_SIMPLIFIED to avoid unnecessary simplifications
2284132718Skan   and avoid unnecessary copying if possible.  */
228590075Sobrien
228690075Sobrienstatic rtx
2287132718Skansimplify_test_exp_in_temp (rtx exp, int insn_code, int insn_index)
228890075Sobrien{
228990075Sobrien  rtx x;
229090075Sobrien  struct obstack *old;
2291117395Skan  if (ATTR_IND_SIMPLIFIED_P (exp))
229290075Sobrien    return exp;
229390075Sobrien  old = rtl_obstack;
229490075Sobrien  rtl_obstack = temp_obstack;
229590075Sobrien  x = simplify_test_exp (exp, insn_code, insn_index);
229690075Sobrien  rtl_obstack = old;
229790075Sobrien  if (x == exp || rtl_obstack == temp_obstack)
229890075Sobrien    return x;
229990075Sobrien  return attr_copy_rtx (x);
230090075Sobrien}
230190075Sobrien
2302132718Skan/* Returns true if S1 is a subset of S2.  */
2303132718Skan
2304132718Skanstatic bool
2305132718Skanattr_alt_subset_p (rtx s1, rtx s2)
2306132718Skan{
2307132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2308132718Skan    {
2309132718Skan    case (0 << 1) | 0:
2310132718Skan      return !(XINT (s1, 0) &~ XINT (s2, 0));
2311132718Skan
2312132718Skan    case (0 << 1) | 1:
2313132718Skan      return !(XINT (s1, 0) & XINT (s2, 0));
2314132718Skan
2315132718Skan    case (1 << 1) | 0:
2316132718Skan      return false;
2317132718Skan
2318132718Skan    case (1 << 1) | 1:
2319132718Skan      return !(XINT (s2, 0) &~ XINT (s1, 0));
2320132718Skan
2321132718Skan    default:
2322169689Skan      gcc_unreachable ();
2323132718Skan    }
2324132718Skan}
2325132718Skan
2326132718Skan/* Returns true if S1 is a subset of complement of S2.  */
2327132718Skan
2328169689Skanstatic bool
2329169689Skanattr_alt_subset_of_compl_p (rtx s1, rtx s2)
2330132718Skan{
2331132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2332132718Skan    {
2333132718Skan    case (0 << 1) | 0:
2334132718Skan      return !(XINT (s1, 0) & XINT (s2, 0));
2335132718Skan
2336132718Skan    case (0 << 1) | 1:
2337132718Skan      return !(XINT (s1, 0) & ~XINT (s2, 0));
2338132718Skan
2339132718Skan    case (1 << 1) | 0:
2340132718Skan      return !(XINT (s2, 0) &~ XINT (s1, 0));
2341132718Skan
2342132718Skan    case (1 << 1) | 1:
2343132718Skan      return false;
2344132718Skan
2345132718Skan    default:
2346169689Skan      gcc_unreachable ();
2347132718Skan    }
2348132718Skan}
2349132718Skan
2350132718Skan/* Return EQ_ATTR_ALT expression representing intersection of S1 and S2.  */
2351132718Skan
2352132718Skanstatic rtx
2353132718Skanattr_alt_intersection (rtx s1, rtx s2)
2354132718Skan{
2355132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2356132718Skan
2357132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2358132718Skan    {
2359132718Skan    case (0 << 1) | 0:
2360132718Skan      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
2361132718Skan      break;
2362132718Skan    case (0 << 1) | 1:
2363132718Skan      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
2364132718Skan      break;
2365132718Skan    case (1 << 1) | 0:
2366132718Skan      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
2367132718Skan      break;
2368132718Skan    case (1 << 1) | 1:
2369132718Skan      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
2370132718Skan      break;
2371132718Skan    default:
2372169689Skan      gcc_unreachable ();
2373132718Skan    }
2374132718Skan  XINT (result, 1) = XINT (s1, 1) & XINT (s2, 1);
2375132718Skan
2376132718Skan  return result;
2377132718Skan}
2378132718Skan
2379132718Skan/* Return EQ_ATTR_ALT expression representing union of S1 and S2.  */
2380132718Skan
2381132718Skanstatic rtx
2382132718Skanattr_alt_union (rtx s1, rtx s2)
2383132718Skan{
2384132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2385132718Skan
2386132718Skan  switch ((XINT (s1, 1) << 1) | XINT (s2, 1))
2387132718Skan    {
2388132718Skan    case (0 << 1) | 0:
2389132718Skan      XINT (result, 0) = XINT (s1, 0) | XINT (s2, 0);
2390132718Skan      break;
2391132718Skan    case (0 << 1) | 1:
2392132718Skan      XINT (result, 0) = XINT (s2, 0) & ~XINT (s1, 0);
2393132718Skan      break;
2394132718Skan    case (1 << 1) | 0:
2395132718Skan      XINT (result, 0) = XINT (s1, 0) & ~XINT (s2, 0);
2396132718Skan      break;
2397132718Skan    case (1 << 1) | 1:
2398132718Skan      XINT (result, 0) = XINT (s1, 0) & XINT (s2, 0);
2399132718Skan      break;
2400132718Skan    default:
2401169689Skan      gcc_unreachable ();
2402132718Skan    }
2403132718Skan
2404132718Skan  XINT (result, 1) = XINT (s1, 1) | XINT (s2, 1);
2405132718Skan  return result;
2406132718Skan}
2407132718Skan
2408132718Skan/* Return EQ_ATTR_ALT expression representing complement of S.  */
2409132718Skan
2410132718Skanstatic rtx
2411132718Skanattr_alt_complement (rtx s)
2412132718Skan{
2413132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2414132718Skan
2415132718Skan  XINT (result, 0) = XINT (s, 0);
2416132718Skan  XINT (result, 1) = 1 - XINT (s, 1);
2417132718Skan
2418132718Skan  return result;
2419132718Skan}
2420132718Skan
2421132718Skan/* Return EQ_ATTR_ALT expression representing set containing elements set
2422132718Skan   in E.  */
2423132718Skan
2424132718Skanstatic rtx
2425132718Skanmk_attr_alt (int e)
2426132718Skan{
2427132718Skan  rtx result = rtx_alloc (EQ_ATTR_ALT);
2428132718Skan
2429132718Skan  XINT (result, 0) = e;
2430132718Skan  XINT (result, 1) = 0;
2431132718Skan
2432132718Skan  return result;
2433132718Skan}
2434132718Skan
243518334Speter/* Given an expression, see if it can be simplified for a particular insn
243618334Speter   code based on the values of other attributes being tested.  This can
243718334Speter   eliminate nested get_attr_... calls.
243818334Speter
243990075Sobrien   Note that if an endless recursion is specified in the patterns, the
244018334Speter   optimization will loop.  However, it will do so in precisely the cases where
244118334Speter   an infinite recursion loop could occur during compilation.  It's better that
244218334Speter   it occurs here!  */
244318334Speter
244418334Speterstatic rtx
2445132718Skansimplify_test_exp (rtx exp, int insn_code, int insn_index)
244618334Speter{
244718334Speter  rtx left, right;
244818334Speter  struct attr_desc *attr;
244918334Speter  struct attr_value *av;
245018334Speter  struct insn_ent *ie;
245118334Speter  int i;
245218334Speter  rtx newexp = exp;
2453132718Skan  bool left_alt, right_alt;
245418334Speter
245518334Speter  /* Don't re-simplify something we already simplified.  */
2456117395Skan  if (ATTR_IND_SIMPLIFIED_P (exp) || ATTR_CURR_SIMPLIFIED_P (exp))
245718334Speter    return exp;
245818334Speter
245918334Speter  switch (GET_CODE (exp))
246018334Speter    {
246118334Speter    case AND:
246218334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
246318334Speter      if (left == false_rtx)
246490075Sobrien	return false_rtx;
246518334Speter      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
2466169689Skan      if (right == false_rtx)
246790075Sobrien	return false_rtx;
246818334Speter
2469132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT
2470132718Skan	  && GET_CODE (right) == EQ_ATTR_ALT)
2471132718Skan	{
2472132718Skan	  exp = attr_alt_intersection (left, right);
2473132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2474132718Skan	}
2475132718Skan
247618334Speter      /* If either side is an IOR and we have (eq_attr "alternative" ..")
247718334Speter	 present on both sides, apply the distributive law since this will
247818334Speter	 yield simplifications.  */
247918334Speter      if ((GET_CODE (left) == IOR || GET_CODE (right) == IOR)
248018334Speter	  && compute_alternative_mask (left, IOR)
248118334Speter	  && compute_alternative_mask (right, IOR))
248218334Speter	{
248318334Speter	  if (GET_CODE (left) == IOR)
248418334Speter	    {
248518334Speter	      rtx tem = left;
248618334Speter	      left = right;
248718334Speter	      right = tem;
248818334Speter	    }
248918334Speter
249018334Speter	  newexp = attr_rtx (IOR,
249118334Speter			     attr_rtx (AND, left, XEXP (right, 0)),
249218334Speter			     attr_rtx (AND, left, XEXP (right, 1)));
249318334Speter
249418334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
249518334Speter	}
249618334Speter
249718334Speter      /* Try with the term on both sides.  */
249818334Speter      right = simplify_and_tree (right, &left, insn_code, insn_index);
249918334Speter      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
250018334Speter	left = simplify_and_tree (left, &right, insn_code, insn_index);
250118334Speter
250218334Speter      if (left == false_rtx || right == false_rtx)
250390075Sobrien	return false_rtx;
250418334Speter      else if (left == true_rtx)
250518334Speter	{
250618334Speter	  return right;
250718334Speter	}
250818334Speter      else if (right == true_rtx)
250918334Speter	{
251018334Speter	  return left;
251118334Speter	}
251218334Speter      /* See if all or all but one of the insn's alternatives are specified
251318334Speter	 in this tree.  Optimize if so.  */
251418334Speter
2515132718Skan      if (GET_CODE (left) == NOT)
2516132718Skan	left_alt = (GET_CODE (XEXP (left, 0)) == EQ_ATTR
2517132718Skan		    && XSTR (XEXP (left, 0), 0) == alternative_name);
2518132718Skan      else
2519132718Skan	left_alt = (GET_CODE (left) == EQ_ATTR_ALT
2520132718Skan		    && XINT (left, 1));
2521132718Skan
2522132718Skan      if (GET_CODE (right) == NOT)
2523132718Skan	right_alt = (GET_CODE (XEXP (right, 0)) == EQ_ATTR
2524132718Skan		     && XSTR (XEXP (right, 0), 0) == alternative_name);
2525132718Skan      else
2526132718Skan	right_alt = (GET_CODE (right) == EQ_ATTR_ALT
2527132718Skan		     && XINT (right, 1));
2528132718Skan
2529132718Skan      if (insn_code >= 0
2530132718Skan	  && (GET_CODE (left) == AND
2531132718Skan	      || left_alt
2532132718Skan	      || GET_CODE (right) == AND
2533132718Skan	      || right_alt))
253418334Speter	{
253518334Speter	  i = compute_alternative_mask (exp, AND);
253618334Speter	  if (i & ~insn_alternatives[insn_code])
253790075Sobrien	    fatal ("invalid alternative specified for pattern number %d",
253818334Speter		   insn_index);
253918334Speter
254050397Sobrien	  /* If all alternatives are excluded, this is false.  */
254118334Speter	  i ^= insn_alternatives[insn_code];
254218334Speter	  if (i == 0)
254318334Speter	    return false_rtx;
254418334Speter	  else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
254518334Speter	    {
254618334Speter	      /* If just one excluded, AND a comparison with that one to the
254718334Speter		 front of the tree.  The others will be eliminated by
254818334Speter		 optimization.  We do not want to do this if the insn has one
254918334Speter		 alternative and we have tested none of them!  */
255018334Speter	      left = make_alternative_compare (i);
255118334Speter	      right = simplify_and_tree (exp, &left, insn_code, insn_index);
255218334Speter	      newexp = attr_rtx (AND, left, right);
255318334Speter
255418334Speter	      return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
255518334Speter	    }
255618334Speter	}
255718334Speter
255818334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
255918334Speter	{
256018334Speter	  newexp = attr_rtx (AND, left, right);
256118334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
256218334Speter	}
256318334Speter      break;
256418334Speter
256518334Speter    case IOR:
256618334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
256718334Speter      if (left == true_rtx)
256890075Sobrien	return true_rtx;
256918334Speter      right = SIMPLIFY_TEST_EXP (XEXP (exp, 1), insn_code, insn_index);
257018334Speter      if (right == true_rtx)
257190075Sobrien	return true_rtx;
257218334Speter
2573132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT
2574132718Skan	  && GET_CODE (right) == EQ_ATTR_ALT)
2575132718Skan	{
2576132718Skan	  exp = attr_alt_union (left, right);
2577132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2578132718Skan	}
2579132718Skan
258018334Speter      right = simplify_or_tree (right, &left, insn_code, insn_index);
258118334Speter      if (left == XEXP (exp, 0) && right == XEXP (exp, 1))
258218334Speter	left = simplify_or_tree (left, &right, insn_code, insn_index);
258318334Speter
258418334Speter      if (right == true_rtx || left == true_rtx)
258590075Sobrien	return true_rtx;
258618334Speter      else if (left == false_rtx)
258718334Speter	{
258818334Speter	  return right;
258918334Speter	}
259018334Speter      else if (right == false_rtx)
259118334Speter	{
259218334Speter	  return left;
259318334Speter	}
259418334Speter
259518334Speter      /* Test for simple cases where the distributive law is useful.  I.e.,
259618334Speter	    convert (ior (and (x) (y))
259718334Speter			 (and (x) (z)))
259818334Speter	    to      (and (x)
259918334Speter			 (ior (y) (z)))
260018334Speter       */
260118334Speter
260218334Speter      else if (GET_CODE (left) == AND && GET_CODE (right) == AND
260390075Sobrien	       && attr_equal_p (XEXP (left, 0), XEXP (right, 0)))
260418334Speter	{
260518334Speter	  newexp = attr_rtx (IOR, XEXP (left, 1), XEXP (right, 1));
260618334Speter
260718334Speter	  left = XEXP (left, 0);
260818334Speter	  right = newexp;
260918334Speter	  newexp = attr_rtx (AND, left, right);
261018334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
261118334Speter	}
261218334Speter
261318334Speter      /* See if all or all but one of the insn's alternatives are specified
261418334Speter	 in this tree.  Optimize if so.  */
261518334Speter
261618334Speter      else if (insn_code >= 0
261790075Sobrien	       && (GET_CODE (left) == IOR
2618132718Skan		   || (GET_CODE (left) == EQ_ATTR_ALT
2619132718Skan		       && !XINT (left, 1))
262090075Sobrien		   || (GET_CODE (left) == EQ_ATTR
262190075Sobrien		       && XSTR (left, 0) == alternative_name)
262290075Sobrien		   || GET_CODE (right) == IOR
2623132718Skan		   || (GET_CODE (right) == EQ_ATTR_ALT
2624132718Skan		       && !XINT (right, 1))
262590075Sobrien		   || (GET_CODE (right) == EQ_ATTR
262690075Sobrien		       && XSTR (right, 0) == alternative_name)))
262718334Speter	{
262818334Speter	  i = compute_alternative_mask (exp, IOR);
262918334Speter	  if (i & ~insn_alternatives[insn_code])
263090075Sobrien	    fatal ("invalid alternative specified for pattern number %d",
263118334Speter		   insn_index);
263218334Speter
263350397Sobrien	  /* If all alternatives are included, this is true.  */
263418334Speter	  i ^= insn_alternatives[insn_code];
263518334Speter	  if (i == 0)
263618334Speter	    return true_rtx;
263718334Speter	  else if ((i & (i - 1)) == 0 && insn_alternatives[insn_code] > 1)
263818334Speter	    {
263918334Speter	      /* If just one excluded, IOR a comparison with that one to the
264018334Speter		 front of the tree.  The others will be eliminated by
264118334Speter		 optimization.  We do not want to do this if the insn has one
264218334Speter		 alternative and we have tested none of them!  */
264318334Speter	      left = make_alternative_compare (i);
264418334Speter	      right = simplify_and_tree (exp, &left, insn_code, insn_index);
264518334Speter	      newexp = attr_rtx (IOR, attr_rtx (NOT, left), right);
264618334Speter
264718334Speter	      return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
264818334Speter	    }
264918334Speter	}
265018334Speter
265118334Speter      if (left != XEXP (exp, 0) || right != XEXP (exp, 1))
265218334Speter	{
265318334Speter	  newexp = attr_rtx (IOR, left, right);
265418334Speter	  return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
265518334Speter	}
265618334Speter      break;
265718334Speter
265818334Speter    case NOT:
265918334Speter      if (GET_CODE (XEXP (exp, 0)) == NOT)
266018334Speter	{
266118334Speter	  left = SIMPLIFY_TEST_EXP (XEXP (XEXP (exp, 0), 0),
266218334Speter				    insn_code, insn_index);
266318334Speter	  return left;
266418334Speter	}
266518334Speter
266618334Speter      left = SIMPLIFY_TEST_EXP (XEXP (exp, 0), insn_code, insn_index);
266718334Speter      if (GET_CODE (left) == NOT)
266818334Speter	return XEXP (left, 0);
266918334Speter
267018334Speter      if (left == false_rtx)
267190075Sobrien	return true_rtx;
2672132718Skan      if (left == true_rtx)
267390075Sobrien	return false_rtx;
267418334Speter
2675132718Skan      if (GET_CODE (left) == EQ_ATTR_ALT)
2676132718Skan	{
2677132718Skan	  exp = attr_alt_complement (left);
2678132718Skan	  return simplify_test_exp (exp, insn_code, insn_index);
2679132718Skan	}
2680132718Skan
268118334Speter      /* Try to apply De`Morgan's laws.  */
2682132718Skan      if (GET_CODE (left) == IOR)
268318334Speter	{
268418334Speter	  newexp = attr_rtx (AND,
268518334Speter			     attr_rtx (NOT, XEXP (left, 0)),
268618334Speter			     attr_rtx (NOT, XEXP (left, 1)));
268718334Speter
268818334Speter	  newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
268918334Speter	}
269018334Speter      else if (GET_CODE (left) == AND)
269118334Speter	{
269218334Speter	  newexp = attr_rtx (IOR,
269318334Speter			     attr_rtx (NOT, XEXP (left, 0)),
269418334Speter			     attr_rtx (NOT, XEXP (left, 1)));
269518334Speter
269618334Speter	  newexp = SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
269718334Speter	}
269818334Speter      else if (left != XEXP (exp, 0))
269918334Speter	{
270018334Speter	  newexp = attr_rtx (NOT, left);
270118334Speter	}
270218334Speter      break;
270318334Speter
2704132718Skan    case EQ_ATTR_ALT:
2705132718Skan      if (!XINT (exp, 0))
2706132718Skan	return XINT (exp, 1) ? true_rtx : false_rtx;
2707132718Skan      break;
2708132718Skan
270918334Speter    case EQ_ATTR:
2710132718Skan      if (XSTR (exp, 0) == alternative_name)
2711132718Skan	{
2712132718Skan	  newexp = mk_attr_alt (1 << atoi (XSTR (exp, 1)));
2713132718Skan	  break;
2714132718Skan	}
2715132718Skan
271618334Speter      /* Look at the value for this insn code in the specified attribute.
271718334Speter	 We normally can replace this comparison with the condition that
271890075Sobrien	 would give this insn the values being tested for.  */
2719169689Skan      if (insn_code >= 0
2720132718Skan	  && (attr = find_attr (&XSTR (exp, 0), 0)) != NULL)
272118334Speter	for (av = attr->first_value; av; av = av->next)
272218334Speter	  for (ie = av->first_insn; ie; ie = ie->next)
2723169689Skan	    if (ie->def->insn_code == insn_code)
272490075Sobrien	      {
272590075Sobrien		rtx x;
272690075Sobrien		x = evaluate_eq_attr (exp, av->value, insn_code, insn_index);
272790075Sobrien		x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
272890075Sobrien		if (attr_rtx_cost(x) < 20)
272990075Sobrien		  return x;
273090075Sobrien	      }
273150397Sobrien      break;
273290075Sobrien
273350397Sobrien    default:
273450397Sobrien      break;
273518334Speter    }
273618334Speter
273718334Speter  /* We have already simplified this expression.  Simplifying it again
273818334Speter     won't buy anything unless we weren't given a valid insn code
273918334Speter     to process (i.e., we are canonicalizing something.).  */
2740169689Skan  if (insn_code != -2
2741117395Skan      && ! ATTR_IND_SIMPLIFIED_P (newexp))
274218334Speter    return copy_rtx_unchanging (newexp);
274318334Speter
274418334Speter  return newexp;
274518334Speter}
2746132718Skan
274718334Speter/* Optimize the attribute lists by seeing if we can determine conditional
274818334Speter   values from the known values of other attributes.  This will save subroutine
274918334Speter   calls during the compilation.  */
275018334Speter
275118334Speterstatic void
2752132718Skanoptimize_attrs (void)
275318334Speter{
275418334Speter  struct attr_desc *attr;
275518334Speter  struct attr_value *av;
275618334Speter  struct insn_ent *ie;
275718334Speter  rtx newexp;
275818334Speter  int i;
275990075Sobrien  struct attr_value_list
276090075Sobrien  {
276190075Sobrien    struct attr_value *av;
276290075Sobrien    struct insn_ent *ie;
276390075Sobrien    struct attr_desc *attr;
276490075Sobrien    struct attr_value_list *next;
276590075Sobrien  };
276618334Speter  struct attr_value_list **insn_code_values;
276718334Speter  struct attr_value_list *ivbuf;
276818334Speter  struct attr_value_list *iv;
276918334Speter
277018334Speter  /* For each insn code, make a list of all the insn_ent's for it,
277118334Speter     for all values for all attributes.  */
277218334Speter
277318334Speter  if (num_insn_ents == 0)
277418334Speter    return;
277518334Speter
277618334Speter  /* Make 2 extra elements, for "code" values -2 and -1.  */
2777169689Skan  insn_code_values = XCNEWVEC (struct attr_value_list *, insn_code_number + 2);
277818334Speter
277918334Speter  /* Offset the table address so we can index by -2 or -1.  */
278018334Speter  insn_code_values += 2;
278118334Speter
2782169689Skan  iv = ivbuf = XNEWVEC (struct attr_value_list, num_insn_ents);
278318334Speter
278418334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
278518334Speter    for (attr = attrs[i]; attr; attr = attr->next)
278618334Speter      for (av = attr->first_value; av; av = av->next)
278718334Speter	for (ie = av->first_insn; ie; ie = ie->next)
278818334Speter	  {
278918334Speter	    iv->attr = attr;
279018334Speter	    iv->av = av;
279118334Speter	    iv->ie = ie;
2792169689Skan	    iv->next = insn_code_values[ie->def->insn_code];
2793169689Skan	    insn_code_values[ie->def->insn_code] = iv;
279418334Speter	    iv++;
279518334Speter	  }
279618334Speter
279718334Speter  /* Sanity check on num_insn_ents.  */
2798169689Skan  gcc_assert (iv == ivbuf + num_insn_ents);
279918334Speter
280018334Speter  /* Process one insn code at a time.  */
280118334Speter  for (i = -2; i < insn_code_number; i++)
280218334Speter    {
2803117395Skan      /* Clear the ATTR_CURR_SIMPLIFIED_P flag everywhere relevant.
280418334Speter	 We use it to mean "already simplified for this insn".  */
280518334Speter      for (iv = insn_code_values[i]; iv; iv = iv->next)
280618334Speter	clear_struct_flag (iv->av->value);
280718334Speter
280890075Sobrien      for (iv = insn_code_values[i]; iv; iv = iv->next)
280918334Speter	{
281090075Sobrien	  struct obstack *old = rtl_obstack;
281118334Speter
281290075Sobrien	  attr = iv->attr;
281390075Sobrien	  av = iv->av;
281490075Sobrien	  ie = iv->ie;
281590075Sobrien	  if (GET_CODE (av->value) != COND)
281690075Sobrien	    continue;
281718334Speter
281890075Sobrien	  rtl_obstack = temp_obstack;
281990075Sobrien	  newexp = av->value;
282090075Sobrien	  while (GET_CODE (newexp) == COND)
282190075Sobrien	    {
2822169689Skan	      rtx newexp2 = simplify_cond (newexp, ie->def->insn_code,
2823169689Skan					   ie->def->insn_index);
282490075Sobrien	      if (newexp2 == newexp)
282590075Sobrien		break;
282690075Sobrien	      newexp = newexp2;
282790075Sobrien	    }
282818334Speter
282990075Sobrien	  rtl_obstack = old;
283090075Sobrien	  if (newexp != av->value)
283190075Sobrien	    {
283290075Sobrien	      newexp = attr_copy_rtx (newexp);
283390075Sobrien	      remove_insn_ent (av, ie);
2834169689Skan	      av = get_attr_value (newexp, attr, ie->def->insn_code);
283590075Sobrien	      iv->av = av;
283690075Sobrien	      insert_insn_ent (av, ie);
283718334Speter	    }
283818334Speter	}
283918334Speter    }
284018334Speter
284118334Speter  free (ivbuf);
284290075Sobrien  free (insn_code_values - 2);
284318334Speter}
284418334Speter
2845117395Skan/* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions.  */
284618334Speter
284718334Speterstatic void
2848132718Skanclear_struct_flag (rtx x)
284918334Speter{
285090075Sobrien  int i;
285190075Sobrien  int j;
285290075Sobrien  enum rtx_code code;
285390075Sobrien  const char *fmt;
285418334Speter
2855117395Skan  ATTR_CURR_SIMPLIFIED_P (x) = 0;
2856117395Skan  if (ATTR_IND_SIMPLIFIED_P (x))
285718334Speter    return;
285818334Speter
285918334Speter  code = GET_CODE (x);
286018334Speter
286118334Speter  switch (code)
286218334Speter    {
286318334Speter    case REG:
286418334Speter    case CONST_INT:
286518334Speter    case CONST_DOUBLE:
286696263Sobrien    case CONST_VECTOR:
286718334Speter    case SYMBOL_REF:
286818334Speter    case CODE_LABEL:
286918334Speter    case PC:
287018334Speter    case CC0:
287118334Speter    case EQ_ATTR:
287218334Speter    case ATTR_FLAG:
287318334Speter      return;
287490075Sobrien
287550397Sobrien    default:
287650397Sobrien      break;
287718334Speter    }
287818334Speter
287918334Speter  /* Compare the elements.  If any pair of corresponding elements
288018334Speter     fail to match, return 0 for the whole things.  */
288118334Speter
288218334Speter  fmt = GET_RTX_FORMAT (code);
288318334Speter  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
288418334Speter    {
288518334Speter      switch (fmt[i])
288618334Speter	{
288718334Speter	case 'V':
288818334Speter	case 'E':
288918334Speter	  for (j = 0; j < XVECLEN (x, i); j++)
289018334Speter	    clear_struct_flag (XVECEXP (x, i, j));
289118334Speter	  break;
289218334Speter
289318334Speter	case 'e':
289418334Speter	  clear_struct_flag (XEXP (x, i));
289518334Speter	  break;
289618334Speter	}
289718334Speter    }
289818334Speter}
289918334Speter
290018334Speter/* Create table entries for DEFINE_ATTR.  */
290118334Speter
290218334Speterstatic void
2903132718Skangen_attr (rtx exp, int lineno)
290418334Speter{
290518334Speter  struct attr_desc *attr;
290618334Speter  struct attr_value *av;
290790075Sobrien  const char *name_ptr;
290818334Speter  char *p;
290918334Speter
291018334Speter  /* Make a new attribute structure.  Check for duplicate by looking at
291118334Speter     attr->default_val, since it is initialized by this routine.  */
2912132718Skan  attr = find_attr (&XSTR (exp, 0), 1);
291318334Speter  if (attr->default_val)
291490075Sobrien    {
291590075Sobrien      message_with_line (lineno, "duplicate definition for attribute %s",
291690075Sobrien			 attr->name);
291790075Sobrien      message_with_line (attr->lineno, "previous definition");
291890075Sobrien      have_error = 1;
291990075Sobrien      return;
292090075Sobrien    }
292190075Sobrien  attr->lineno = lineno;
292218334Speter
292318334Speter  if (*XSTR (exp, 1) == '\0')
292452284Sobrien    attr->is_numeric = 1;
292518334Speter  else
292618334Speter    {
292718334Speter      name_ptr = XSTR (exp, 1);
292818334Speter      while ((p = next_comma_elt (&name_ptr)) != NULL)
292918334Speter	{
2930132718Skan	  av = oballoc (sizeof (struct attr_value));
293118334Speter	  av->value = attr_rtx (CONST_STRING, p);
293218334Speter	  av->next = attr->first_value;
293318334Speter	  attr->first_value = av;
293418334Speter	  av->first_insn = NULL;
293518334Speter	  av->num_insns = 0;
293618334Speter	  av->has_asm_insn = 0;
293718334Speter	}
293818334Speter    }
293918334Speter
294018334Speter  if (GET_CODE (XEXP (exp, 2)) == CONST)
294118334Speter    {
294218334Speter      attr->is_const = 1;
294318334Speter      if (attr->is_numeric)
294490075Sobrien	{
294590075Sobrien	  message_with_line (lineno,
294690075Sobrien			     "constant attributes may not take numeric values");
294790075Sobrien	  have_error = 1;
294890075Sobrien	}
294990075Sobrien
295018334Speter      /* Get rid of the CONST node.  It is allowed only at top-level.  */
295118334Speter      XEXP (exp, 2) = XEXP (XEXP (exp, 2), 0);
295218334Speter    }
295318334Speter
2954132718Skan  if (! strcmp_check (attr->name, length_str) && ! attr->is_numeric)
295590075Sobrien    {
295690075Sobrien      message_with_line (lineno,
295790075Sobrien			 "`length' attribute must take numeric values");
295890075Sobrien      have_error = 1;
295990075Sobrien    }
296018334Speter
296150397Sobrien  /* Set up the default value.  */
296218334Speter  XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
296318334Speter  attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
296418334Speter}
2965132718Skan
296618334Speter/* Given a pattern for DEFINE_PEEPHOLE or DEFINE_INSN, return the number of
296718334Speter   alternatives in the constraints.  Assume all MATCH_OPERANDs have the same
296818334Speter   number of alternatives as this should be checked elsewhere.  */
296918334Speter
297018334Speterstatic int
2971132718Skancount_alternatives (rtx exp)
297218334Speter{
297318334Speter  int i, j, n;
297490075Sobrien  const char *fmt;
297590075Sobrien
297618334Speter  if (GET_CODE (exp) == MATCH_OPERAND)
297718334Speter    return n_comma_elts (XSTR (exp, 2));
297818334Speter
297918334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
298018334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
298118334Speter    switch (*fmt++)
298218334Speter      {
298318334Speter      case 'e':
298418334Speter      case 'u':
298518334Speter	n = count_alternatives (XEXP (exp, i));
298618334Speter	if (n)
298718334Speter	  return n;
298818334Speter	break;
298918334Speter
299018334Speter      case 'E':
299118334Speter      case 'V':
299218334Speter	if (XVEC (exp, i) != NULL)
299318334Speter	  for (j = 0; j < XVECLEN (exp, i); j++)
299418334Speter	    {
299518334Speter	      n = count_alternatives (XVECEXP (exp, i, j));
299618334Speter	      if (n)
299718334Speter		return n;
299818334Speter	    }
299918334Speter      }
300018334Speter
300118334Speter  return 0;
300218334Speter}
3003132718Skan
3004117395Skan/* Returns nonzero if the given expression contains an EQ_ATTR with the
300518334Speter   `alternative' attribute.  */
300618334Speter
300718334Speterstatic int
3008132718Skancompares_alternatives_p (rtx exp)
300918334Speter{
301018334Speter  int i, j;
301190075Sobrien  const char *fmt;
301218334Speter
301318334Speter  if (GET_CODE (exp) == EQ_ATTR && XSTR (exp, 0) == alternative_name)
301418334Speter    return 1;
301518334Speter
301618334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
301718334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
301818334Speter    switch (*fmt++)
301918334Speter      {
302018334Speter      case 'e':
302118334Speter      case 'u':
302218334Speter	if (compares_alternatives_p (XEXP (exp, i)))
302318334Speter	  return 1;
302418334Speter	break;
302518334Speter
302618334Speter      case 'E':
302718334Speter	for (j = 0; j < XVECLEN (exp, i); j++)
302818334Speter	  if (compares_alternatives_p (XVECEXP (exp, i, j)))
302918334Speter	    return 1;
303018334Speter	break;
303118334Speter      }
303218334Speter
303318334Speter  return 0;
303418334Speter}
3035132718Skan
3036117395Skan/* Returns nonzero is INNER is contained in EXP.  */
303718334Speter
303818334Speterstatic int
3039132718Skancontained_in_p (rtx inner, rtx exp)
304018334Speter{
304118334Speter  int i, j;
304290075Sobrien  const char *fmt;
304318334Speter
304418334Speter  if (rtx_equal_p (inner, exp))
304518334Speter    return 1;
304618334Speter
304718334Speter  for (i = 0, fmt = GET_RTX_FORMAT (GET_CODE (exp));
304818334Speter       i < GET_RTX_LENGTH (GET_CODE (exp)); i++)
304918334Speter    switch (*fmt++)
305018334Speter      {
305118334Speter      case 'e':
305218334Speter      case 'u':
305318334Speter	if (contained_in_p (inner, XEXP (exp, i)))
305418334Speter	  return 1;
305518334Speter	break;
305618334Speter
305718334Speter      case 'E':
305818334Speter	for (j = 0; j < XVECLEN (exp, i); j++)
305918334Speter	  if (contained_in_p (inner, XVECEXP (exp, i, j)))
306018334Speter	    return 1;
306118334Speter	break;
306218334Speter      }
306318334Speter
306418334Speter  return 0;
306518334Speter}
3066132718Skan
306718334Speter/* Process DEFINE_PEEPHOLE, DEFINE_INSN, and DEFINE_ASM_ATTRIBUTES.  */
306818334Speter
306918334Speterstatic void
3070132718Skangen_insn (rtx exp, int lineno)
307118334Speter{
307218334Speter  struct insn_def *id;
307318334Speter
3074132718Skan  id = oballoc (sizeof (struct insn_def));
307518334Speter  id->next = defs;
307618334Speter  defs = id;
307718334Speter  id->def = exp;
307890075Sobrien  id->lineno = lineno;
307918334Speter
308018334Speter  switch (GET_CODE (exp))
308118334Speter    {
308218334Speter    case DEFINE_INSN:
308390075Sobrien      id->insn_code = insn_code_number;
308490075Sobrien      id->insn_index = insn_index_number;
308518334Speter      id->num_alternatives = count_alternatives (exp);
308618334Speter      if (id->num_alternatives == 0)
308718334Speter	id->num_alternatives = 1;
308818334Speter      id->vec_idx = 4;
308918334Speter      break;
309018334Speter
309118334Speter    case DEFINE_PEEPHOLE:
309290075Sobrien      id->insn_code = insn_code_number;
309390075Sobrien      id->insn_index = insn_index_number;
309418334Speter      id->num_alternatives = count_alternatives (exp);
309518334Speter      if (id->num_alternatives == 0)
309618334Speter	id->num_alternatives = 1;
309718334Speter      id->vec_idx = 3;
309818334Speter      break;
309918334Speter
310018334Speter    case DEFINE_ASM_ATTRIBUTES:
310118334Speter      id->insn_code = -1;
310218334Speter      id->insn_index = -1;
310318334Speter      id->num_alternatives = 1;
310418334Speter      id->vec_idx = 0;
310518334Speter      got_define_asm_attributes = 1;
310618334Speter      break;
310790075Sobrien
310850397Sobrien    default:
3109169689Skan      gcc_unreachable ();
311018334Speter    }
311118334Speter}
3112132718Skan
311318334Speter/* Process a DEFINE_DELAY.  Validate the vector length, check if annul
311418334Speter   true or annul false is specified, and make a `struct delay_desc'.  */
311518334Speter
311618334Speterstatic void
3117132718Skangen_delay (rtx def, int lineno)
311818334Speter{
311918334Speter  struct delay_desc *delay;
312018334Speter  int i;
312118334Speter
312218334Speter  if (XVECLEN (def, 1) % 3 != 0)
312390075Sobrien    {
312490075Sobrien      message_with_line (lineno,
312590075Sobrien			 "number of elements in DEFINE_DELAY must be multiple of three");
312690075Sobrien      have_error = 1;
312790075Sobrien      return;
312890075Sobrien    }
312918334Speter
313018334Speter  for (i = 0; i < XVECLEN (def, 1); i += 3)
313118334Speter    {
313218334Speter      if (XVECEXP (def, 1, i + 1))
313318334Speter	have_annul_true = 1;
313418334Speter      if (XVECEXP (def, 1, i + 2))
313518334Speter	have_annul_false = 1;
313618334Speter    }
313790075Sobrien
3138132718Skan  delay = oballoc (sizeof (struct delay_desc));
313918334Speter  delay->def = def;
314018334Speter  delay->num = ++num_delays;
314118334Speter  delay->next = delays;
314290075Sobrien  delay->lineno = lineno;
314318334Speter  delays = delay;
314418334Speter}
3145132718Skan
314650397Sobrien/* Given a piece of RTX, print a C expression to test its truth value.
314790075Sobrien   We use AND and IOR both for logical and bit-wise operations, so
314818334Speter   interpret them as logical unless they are inside a comparison expression.
3149117395Skan   The first bit of FLAGS will be nonzero in that case.
315018334Speter
315150397Sobrien   Set the second bit of FLAGS to make references to attribute values use
315250397Sobrien   a cached local variable instead of calling a function.  */
315350397Sobrien
315418334Speterstatic void
3155132718Skanwrite_test_expr (rtx exp, int flags)
315618334Speter{
315718334Speter  int comparison_operator = 0;
315818334Speter  RTX_CODE code;
315918334Speter  struct attr_desc *attr;
316018334Speter
316118334Speter  /* In order not to worry about operator precedence, surround our part of
316218334Speter     the expression with parentheses.  */
316318334Speter
316418334Speter  printf ("(");
316518334Speter  code = GET_CODE (exp);
316618334Speter  switch (code)
316718334Speter    {
316818334Speter    /* Binary operators.  */
3169169689Skan    case GEU: case GTU:
3170169689Skan    case LEU: case LTU:
3171169689Skan      printf ("(unsigned) ");
3172169689Skan      /* Fall through.  */
3173169689Skan
317418334Speter    case EQ: case NE:
3175169689Skan    case GE: case GT:
3176169689Skan    case LE: case LT:
317718334Speter      comparison_operator = 1;
317818334Speter
317918334Speter    case PLUS:   case MINUS:  case MULT:     case DIV:      case MOD:
318018334Speter    case AND:    case IOR:    case XOR:
318118334Speter    case ASHIFT: case LSHIFTRT: case ASHIFTRT:
318250397Sobrien      write_test_expr (XEXP (exp, 0), flags | comparison_operator);
318318334Speter      switch (code)
318490075Sobrien	{
318518334Speter	case EQ:
318618334Speter	  printf (" == ");
318718334Speter	  break;
318818334Speter	case NE:
318918334Speter	  printf (" != ");
319018334Speter	  break;
319118334Speter	case GE:
319218334Speter	  printf (" >= ");
319318334Speter	  break;
319418334Speter	case GT:
319518334Speter	  printf (" > ");
319618334Speter	  break;
319718334Speter	case GEU:
319818334Speter	  printf (" >= (unsigned) ");
319918334Speter	  break;
320018334Speter	case GTU:
320118334Speter	  printf (" > (unsigned) ");
320218334Speter	  break;
320318334Speter	case LE:
320418334Speter	  printf (" <= ");
320518334Speter	  break;
320618334Speter	case LT:
320718334Speter	  printf (" < ");
320818334Speter	  break;
320918334Speter	case LEU:
321018334Speter	  printf (" <= (unsigned) ");
321118334Speter	  break;
321218334Speter	case LTU:
321318334Speter	  printf (" < (unsigned) ");
321418334Speter	  break;
321518334Speter	case PLUS:
321618334Speter	  printf (" + ");
321718334Speter	  break;
321818334Speter	case MINUS:
321918334Speter	  printf (" - ");
322018334Speter	  break;
322118334Speter	case MULT:
322218334Speter	  printf (" * ");
322318334Speter	  break;
322418334Speter	case DIV:
322518334Speter	  printf (" / ");
322618334Speter	  break;
322718334Speter	case MOD:
322818334Speter	  printf (" %% ");
322918334Speter	  break;
323018334Speter	case AND:
323150397Sobrien	  if (flags & 1)
323218334Speter	    printf (" & ");
323318334Speter	  else
323418334Speter	    printf (" && ");
323518334Speter	  break;
323618334Speter	case IOR:
323750397Sobrien	  if (flags & 1)
323818334Speter	    printf (" | ");
323918334Speter	  else
324018334Speter	    printf (" || ");
324118334Speter	  break;
324218334Speter	case XOR:
324318334Speter	  printf (" ^ ");
324418334Speter	  break;
324518334Speter	case ASHIFT:
324618334Speter	  printf (" << ");
324718334Speter	  break;
324818334Speter	case LSHIFTRT:
324918334Speter	case ASHIFTRT:
325018334Speter	  printf (" >> ");
325118334Speter	  break;
325250397Sobrien	default:
3253169689Skan	  gcc_unreachable ();
325490075Sobrien	}
325518334Speter
325650397Sobrien      write_test_expr (XEXP (exp, 1), flags | comparison_operator);
325718334Speter      break;
325818334Speter
325918334Speter    case NOT:
326018334Speter      /* Special-case (not (eq_attrq "alternative" "x")) */
326150397Sobrien      if (! (flags & 1) && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
326218334Speter	  && XSTR (XEXP (exp, 0), 0) == alternative_name)
326318334Speter	{
326418334Speter	  printf ("which_alternative != %s", XSTR (XEXP (exp, 0), 1));
326518334Speter	  break;
326618334Speter	}
326718334Speter
326818334Speter      /* Otherwise, fall through to normal unary operator.  */
326918334Speter
327090075Sobrien    /* Unary operators.  */
327118334Speter    case ABS:  case NEG:
327218334Speter      switch (code)
327318334Speter	{
327418334Speter	case NOT:
327550397Sobrien	  if (flags & 1)
327618334Speter	    printf ("~ ");
327718334Speter	  else
327818334Speter	    printf ("! ");
327918334Speter	  break;
328018334Speter	case ABS:
328118334Speter	  printf ("abs ");
328218334Speter	  break;
328318334Speter	case NEG:
328418334Speter	  printf ("-");
328518334Speter	  break;
328650397Sobrien	default:
3287169689Skan	  gcc_unreachable ();
328818334Speter	}
328918334Speter
329050397Sobrien      write_test_expr (XEXP (exp, 0), flags);
329118334Speter      break;
329218334Speter
3293132718Skan    case EQ_ATTR_ALT:
3294132718Skan	{
3295132718Skan	  int set = XINT (exp, 0), bit = 0;
3296132718Skan
3297132718Skan	  if (flags & 1)
3298132718Skan	    fatal ("EQ_ATTR_ALT not valid inside comparison");
3299132718Skan
3300132718Skan	  if (!set)
3301132718Skan	    fatal ("Empty EQ_ATTR_ALT should be optimized out");
3302132718Skan
3303132718Skan	  if (!(set & (set - 1)))
3304132718Skan	    {
3305132718Skan	      if (!(set & 0xffff))
3306132718Skan		{
3307132718Skan		  bit += 16;
3308132718Skan		  set >>= 16;
3309132718Skan		}
3310132718Skan	      if (!(set & 0xff))
3311132718Skan		{
3312132718Skan		  bit += 8;
3313132718Skan		  set >>= 8;
3314132718Skan		}
3315132718Skan	      if (!(set & 0xf))
3316132718Skan		{
3317132718Skan		  bit += 4;
3318132718Skan		  set >>= 4;
3319132718Skan		}
3320132718Skan	      if (!(set & 0x3))
3321132718Skan		{
3322132718Skan		  bit += 2;
3323132718Skan		  set >>= 2;
3324132718Skan		}
3325132718Skan	      if (!(set & 1))
3326132718Skan		bit++;
3327132718Skan
3328132718Skan	      printf ("which_alternative %s= %d",
3329132718Skan		      XINT (exp, 1) ? "!" : "=", bit);
3330132718Skan	    }
3331132718Skan	  else
3332132718Skan	    {
3333132718Skan	      printf ("%s((1 << which_alternative) & 0x%x)",
3334132718Skan		      XINT (exp, 1) ? "!" : "", set);
3335132718Skan	    }
3336132718Skan	}
3337132718Skan      break;
3338132718Skan
333918334Speter    /* Comparison test of an attribute with a value.  Most of these will
334018334Speter       have been removed by optimization.   Handle "alternative"
334118334Speter       specially and give error if EQ_ATTR present inside a comparison.  */
334218334Speter    case EQ_ATTR:
334350397Sobrien      if (flags & 1)
334418334Speter	fatal ("EQ_ATTR not valid inside comparison");
334518334Speter
334618334Speter      if (XSTR (exp, 0) == alternative_name)
334718334Speter	{
334818334Speter	  printf ("which_alternative == %s", XSTR (exp, 1));
334918334Speter	  break;
335018334Speter	}
335118334Speter
3352132718Skan      attr = find_attr (&XSTR (exp, 0), 0);
3353169689Skan      gcc_assert (attr);
335418334Speter
335518334Speter      /* Now is the time to expand the value of a constant attribute.  */
335618334Speter      if (attr->is_const)
335718334Speter	{
335818334Speter	  write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
335918334Speter					     -2, -2),
336050397Sobrien			   flags);
336118334Speter	}
336218334Speter      else
336318334Speter	{
336450397Sobrien	  if (flags & 2)
336550397Sobrien	    printf ("attr_%s", attr->name);
336650397Sobrien	  else
336750397Sobrien	    printf ("get_attr_%s (insn)", attr->name);
336850397Sobrien	  printf (" == ");
336950397Sobrien	  write_attr_valueq (attr, XSTR (exp, 1));
337018334Speter	}
337118334Speter      break;
337218334Speter
337318334Speter    /* Comparison test of flags for define_delays.  */
337418334Speter    case ATTR_FLAG:
337550397Sobrien      if (flags & 1)
337618334Speter	fatal ("ATTR_FLAG not valid inside comparison");
337718334Speter      printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
337818334Speter      break;
337918334Speter
338018334Speter    /* See if an operand matches a predicate.  */
338118334Speter    case MATCH_OPERAND:
338218334Speter      /* If only a mode is given, just ensure the mode matches the operand.
338318334Speter	 If neither a mode nor predicate is given, error.  */
338490075Sobrien      if (XSTR (exp, 1) == NULL || *XSTR (exp, 1) == '\0')
338518334Speter	{
338618334Speter	  if (GET_MODE (exp) == VOIDmode)
338790075Sobrien	    fatal ("null MATCH_OPERAND specified as test");
338818334Speter	  else
338918334Speter	    printf ("GET_MODE (operands[%d]) == %smode",
339018334Speter		    XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
339118334Speter	}
339218334Speter      else
339318334Speter	printf ("%s (operands[%d], %smode)",
339418334Speter		XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
339518334Speter      break;
339618334Speter
339750397Sobrien    /* Constant integer.  */
339818334Speter    case CONST_INT:
339950397Sobrien      printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
340018334Speter      break;
340118334Speter
340250397Sobrien    /* A random C expression.  */
340318334Speter    case SYMBOL_REF:
3404169689Skan      print_c_condition (XSTR (exp, 0));
340518334Speter      break;
340618334Speter
340718334Speter    /* The address of the branch target.  */
340818334Speter    case MATCH_DUP:
340990075Sobrien      printf ("INSN_ADDRESSES_SET_P () ? INSN_ADDRESSES (INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])) : 0",
341050397Sobrien	      XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
341118334Speter      break;
341218334Speter
341318334Speter    case PC:
341450397Sobrien      /* The address of the current insn.  We implement this actually as the
341550397Sobrien	 address of the current insn for backward branches, but the last
341650397Sobrien	 address of the next insn for forward branches, and both with
341750397Sobrien	 adjustments that account for the worst-case possible stretching of
341850397Sobrien	 intervening alignments between this insn and its destination.  */
341990075Sobrien      printf ("insn_current_reference_address (insn)");
342018334Speter      break;
342118334Speter
342250397Sobrien    case CONST_STRING:
342350397Sobrien      printf ("%s", XSTR (exp, 0));
342450397Sobrien      break;
342550397Sobrien
342650397Sobrien    case IF_THEN_ELSE:
342750397Sobrien      write_test_expr (XEXP (exp, 0), flags & 2);
342850397Sobrien      printf (" ? ");
342950397Sobrien      write_test_expr (XEXP (exp, 1), flags | 1);
343050397Sobrien      printf (" : ");
343150397Sobrien      write_test_expr (XEXP (exp, 2), flags | 1);
343250397Sobrien      break;
343350397Sobrien
343418334Speter    default:
343518334Speter      fatal ("bad RTX code `%s' in attribute calculation\n",
343618334Speter	     GET_RTX_NAME (code));
343718334Speter    }
343818334Speter
343918334Speter  printf (")");
344018334Speter}
3441132718Skan
344218334Speter/* Given an attribute value, return the maximum CONST_STRING argument
344352284Sobrien   encountered.  Set *UNKNOWNP and return INT_MAX if the value is unknown.  */
344418334Speter
344518334Speterstatic int
3446132718Skanmax_attr_value (rtx exp, int *unknownp)
344718334Speter{
344852284Sobrien  int current_max;
344952284Sobrien  int i, n;
345018334Speter
345152284Sobrien  switch (GET_CODE (exp))
345252284Sobrien    {
345352284Sobrien    case CONST_STRING:
345452284Sobrien      current_max = atoi (XSTR (exp, 0));
345552284Sobrien      break;
345618334Speter
345752284Sobrien    case COND:
345852284Sobrien      current_max = max_attr_value (XEXP (exp, 1), unknownp);
345918334Speter      for (i = 0; i < XVECLEN (exp, 0); i += 2)
346018334Speter	{
346152284Sobrien	  n = max_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
346218334Speter	  if (n > current_max)
346318334Speter	    current_max = n;
346418334Speter	}
346552284Sobrien      break;
346618334Speter
346752284Sobrien    case IF_THEN_ELSE:
346852284Sobrien      current_max = max_attr_value (XEXP (exp, 1), unknownp);
346952284Sobrien      n = max_attr_value (XEXP (exp, 2), unknownp);
347018334Speter      if (n > current_max)
347118334Speter	current_max = n;
347252284Sobrien      break;
347318334Speter
347452284Sobrien    default:
347552284Sobrien      *unknownp = 1;
347652284Sobrien      current_max = INT_MAX;
347752284Sobrien      break;
347818334Speter    }
347918334Speter
348018334Speter  return current_max;
348118334Speter}
348250397Sobrien
3483169689Skan/* Given an attribute value, return the minimum CONST_STRING argument
3484169689Skan   encountered.  Set *UNKNOWNP and return 0 if the value is unknown.  */
3485169689Skan
3486169689Skanstatic int
3487169689Skanmin_attr_value (rtx exp, int *unknownp)
3488169689Skan{
3489169689Skan  int current_min;
3490169689Skan  int i, n;
3491169689Skan
3492169689Skan  switch (GET_CODE (exp))
3493169689Skan    {
3494169689Skan    case CONST_STRING:
3495169689Skan      current_min = atoi (XSTR (exp, 0));
3496169689Skan      break;
3497169689Skan
3498169689Skan    case COND:
3499169689Skan      current_min = min_attr_value (XEXP (exp, 1), unknownp);
3500169689Skan      for (i = 0; i < XVECLEN (exp, 0); i += 2)
3501169689Skan	{
3502169689Skan	  n = min_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
3503169689Skan	  if (n < current_min)
3504169689Skan	    current_min = n;
3505169689Skan	}
3506169689Skan      break;
3507169689Skan
3508169689Skan    case IF_THEN_ELSE:
3509169689Skan      current_min = min_attr_value (XEXP (exp, 1), unknownp);
3510169689Skan      n = min_attr_value (XEXP (exp, 2), unknownp);
3511169689Skan      if (n < current_min)
3512169689Skan	current_min = n;
3513169689Skan      break;
3514169689Skan
3515169689Skan    default:
3516169689Skan      *unknownp = 1;
3517169689Skan      current_min = INT_MAX;
3518169689Skan      break;
3519169689Skan    }
3520169689Skan
3521169689Skan  return current_min;
3522169689Skan}
3523169689Skan
352450397Sobrien/* Given an attribute value, return the result of ORing together all
352552284Sobrien   CONST_STRING arguments encountered.  Set *UNKNOWNP and return -1
352652284Sobrien   if the numeric value is not known.  */
352750397Sobrien
352850397Sobrienstatic int
3529132718Skanor_attr_value (rtx exp, int *unknownp)
353050397Sobrien{
353152284Sobrien  int current_or;
353250397Sobrien  int i;
353350397Sobrien
353452284Sobrien  switch (GET_CODE (exp))
353552284Sobrien    {
353652284Sobrien    case CONST_STRING:
353752284Sobrien      current_or = atoi (XSTR (exp, 0));
353852284Sobrien      break;
353950397Sobrien
354052284Sobrien    case COND:
354152284Sobrien      current_or = or_attr_value (XEXP (exp, 1), unknownp);
354250397Sobrien      for (i = 0; i < XVECLEN (exp, 0); i += 2)
354352284Sobrien	current_or |= or_attr_value (XVECEXP (exp, 0, i + 1), unknownp);
354452284Sobrien      break;
354550397Sobrien
354652284Sobrien    case IF_THEN_ELSE:
354752284Sobrien      current_or = or_attr_value (XEXP (exp, 1), unknownp);
354852284Sobrien      current_or |= or_attr_value (XEXP (exp, 2), unknownp);
354952284Sobrien      break;
355050397Sobrien
355152284Sobrien    default:
355252284Sobrien      *unknownp = 1;
355352284Sobrien      current_or = -1;
355452284Sobrien      break;
355550397Sobrien    }
355650397Sobrien
355750397Sobrien  return current_or;
355850397Sobrien}
3559132718Skan
356018334Speter/* Scan an attribute value, possibly a conditional, and record what actions
356118334Speter   will be required to do any conditional tests in it.
356218334Speter
356318334Speter   Specifically, set
356418334Speter	`must_extract'	  if we need to extract the insn operands
356518334Speter	`must_constrain'  if we must compute `which_alternative'
356618334Speter	`address_used'	  if an address expression was used
356718334Speter	`length_used'	  if an (eq_attr "length" ...) was used
356818334Speter */
356918334Speter
357018334Speterstatic void
3571132718Skanwalk_attr_value (rtx exp)
357218334Speter{
357390075Sobrien  int i, j;
357490075Sobrien  const char *fmt;
357518334Speter  RTX_CODE code;
357618334Speter
357718334Speter  if (exp == NULL)
357818334Speter    return;
357918334Speter
358018334Speter  code = GET_CODE (exp);
358118334Speter  switch (code)
358218334Speter    {
358318334Speter    case SYMBOL_REF:
3584117395Skan      if (! ATTR_IND_SIMPLIFIED_P (exp))
358518334Speter	/* Since this is an arbitrary expression, it can look at anything.
358618334Speter	   However, constant expressions do not depend on any particular
358718334Speter	   insn.  */
358818334Speter	must_extract = must_constrain = 1;
358918334Speter      return;
359018334Speter
359118334Speter    case MATCH_OPERAND:
359218334Speter      must_extract = 1;
359318334Speter      return;
359418334Speter
3595132718Skan    case EQ_ATTR_ALT:
3596132718Skan      must_extract = must_constrain = 1;
3597132718Skan      break;
3598132718Skan
359918334Speter    case EQ_ATTR:
360018334Speter      if (XSTR (exp, 0) == alternative_name)
360118334Speter	must_extract = must_constrain = 1;
3602132718Skan      else if (strcmp_check (XSTR (exp, 0), length_str) == 0)
360318334Speter	length_used = 1;
360418334Speter      return;
360518334Speter
360618334Speter    case MATCH_DUP:
360718334Speter      must_extract = 1;
360818334Speter      address_used = 1;
360918334Speter      return;
361018334Speter
361118334Speter    case PC:
361218334Speter      address_used = 1;
361318334Speter      return;
361418334Speter
361518334Speter    case ATTR_FLAG:
361618334Speter      return;
361750397Sobrien
361850397Sobrien    default:
361950397Sobrien      break;
362018334Speter    }
362118334Speter
362218334Speter  for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
362318334Speter    switch (*fmt++)
362418334Speter      {
362518334Speter      case 'e':
362618334Speter      case 'u':
362718334Speter	walk_attr_value (XEXP (exp, i));
362818334Speter	break;
362918334Speter
363018334Speter      case 'E':
363118334Speter	if (XVEC (exp, i) != NULL)
363218334Speter	  for (j = 0; j < XVECLEN (exp, i); j++)
363318334Speter	    walk_attr_value (XVECEXP (exp, i, j));
363418334Speter	break;
363518334Speter      }
363618334Speter}
3637132718Skan
363818334Speter/* Write out a function to obtain the attribute for a given INSN.  */
363918334Speter
364018334Speterstatic void
3641132718Skanwrite_attr_get (struct attr_desc *attr)
364218334Speter{
364318334Speter  struct attr_value *av, *common_av;
364418334Speter
364518334Speter  /* Find the most used attribute value.  Handle that as the `default' of the
364650397Sobrien     switch we will generate.  */
364718334Speter  common_av = find_most_used (attr);
364818334Speter
364918334Speter  /* Write out start of function, then all values with explicit `case' lines,
365018334Speter     then a `default', then the value with the most uses.  */
365118334Speter  if (!attr->is_numeric)
365218334Speter    printf ("enum attr_%s\n", attr->name);
365318334Speter  else
365418334Speter    printf ("int\n");
365518334Speter
365618334Speter  /* If the attribute name starts with a star, the remainder is the name of
365718334Speter     the subroutine to use, instead of `get_attr_...'.  */
365818334Speter  if (attr->name[0] == '*')
3659132718Skan    printf ("%s (rtx insn ATTRIBUTE_UNUSED)\n", &attr->name[1]);
366018334Speter  else if (attr->is_const == 0)
3661132718Skan    printf ("get_attr_%s (rtx insn ATTRIBUTE_UNUSED)\n", attr->name);
366218334Speter  else
366318334Speter    {
3664132718Skan      printf ("get_attr_%s (void)\n", attr->name);
366518334Speter      printf ("{\n");
366618334Speter
366718334Speter      for (av = attr->first_value; av; av = av->next)
3668169689Skan	if (av->num_insns == 1)
366918334Speter	  write_attr_set (attr, 2, av->value, "return", ";",
3670169689Skan			  true_rtx, av->first_insn->def->insn_code,
3671169689Skan			  av->first_insn->def->insn_index);
3672169689Skan	else if (av->num_insns != 0)
3673169689Skan	  write_attr_set (attr, 2, av->value, "return", ";",
3674169689Skan			  true_rtx, -2, 0);
367518334Speter
367618334Speter      printf ("}\n\n");
367718334Speter      return;
367818334Speter    }
367950397Sobrien
368018334Speter  printf ("{\n");
3681169689Skan  printf ("  switch (recog_memoized (insn))\n");
3682169689Skan  printf ("    {\n");
368318334Speter
3684169689Skan  for (av = attr->first_value; av; av = av->next)
3685169689Skan    if (av != common_av)
3686169689Skan      write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
368718334Speter
3688169689Skan  write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
3689169689Skan  printf ("    }\n}\n\n");
369018334Speter}
3691132718Skan
369218334Speter/* Given an AND tree of known true terms (because we are inside an `if' with
369318334Speter   that as the condition or are in an `else' clause) and an expression,
369418334Speter   replace any known true terms with TRUE.  Use `simplify_and_tree' to do
369518334Speter   the bulk of the work.  */
369618334Speter
369718334Speterstatic rtx
3698132718Skaneliminate_known_true (rtx known_true, rtx exp, int insn_code, int insn_index)
369918334Speter{
370018334Speter  rtx term;
370118334Speter
370218334Speter  known_true = SIMPLIFY_TEST_EXP (known_true, insn_code, insn_index);
370318334Speter
370418334Speter  if (GET_CODE (known_true) == AND)
370518334Speter    {
370618334Speter      exp = eliminate_known_true (XEXP (known_true, 0), exp,
370718334Speter				  insn_code, insn_index);
370818334Speter      exp = eliminate_known_true (XEXP (known_true, 1), exp,
370918334Speter				  insn_code, insn_index);
371018334Speter    }
371118334Speter  else
371218334Speter    {
371318334Speter      term = known_true;
371418334Speter      exp = simplify_and_tree (exp, &term, insn_code, insn_index);
371518334Speter    }
371618334Speter
371718334Speter  return exp;
371818334Speter}
3719132718Skan
372018334Speter/* Write out a series of tests and assignment statements to perform tests and
372118334Speter   sets of an attribute value.  We are passed an indentation amount and prefix
372218334Speter   and suffix strings to write around each attribute value (e.g., "return"
372318334Speter   and ";").  */
372418334Speter
372518334Speterstatic void
3726132718Skanwrite_attr_set (struct attr_desc *attr, int indent, rtx value,
3727132718Skan		const char *prefix, const char *suffix, rtx known_true,
3728132718Skan		int insn_code, int insn_index)
372918334Speter{
373052284Sobrien  if (GET_CODE (value) == COND)
373118334Speter    {
373218334Speter      /* Assume the default value will be the default of the COND unless we
373318334Speter	 find an always true expression.  */
373418334Speter      rtx default_val = XEXP (value, 1);
373518334Speter      rtx our_known_true = known_true;
373618334Speter      rtx newexp;
373718334Speter      int first_if = 1;
373818334Speter      int i;
373918334Speter
374018334Speter      for (i = 0; i < XVECLEN (value, 0); i += 2)
374118334Speter	{
374218334Speter	  rtx testexp;
374318334Speter	  rtx inner_true;
374418334Speter
374518334Speter	  testexp = eliminate_known_true (our_known_true,
374618334Speter					  XVECEXP (value, 0, i),
374718334Speter					  insn_code, insn_index);
374818334Speter	  newexp = attr_rtx (NOT, testexp);
374990075Sobrien	  newexp = insert_right_side (AND, our_known_true, newexp,
375090075Sobrien				      insn_code, insn_index);
375118334Speter
375218334Speter	  /* If the test expression is always true or if the next `known_true'
375318334Speter	     expression is always false, this is the last case, so break
375418334Speter	     out and let this value be the `else' case.  */
375518334Speter	  if (testexp == true_rtx || newexp == false_rtx)
375618334Speter	    {
375718334Speter	      default_val = XVECEXP (value, 0, i + 1);
375818334Speter	      break;
375918334Speter	    }
376018334Speter
376118334Speter	  /* Compute the expression to pass to our recursive call as being
376218334Speter	     known true.  */
376318334Speter	  inner_true = insert_right_side (AND, our_known_true,
376418334Speter					  testexp, insn_code, insn_index);
376518334Speter
376618334Speter	  /* If this is always false, skip it.  */
376718334Speter	  if (inner_true == false_rtx)
376818334Speter	    continue;
376918334Speter
377018334Speter	  write_indent (indent);
377118334Speter	  printf ("%sif ", first_if ? "" : "else ");
377218334Speter	  first_if = 0;
377318334Speter	  write_test_expr (testexp, 0);
377418334Speter	  printf ("\n");
377518334Speter	  write_indent (indent + 2);
377618334Speter	  printf ("{\n");
377718334Speter
377890075Sobrien	  write_attr_set (attr, indent + 4,
377918334Speter			  XVECEXP (value, 0, i + 1), prefix, suffix,
378018334Speter			  inner_true, insn_code, insn_index);
378118334Speter	  write_indent (indent + 2);
378218334Speter	  printf ("}\n");
378318334Speter	  our_known_true = newexp;
378418334Speter	}
378518334Speter
378618334Speter      if (! first_if)
378718334Speter	{
378818334Speter	  write_indent (indent);
378918334Speter	  printf ("else\n");
379018334Speter	  write_indent (indent + 2);
379118334Speter	  printf ("{\n");
379218334Speter	}
379318334Speter
379418334Speter      write_attr_set (attr, first_if ? indent : indent + 4, default_val,
379518334Speter		      prefix, suffix, our_known_true, insn_code, insn_index);
379618334Speter
379718334Speter      if (! first_if)
379818334Speter	{
379918334Speter	  write_indent (indent + 2);
380018334Speter	  printf ("}\n");
380118334Speter	}
380218334Speter    }
380318334Speter  else
380452284Sobrien    {
380552284Sobrien      write_indent (indent);
380652284Sobrien      printf ("%s ", prefix);
380752284Sobrien      write_attr_value (attr, value);
380852284Sobrien      printf ("%s\n", suffix);
380952284Sobrien    }
381018334Speter}
3811132718Skan
3812169689Skan/* Write a series of case statements for every instruction in list IE.
3813169689Skan   INDENT is the amount of indentation to write before each case.  */
3814169689Skan
3815169689Skanstatic void
3816169689Skanwrite_insn_cases (struct insn_ent *ie, int indent)
3817169689Skan{
3818169689Skan  for (; ie != 0; ie = ie->next)
3819169689Skan    if (ie->def->insn_code != -1)
3820169689Skan      {
3821169689Skan	write_indent (indent);
3822169689Skan	if (GET_CODE (ie->def->def) == DEFINE_PEEPHOLE)
3823169689Skan	  printf ("case %d:  /* define_peephole, line %d */\n",
3824169689Skan		  ie->def->insn_code, ie->def->lineno);
3825169689Skan	else
3826169689Skan	  printf ("case %d:  /* %s */\n",
3827169689Skan		  ie->def->insn_code, XSTR (ie->def->def, 0));
3828169689Skan      }
3829169689Skan}
3830169689Skan
383118334Speter/* Write out the computation for one attribute value.  */
383218334Speter
383318334Speterstatic void
3834132718Skanwrite_attr_case (struct attr_desc *attr, struct attr_value *av,
3835132718Skan		 int write_case_lines, const char *prefix, const char *suffix,
3836132718Skan		 int indent, rtx known_true)
383718334Speter{
383818334Speter  if (av->num_insns == 0)
383918334Speter    return;
384018334Speter
384118334Speter  if (av->has_asm_insn)
384218334Speter    {
384318334Speter      write_indent (indent);
384418334Speter      printf ("case -1:\n");
384518334Speter      write_indent (indent + 2);
384618334Speter      printf ("if (GET_CODE (PATTERN (insn)) != ASM_INPUT\n");
384718334Speter      write_indent (indent + 2);
384818334Speter      printf ("    && asm_noperands (PATTERN (insn)) < 0)\n");
384918334Speter      write_indent (indent + 2);
385018334Speter      printf ("  fatal_insn_not_found (insn);\n");
385118334Speter    }
385218334Speter
385318334Speter  if (write_case_lines)
3854169689Skan    write_insn_cases (av->first_insn, indent);
385518334Speter  else
385618334Speter    {
385718334Speter      write_indent (indent);
385818334Speter      printf ("default:\n");
385918334Speter    }
386018334Speter
386118334Speter  /* See what we have to do to output this value.  */
386218334Speter  must_extract = must_constrain = address_used = 0;
386318334Speter  walk_attr_value (av->value);
386418334Speter
386590075Sobrien  if (must_constrain)
386618334Speter    {
386718334Speter      write_indent (indent + 2);
386890075Sobrien      printf ("extract_constrain_insn_cached (insn);\n");
386918334Speter    }
387090075Sobrien  else if (must_extract)
387118334Speter    {
387218334Speter      write_indent (indent + 2);
387390075Sobrien      printf ("extract_insn_cached (insn);\n");
387418334Speter    }
387518334Speter
3876169689Skan  if (av->num_insns == 1)
3877169689Skan    write_attr_set (attr, indent + 2, av->value, prefix, suffix,
3878169689Skan		    known_true, av->first_insn->def->insn_code,
3879169689Skan		    av->first_insn->def->insn_index);
3880169689Skan  else
3881169689Skan    write_attr_set (attr, indent + 2, av->value, prefix, suffix,
3882169689Skan		    known_true, -2, 0);
388318334Speter
388418334Speter  if (strncmp (prefix, "return", 6))
388518334Speter    {
388618334Speter      write_indent (indent + 2);
388718334Speter      printf ("break;\n");
388818334Speter    }
388918334Speter  printf ("\n");
389018334Speter}
3891132718Skan
389250397Sobrien/* Search for uses of non-const attributes and write code to cache them.  */
389350397Sobrien
389450397Sobrienstatic int
3895132718Skanwrite_expr_attr_cache (rtx p, struct attr_desc *attr)
389650397Sobrien{
389790075Sobrien  const char *fmt;
389850397Sobrien  int i, ie, j, je;
389950397Sobrien
390050397Sobrien  if (GET_CODE (p) == EQ_ATTR)
390150397Sobrien    {
390250397Sobrien      if (XSTR (p, 0) != attr->name)
390350397Sobrien	return 0;
390450397Sobrien
390550397Sobrien      if (!attr->is_numeric)
390690075Sobrien	printf ("  enum attr_%s ", attr->name);
390750397Sobrien      else
390890075Sobrien	printf ("  int ");
390950397Sobrien
391050397Sobrien      printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
391150397Sobrien      return 1;
391250397Sobrien    }
391350397Sobrien
391450397Sobrien  fmt = GET_RTX_FORMAT (GET_CODE (p));
391550397Sobrien  ie = GET_RTX_LENGTH (GET_CODE (p));
391650397Sobrien  for (i = 0; i < ie; i++)
391750397Sobrien    {
391850397Sobrien      switch (*fmt++)
391950397Sobrien	{
392050397Sobrien	case 'e':
392150397Sobrien	  if (write_expr_attr_cache (XEXP (p, i), attr))
392250397Sobrien	    return 1;
392350397Sobrien	  break;
392450397Sobrien
392550397Sobrien	case 'E':
392650397Sobrien	  je = XVECLEN (p, i);
392750397Sobrien	  for (j = 0; j < je; ++j)
392850397Sobrien	    if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
392950397Sobrien	      return 1;
393050397Sobrien	  break;
393150397Sobrien	}
393250397Sobrien    }
393350397Sobrien
393450397Sobrien  return 0;
393550397Sobrien}
393650397Sobrien
3937169689Skan/* Utilities to write in various forms.  */
393850397Sobrien
393950397Sobrienstatic void
3940132718Skanwrite_attr_valueq (struct attr_desc *attr, const char *s)
394118334Speter{
394218334Speter  if (attr->is_numeric)
394318334Speter    {
394450397Sobrien      int num = atoi (s);
394550397Sobrien
394650397Sobrien      printf ("%d", num);
394750397Sobrien
3948169689Skan      if (num > 9 || num < 0)
394950397Sobrien	printf (" /* 0x%x */", num);
395018334Speter    }
395118334Speter  else
395218334Speter    {
395318334Speter      write_upcase (attr->name);
395418334Speter      printf ("_");
395518334Speter      write_upcase (s);
395618334Speter    }
395718334Speter}
395818334Speter
395918334Speterstatic void
3960132718Skanwrite_attr_value (struct attr_desc *attr, rtx value)
396118334Speter{
396252284Sobrien  int op;
396318334Speter
396452284Sobrien  switch (GET_CODE (value))
396552284Sobrien    {
396652284Sobrien    case CONST_STRING:
396752284Sobrien      write_attr_valueq (attr, XSTR (value, 0));
396852284Sobrien      break;
396952284Sobrien
397090075Sobrien    case CONST_INT:
397190075Sobrien      printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (value));
397290075Sobrien      break;
397390075Sobrien
397452284Sobrien    case SYMBOL_REF:
3975169689Skan      print_c_condition (XSTR (value, 0));
397652284Sobrien      break;
397752284Sobrien
397852284Sobrien    case ATTR:
397952284Sobrien      {
3980132718Skan	struct attr_desc *attr2 = find_attr (&XSTR (value, 0), 0);
398190075Sobrien	printf ("get_attr_%s (%s)", attr2->name,
398252284Sobrien		(attr2->is_const ? "" : "insn"));
398352284Sobrien      }
398452284Sobrien      break;
398552284Sobrien
398652284Sobrien    case PLUS:
398752284Sobrien      op = '+';
398852284Sobrien      goto do_operator;
398952284Sobrien    case MINUS:
399052284Sobrien      op = '-';
399152284Sobrien      goto do_operator;
399252284Sobrien    case MULT:
399352284Sobrien      op = '*';
399452284Sobrien      goto do_operator;
399552284Sobrien    case DIV:
399652284Sobrien      op = '/';
399752284Sobrien      goto do_operator;
399852284Sobrien    case MOD:
399952284Sobrien      op = '%';
400052284Sobrien      goto do_operator;
400152284Sobrien
400252284Sobrien    do_operator:
400352284Sobrien      write_attr_value (attr, XEXP (value, 0));
400452284Sobrien      putchar (' ');
400552284Sobrien      putchar (op);
400652284Sobrien      putchar (' ');
400752284Sobrien      write_attr_value (attr, XEXP (value, 1));
400852284Sobrien      break;
400952284Sobrien
401052284Sobrien    default:
4011169689Skan      gcc_unreachable ();
401252284Sobrien    }
401318334Speter}
401418334Speter
401518334Speterstatic void
4016132718Skanwrite_upcase (const char *str)
401718334Speter{
401818334Speter  while (*str)
401990075Sobrien    {
402090075Sobrien      /* The argument of TOUPPER should not have side effects.  */
402190075Sobrien      putchar (TOUPPER(*str));
402290075Sobrien      str++;
402390075Sobrien    }
402418334Speter}
402518334Speter
402618334Speterstatic void
4027132718Skanwrite_indent (int indent)
402818334Speter{
402918334Speter  for (; indent > 8; indent -= 8)
403018334Speter    printf ("\t");
403118334Speter
403218334Speter  for (; indent; indent--)
403318334Speter    printf (" ");
403418334Speter}
4035132718Skan
403618334Speter/* Write a subroutine that is given an insn that requires a delay slot, a
4037117395Skan   delay slot ordinal, and a candidate insn.  It returns nonzero if the
403818334Speter   candidate can be placed in the specified delay slot of the insn.
403918334Speter
404018334Speter   We can write as many as three subroutines.  `eligible_for_delay'
404118334Speter   handles normal delay slots, `eligible_for_annul_true' indicates that
404218334Speter   the specified insn can be annulled if the branch is true, and likewise
404318334Speter   for `eligible_for_annul_false'.
404418334Speter
404518334Speter   KIND is a string distinguishing these three cases ("delay", "annul_true",
404618334Speter   or "annul_false").  */
404718334Speter
404818334Speterstatic void
4049132718Skanwrite_eligible_delay (const char *kind)
405018334Speter{
405118334Speter  struct delay_desc *delay;
405218334Speter  int max_slots;
405318334Speter  char str[50];
4054132718Skan  const char *pstr;
405518334Speter  struct attr_desc *attr;
405618334Speter  struct attr_value *av, *common_av;
405718334Speter  int i;
405818334Speter
405918334Speter  /* Compute the maximum number of delay slots required.  We use the delay
406018334Speter     ordinal times this number plus one, plus the slot number as an index into
406118334Speter     the appropriate predicate to test.  */
406218334Speter
406318334Speter  for (delay = delays, max_slots = 0; delay; delay = delay->next)
406418334Speter    if (XVECLEN (delay->def, 1) / 3 > max_slots)
406518334Speter      max_slots = XVECLEN (delay->def, 1) / 3;
406618334Speter
406718334Speter  /* Write function prelude.  */
406818334Speter
406918334Speter  printf ("int\n");
4070132718Skan  printf ("eligible_for_%s (rtx delay_insn ATTRIBUTE_UNUSED, int slot, rtx candidate_insn, int flags ATTRIBUTE_UNUSED)\n",
407190075Sobrien	  kind);
407218334Speter  printf ("{\n");
407318334Speter  printf ("  rtx insn;\n");
407418334Speter  printf ("\n");
4075169689Skan  printf ("  gcc_assert (slot < %d);\n", max_slots);
407618334Speter  printf ("\n");
4077169689Skan  /* Allow dbr_schedule to pass labels, etc.  This can happen if try_split
4078169689Skan     converts a compound instruction into a loop.  */
4079169689Skan  printf ("  if (!INSN_P (candidate_insn))\n");
4080169689Skan  printf ("    return 0;\n");
4081169689Skan  printf ("\n");
408218334Speter
408318334Speter  /* If more than one delay type, find out which type the delay insn is.  */
408418334Speter
408518334Speter  if (num_delays > 1)
408618334Speter    {
4087132718Skan      attr = find_attr (&delay_type_str, 0);
4088169689Skan      gcc_assert (attr);
408918334Speter      common_av = find_most_used (attr);
409018334Speter
409118334Speter      printf ("  insn = delay_insn;\n");
409218334Speter      printf ("  switch (recog_memoized (insn))\n");
409318334Speter      printf ("    {\n");
409418334Speter
409518334Speter      sprintf (str, " * %d;\n      break;", max_slots);
409618334Speter      for (av = attr->first_value; av; av = av->next)
409718334Speter	if (av != common_av)
409818334Speter	  write_attr_case (attr, av, 1, "slot +=", str, 4, true_rtx);
409918334Speter
410018334Speter      write_attr_case (attr, common_av, 0, "slot +=", str, 4, true_rtx);
410118334Speter      printf ("    }\n\n");
410218334Speter
410318334Speter      /* Ensure matched.  Otherwise, shouldn't have been called.  */
4104169689Skan      printf ("  gcc_assert (slot >= %d);\n\n", max_slots);
410518334Speter    }
410618334Speter
410718334Speter  /* If just one type of delay slot, write simple switch.  */
410818334Speter  if (num_delays == 1 && max_slots == 1)
410918334Speter    {
411018334Speter      printf ("  insn = candidate_insn;\n");
411118334Speter      printf ("  switch (recog_memoized (insn))\n");
411218334Speter      printf ("    {\n");
411318334Speter
4114132718Skan      attr = find_attr (&delay_1_0_str, 0);
4115169689Skan      gcc_assert (attr);
411618334Speter      common_av = find_most_used (attr);
411718334Speter
411818334Speter      for (av = attr->first_value; av; av = av->next)
411918334Speter	if (av != common_av)
412018334Speter	  write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
412118334Speter
412218334Speter      write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
412318334Speter      printf ("    }\n");
412418334Speter    }
412518334Speter
412618334Speter  else
412718334Speter    {
412818334Speter      /* Write a nested CASE.  The first indicates which condition we need to
412918334Speter	 test, and the inner CASE tests the condition.  */
413018334Speter      printf ("  insn = candidate_insn;\n");
413118334Speter      printf ("  switch (slot)\n");
413218334Speter      printf ("    {\n");
413318334Speter
413418334Speter      for (delay = delays; delay; delay = delay->next)
413518334Speter	for (i = 0; i < XVECLEN (delay->def, 1); i += 3)
413618334Speter	  {
413718334Speter	    printf ("    case %d:\n",
413818334Speter		    (i / 3) + (num_delays == 1 ? 0 : delay->num * max_slots));
413918334Speter	    printf ("      switch (recog_memoized (insn))\n");
414018334Speter	    printf ("\t{\n");
414118334Speter
414218334Speter	    sprintf (str, "*%s_%d_%d", kind, delay->num, i / 3);
4143132718Skan	    pstr = str;
4144132718Skan	    attr = find_attr (&pstr, 0);
4145169689Skan	    gcc_assert (attr);
414618334Speter	    common_av = find_most_used (attr);
414718334Speter
414818334Speter	    for (av = attr->first_value; av; av = av->next)
414918334Speter	      if (av != common_av)
415018334Speter		write_attr_case (attr, av, 1, "return", ";", 8, true_rtx);
415118334Speter
415218334Speter	    write_attr_case (attr, common_av, 0, "return", ";", 8, true_rtx);
415318334Speter	    printf ("      }\n");
415418334Speter	  }
415518334Speter
415618334Speter      printf ("    default:\n");
4157169689Skan      printf ("      gcc_unreachable ();\n");
415818334Speter      printf ("    }\n");
415918334Speter    }
416018334Speter
416118334Speter  printf ("}\n\n");
416218334Speter}
4163132718Skan
416418334Speter/* This page contains miscellaneous utility routines.  */
416518334Speter
416618334Speter/* Given a pointer to a (char *), return a malloc'ed string containing the
416718334Speter   next comma-separated element.  Advance the pointer to after the string
416818334Speter   scanned, or the end-of-string.  Return NULL if at end of string.  */
416918334Speter
417018334Speterstatic char *
4171132718Skannext_comma_elt (const char **pstr)
417218334Speter{
4173117395Skan  const char *start;
417418334Speter
4175117395Skan  start = scan_comma_elt (pstr);
4176117395Skan
4177117395Skan  if (start == NULL)
417818334Speter    return NULL;
417918334Speter
4180117395Skan  return attr_string (start, *pstr - start);
418118334Speter}
418218334Speter
418318334Speter/* Return a `struct attr_desc' pointer for a given named attribute.  If CREATE
4184132718Skan   is nonzero, build a new attribute, if one does not exist.  *NAME_P is
4185132718Skan   replaced by a pointer to a canonical copy of the string.  */
418618334Speter
418718334Speterstatic struct attr_desc *
4188132718Skanfind_attr (const char **name_p, int create)
418918334Speter{
419018334Speter  struct attr_desc *attr;
419118334Speter  int index;
4192132718Skan  const char *name = *name_p;
419318334Speter
419418334Speter  /* Before we resort to using `strcmp', see if the string address matches
419518334Speter     anywhere.  In most cases, it should have been canonicalized to do so.  */
419618334Speter  if (name == alternative_name)
419718334Speter    return NULL;
419818334Speter
419918334Speter  index = name[0] & (MAX_ATTRS_INDEX - 1);
420018334Speter  for (attr = attrs[index]; attr; attr = attr->next)
420118334Speter    if (name == attr->name)
420218334Speter      return attr;
420318334Speter
420418334Speter  /* Otherwise, do it the slow way.  */
420518334Speter  for (attr = attrs[index]; attr; attr = attr->next)
420618334Speter    if (name[0] == attr->name[0] && ! strcmp (name, attr->name))
4207132718Skan      {
4208132718Skan	*name_p = attr->name;
4209132718Skan	return attr;
4210132718Skan      }
421118334Speter
421218334Speter  if (! create)
421318334Speter    return NULL;
421418334Speter
4215132718Skan  attr = oballoc (sizeof (struct attr_desc));
4216132718Skan  attr->name = DEF_ATTR_STRING (name);
421718334Speter  attr->first_value = attr->default_val = NULL;
4218169689Skan  attr->is_numeric = attr->is_const = attr->is_special = 0;
421918334Speter  attr->next = attrs[index];
422018334Speter  attrs[index] = attr;
422118334Speter
4222132718Skan  *name_p = attr->name;
4223132718Skan
422418334Speter  return attr;
422518334Speter}
422618334Speter
422718334Speter/* Create internal attribute with the given default value.  */
422818334Speter
4229169689Skanstatic void
4230132718Skanmake_internal_attr (const char *name, rtx value, int special)
423118334Speter{
423218334Speter  struct attr_desc *attr;
423318334Speter
4234132718Skan  attr = find_attr (&name, 1);
4235169689Skan  gcc_assert (!attr->default_val);
423618334Speter
423718334Speter  attr->is_numeric = 1;
423818334Speter  attr->is_const = 0;
4239132718Skan  attr->is_special = (special & ATTR_SPECIAL) != 0;
424018334Speter  attr->default_val = get_attr_value (value, attr, -2);
424118334Speter}
424218334Speter
424318334Speter/* Find the most used value of an attribute.  */
424418334Speter
424518334Speterstatic struct attr_value *
4246132718Skanfind_most_used (struct attr_desc *attr)
424718334Speter{
424818334Speter  struct attr_value *av;
424918334Speter  struct attr_value *most_used;
425018334Speter  int nuses;
425118334Speter
425218334Speter  most_used = NULL;
425318334Speter  nuses = -1;
425418334Speter
425518334Speter  for (av = attr->first_value; av; av = av->next)
425618334Speter    if (av->num_insns > nuses)
425718334Speter      nuses = av->num_insns, most_used = av;
425818334Speter
425918334Speter  return most_used;
426018334Speter}
426118334Speter
4262169689Skan/* Return (attr_value "n") */
426318334Speter
426418334Speterstatic rtx
4265132718Skanmake_numeric_value (int n)
426618334Speter{
426718334Speter  static rtx int_values[20];
426818334Speter  rtx exp;
426918334Speter  char *p;
427018334Speter
4271169689Skan  gcc_assert (n >= 0);
427218334Speter
427318334Speter  if (n < 20 && int_values[n])
427418334Speter    return int_values[n];
427518334Speter
427618334Speter  p = attr_printf (MAX_DIGITS, "%d", n);
427718334Speter  exp = attr_rtx (CONST_STRING, p);
427818334Speter
427918334Speter  if (n < 20)
428018334Speter    int_values[n] = exp;
428118334Speter
428218334Speter  return exp;
428318334Speter}
4284132718Skan
428518334Speterstatic rtx
4286132718Skancopy_rtx_unchanging (rtx orig)
428718334Speter{
4288117395Skan  if (ATTR_IND_SIMPLIFIED_P (orig) || ATTR_CURR_SIMPLIFIED_P (orig))
428918334Speter    return orig;
429018334Speter
4291117395Skan  ATTR_CURR_SIMPLIFIED_P (orig) = 1;
429218334Speter  return orig;
429318334Speter}
429418334Speter
429518334Speter/* Determine if an insn has a constant number of delay slots, i.e., the
429618334Speter   number of delay slots is not a function of the length of the insn.  */
429718334Speter
429890075Sobrienstatic void
4299132718Skanwrite_const_num_delay_slots (void)
430018334Speter{
4301132718Skan  struct attr_desc *attr = find_attr (&num_delay_slots_str, 0);
430218334Speter  struct attr_value *av;
430318334Speter
430418334Speter  if (attr)
430518334Speter    {
4306132718Skan      printf ("int\nconst_num_delay_slots (rtx insn)\n");
430718334Speter      printf ("{\n");
430818334Speter      printf ("  switch (recog_memoized (insn))\n");
430918334Speter      printf ("    {\n");
431018334Speter
431118334Speter      for (av = attr->first_value; av; av = av->next)
431218334Speter	{
431318334Speter	  length_used = 0;
431418334Speter	  walk_attr_value (av->value);
431518334Speter	  if (length_used)
4316169689Skan	    write_insn_cases (av->first_insn, 4);
431718334Speter	}
431818334Speter
431918334Speter      printf ("    default:\n");
432018334Speter      printf ("      return 1;\n");
432150397Sobrien      printf ("    }\n}\n\n");
432218334Speter    }
432318334Speter}
4324169689Skan
4325169689Skan/* Synthetic attributes used by insn-automata.c and the scheduler.
4326169689Skan   These are primarily concerned with (define_insn_reservation)
4327169689Skan   patterns.  */
432818334Speter
4329169689Skanstruct insn_reserv
4330169689Skan{
4331169689Skan  struct insn_reserv *next;
4332169689Skan
4333169689Skan  const char *name;
4334169689Skan  int default_latency;
4335169689Skan  rtx condexp;
4336169689Skan
4337169689Skan  /* Sequence number of this insn.  */
4338169689Skan  int insn_num;
4339169689Skan
4340169689Skan  /* Whether a (define_bypass) construct names this insn in its
4341169689Skan     output list.  */
4342169689Skan  bool bypassed;
4343169689Skan};
4344169689Skan
4345169689Skanstatic struct insn_reserv *all_insn_reservs = 0;
4346169689Skanstatic struct insn_reserv **last_insn_reserv_p = &all_insn_reservs;
4347169689Skanstatic size_t n_insn_reservs;
4348169689Skan
4349169689Skan/* Store information from a DEFINE_INSN_RESERVATION for future
4350169689Skan   attribute generation.  */
4351169689Skanstatic void
4352169689Skangen_insn_reserv (rtx def)
4353169689Skan{
4354169689Skan  struct insn_reserv *decl = oballoc (sizeof (struct insn_reserv));
4355169689Skan
4356169689Skan  decl->name            = DEF_ATTR_STRING (XSTR (def, 0));
4357169689Skan  decl->default_latency = XINT (def, 1);
4358169689Skan  decl->condexp         = check_attr_test (XEXP (def, 2), 0, 0);
4359169689Skan  decl->insn_num        = n_insn_reservs;
4360169689Skan  decl->bypassed	= false;
4361169689Skan  decl->next            = 0;
4362169689Skan
4363169689Skan  *last_insn_reserv_p = decl;
4364169689Skan  last_insn_reserv_p  = &decl->next;
4365169689Skan  n_insn_reservs++;
4366169689Skan}
4367169689Skan
4368169689Skan/* Store information from a DEFINE_BYPASS for future attribute
4369169689Skan   generation.  The only thing we care about is the list of output
4370169689Skan   insns, which will later be used to tag reservation structures with
4371169689Skan   a 'bypassed' bit.  */
4372169689Skan
4373169689Skanstruct bypass_list
4374169689Skan{
4375169689Skan  struct bypass_list *next;
4376169689Skan  const char *insn;
4377169689Skan};
4378169689Skan
4379169689Skanstatic struct bypass_list *all_bypasses;
4380169689Skanstatic size_t n_bypasses;
4381169689Skan
4382169689Skanstatic void
4383169689Skangen_bypass_1 (const char *s, size_t len)
4384169689Skan{
4385169689Skan  struct bypass_list *b;
4386169689Skan
4387169689Skan  if (len == 0)
4388169689Skan    return;
4389169689Skan
4390169689Skan  s = attr_string (s, len);
4391169689Skan  for (b = all_bypasses; b; b = b->next)
4392169689Skan    if (s == b->insn)
4393169689Skan      return;  /* already got that one */
4394169689Skan
4395169689Skan  b = oballoc (sizeof (struct bypass_list));
4396169689Skan  b->insn = s;
4397169689Skan  b->next = all_bypasses;
4398169689Skan  all_bypasses = b;
4399169689Skan  n_bypasses++;
4400169689Skan}
4401169689Skan
4402169689Skanstatic void
4403169689Skangen_bypass (rtx def)
4404169689Skan{
4405169689Skan  const char *p, *base;
4406169689Skan
4407169689Skan  for (p = base = XSTR (def, 1); *p; p++)
4408169689Skan    if (*p == ',')
4409169689Skan      {
4410169689Skan	gen_bypass_1 (base, p - base);
4411169689Skan	do
4412169689Skan	  p++;
4413169689Skan	while (ISSPACE (*p));
4414169689Skan	base = p;
4415169689Skan      }
4416169689Skan  gen_bypass_1 (base, p - base);
4417169689Skan}
4418169689Skan
4419169689Skan/* Find and mark all of the bypassed insns.  */
4420169689Skanstatic void
4421169689Skanprocess_bypasses (void)
4422169689Skan{
4423169689Skan  struct bypass_list *b;
4424169689Skan  struct insn_reserv *r;
4425169689Skan
4426169689Skan  /* The reservation list is likely to be much longer than the bypass
4427169689Skan     list.  */
4428169689Skan  for (r = all_insn_reservs; r; r = r->next)
4429169689Skan    for (b = all_bypasses; b; b = b->next)
4430169689Skan      if (r->name == b->insn)
4431169689Skan	r->bypassed = true;
4432169689Skan}
4433169689Skan
4434169689Skan/* Create all of the attributes that describe automaton properties.  */
4435169689Skanstatic void
4436169689Skanmake_automaton_attrs (void)
4437169689Skan{
4438169689Skan  int i;
4439169689Skan  struct insn_reserv *decl;
4440169689Skan  rtx code_exp, lats_exp, byps_exp;
4441169689Skan
4442169689Skan  if (n_insn_reservs == 0)
4443169689Skan    return;
4444169689Skan
4445169689Skan  code_exp = rtx_alloc (COND);
4446169689Skan  lats_exp = rtx_alloc (COND);
4447169689Skan
4448169689Skan  XVEC (code_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
4449169689Skan  XVEC (lats_exp, 0) = rtvec_alloc (n_insn_reservs * 2);
4450169689Skan
4451169689Skan  XEXP (code_exp, 1) = make_numeric_value (n_insn_reservs + 1);
4452169689Skan  XEXP (lats_exp, 1) = make_numeric_value (0);
4453169689Skan
4454169689Skan  for (decl = all_insn_reservs, i = 0;
4455169689Skan       decl;
4456169689Skan       decl = decl->next, i += 2)
4457169689Skan    {
4458169689Skan      XVECEXP (code_exp, 0, i)   = decl->condexp;
4459169689Skan      XVECEXP (lats_exp, 0, i)   = decl->condexp;
4460169689Skan
4461169689Skan      XVECEXP (code_exp, 0, i+1) = make_numeric_value (decl->insn_num);
4462169689Skan      XVECEXP (lats_exp, 0, i+1) = make_numeric_value (decl->default_latency);
4463169689Skan    }
4464169689Skan
4465169689Skan  if (n_bypasses == 0)
4466169689Skan    byps_exp = make_numeric_value (0);
4467169689Skan  else
4468169689Skan    {
4469169689Skan      process_bypasses ();
4470169689Skan
4471169689Skan      byps_exp = rtx_alloc (COND);
4472169689Skan      XVEC (byps_exp, 0) = rtvec_alloc (n_bypasses * 2);
4473169689Skan      XEXP (byps_exp, 1) = make_numeric_value (0);
4474169689Skan      for (decl = all_insn_reservs, i = 0;
4475169689Skan	   decl;
4476169689Skan	   decl = decl->next)
4477169689Skan	if (decl->bypassed)
4478169689Skan	  {
4479169689Skan	    XVECEXP (byps_exp, 0, i)   = decl->condexp;
4480169689Skan	    XVECEXP (byps_exp, 0, i+1) = make_numeric_value (1);
4481169689Skan	    i += 2;
4482169689Skan	  }
4483169689Skan    }
4484169689Skan
4485169689Skan  make_internal_attr ("*internal_dfa_insn_code", code_exp, ATTR_NONE);
4486169689Skan  make_internal_attr ("*insn_default_latency",   lats_exp, ATTR_NONE);
4487169689Skan  make_internal_attr ("*bypass_p",               byps_exp, ATTR_NONE);
4488169689Skan}
4489169689Skan
449018334Speterint
4491132718Skanmain (int argc, char **argv)
449218334Speter{
449318334Speter  rtx desc;
449418334Speter  struct attr_desc *attr;
449518334Speter  struct insn_def *id;
449618334Speter  rtx tem;
449718334Speter  int i;
449818334Speter
449990075Sobrien  progname = "genattrtab";
450018334Speter
450190075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
450290075Sobrien    return (FATAL_EXIT_CODE);
450390075Sobrien
450418334Speter  obstack_init (hash_obstack);
450518334Speter  obstack_init (temp_obstack);
450618334Speter
450718334Speter  /* Set up true and false rtx's */
450818334Speter  true_rtx = rtx_alloc (CONST_INT);
450918334Speter  XWINT (true_rtx, 0) = 1;
451018334Speter  false_rtx = rtx_alloc (CONST_INT);
451118334Speter  XWINT (false_rtx, 0) = 0;
4512117395Skan  ATTR_IND_SIMPLIFIED_P (true_rtx) = ATTR_IND_SIMPLIFIED_P (false_rtx) = 1;
4513117395Skan  ATTR_PERMANENT_P (true_rtx) = ATTR_PERMANENT_P (false_rtx) = 1;
451418334Speter
4515132718Skan  alternative_name = DEF_ATTR_STRING ("alternative");
4516132718Skan  length_str = DEF_ATTR_STRING ("length");
4517132718Skan  delay_type_str = DEF_ATTR_STRING ("*delay_type");
4518132718Skan  delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0");
4519132718Skan  num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots");
452018334Speter
452118334Speter  printf ("/* Generated automatically by the program `genattrtab'\n\
452218334Speterfrom the machine description file `md'.  */\n\n");
452318334Speter
452418334Speter  /* Read the machine description.  */
452518334Speter
452618334Speter  while (1)
452718334Speter    {
452890075Sobrien      int lineno;
452990075Sobrien
453090075Sobrien      desc = read_md_rtx (&lineno, &insn_code_number);
453190075Sobrien      if (desc == NULL)
453218334Speter	break;
453318334Speter
453490075Sobrien      switch (GET_CODE (desc))
453590075Sobrien	{
453690075Sobrien	case DEFINE_INSN:
453790075Sobrien	case DEFINE_PEEPHOLE:
453890075Sobrien	case DEFINE_ASM_ATTRIBUTES:
453990075Sobrien	  gen_insn (desc, lineno);
454090075Sobrien	  break;
454118334Speter
454290075Sobrien	case DEFINE_ATTR:
454390075Sobrien	  gen_attr (desc, lineno);
454490075Sobrien	  break;
454518334Speter
454690075Sobrien	case DEFINE_DELAY:
454790075Sobrien	  gen_delay (desc, lineno);
454890075Sobrien	  break;
454918334Speter
4550169689Skan	case DEFINE_INSN_RESERVATION:
4551169689Skan	  gen_insn_reserv (desc);
455290075Sobrien	  break;
455318334Speter
4554117395Skan	case DEFINE_BYPASS:
4555117395Skan	  gen_bypass (desc);
4556117395Skan	  break;
4557132718Skan
455890075Sobrien	default:
455990075Sobrien	  break;
456018334Speter	}
456190075Sobrien      if (GET_CODE (desc) != DEFINE_ASM_ATTRIBUTES)
456290075Sobrien	insn_index_number++;
456318334Speter    }
456418334Speter
456590075Sobrien  if (have_error)
456690075Sobrien    return FATAL_EXIT_CODE;
456790075Sobrien
456890075Sobrien  insn_code_number++;
456990075Sobrien
457018334Speter  /* If we didn't have a DEFINE_ASM_ATTRIBUTES, make a null one.  */
457118334Speter  if (! got_define_asm_attributes)
457218334Speter    {
457318334Speter      tem = rtx_alloc (DEFINE_ASM_ATTRIBUTES);
457418334Speter      XVEC (tem, 0) = rtvec_alloc (0);
457590075Sobrien      gen_insn (tem, 0);
457618334Speter    }
457718334Speter
457818334Speter  /* Expand DEFINE_DELAY information into new attribute.  */
457918334Speter  if (num_delays)
458018334Speter    expand_delays ();
458118334Speter
458218334Speter  printf ("#include \"config.h\"\n");
458350397Sobrien  printf ("#include \"system.h\"\n");
4584132718Skan  printf ("#include \"coretypes.h\"\n");
4585132718Skan  printf ("#include \"tm.h\"\n");
458618334Speter  printf ("#include \"rtl.h\"\n");
458790075Sobrien  printf ("#include \"tm_p.h\"\n");
458818334Speter  printf ("#include \"insn-config.h\"\n");
458918334Speter  printf ("#include \"recog.h\"\n");
459018334Speter  printf ("#include \"regs.h\"\n");
459118334Speter  printf ("#include \"real.h\"\n");
459218334Speter  printf ("#include \"output.h\"\n");
459318334Speter  printf ("#include \"insn-attr.h\"\n");
459452284Sobrien  printf ("#include \"toplev.h\"\n");
459590075Sobrien  printf ("#include \"flags.h\"\n");
4596117395Skan  printf ("#include \"function.h\"\n");
459790075Sobrien  printf ("\n");
459890075Sobrien  printf ("#define operands recog_data.operand\n\n");
459918334Speter
460018334Speter  /* Make `insn_alternatives'.  */
4601132718Skan  insn_alternatives = oballoc (insn_code_number * sizeof (int));
460218334Speter  for (id = defs; id; id = id->next)
460318334Speter    if (id->insn_code >= 0)
460418334Speter      insn_alternatives[id->insn_code] = (1 << id->num_alternatives) - 1;
460518334Speter
460618334Speter  /* Make `insn_n_alternatives'.  */
4607132718Skan  insn_n_alternatives = oballoc (insn_code_number * sizeof (int));
460818334Speter  for (id = defs; id; id = id->next)
460918334Speter    if (id->insn_code >= 0)
461018334Speter      insn_n_alternatives[id->insn_code] = id->num_alternatives;
461118334Speter
4612169689Skan  /* Construct extra attributes for automata.  */
4613169689Skan  make_automaton_attrs ();
4614169689Skan
461518334Speter  /* Prepare to write out attribute subroutines by checking everything stored
461618334Speter     away and building the attribute cases.  */
461718334Speter
461818334Speter  check_defs ();
461990075Sobrien
462018334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
462118334Speter    for (attr = attrs[i]; attr; attr = attr->next)
462290075Sobrien      attr->default_val->value
462390075Sobrien	= check_attr_value (attr->default_val->value, attr);
462418334Speter
462590075Sobrien  if (have_error)
462690075Sobrien    return FATAL_EXIT_CODE;
462790075Sobrien
462890075Sobrien  for (i = 0; i < MAX_ATTRS_INDEX; i++)
462990075Sobrien    for (attr = attrs[i]; attr; attr = attr->next)
463090075Sobrien      fill_attr (attr);
463190075Sobrien
463218334Speter  /* Construct extra attributes for `length'.  */
463318334Speter  make_length_attrs ();
463418334Speter
463550397Sobrien  /* Perform any possible optimizations to speed up compilation.  */
463618334Speter  optimize_attrs ();
463718334Speter
463818334Speter  /* Now write out all the `gen_attr_...' routines.  Do these before the
4639169689Skan     special routines so that they get defined before they are used.  */
464018334Speter
464118334Speter  for (i = 0; i < MAX_ATTRS_INDEX; i++)
464218334Speter    for (attr = attrs[i]; attr; attr = attr->next)
464318334Speter      {
464450397Sobrien	if (! attr->is_special && ! attr->is_const)
4645169689Skan	  write_attr_get (attr);
464618334Speter      }
464718334Speter
464818334Speter  /* Write out delay eligibility information, if DEFINE_DELAY present.
464918334Speter     (The function to compute the number of delay slots will be written
465018334Speter     below.)  */
465118334Speter  if (num_delays)
465218334Speter    {
465318334Speter      write_eligible_delay ("delay");
465418334Speter      if (have_annul_true)
465518334Speter	write_eligible_delay ("annul_true");
465618334Speter      if (have_annul_false)
465718334Speter	write_eligible_delay ("annul_false");
465818334Speter    }
465918334Speter
4660132718Skan  /* Write out constant delay slot info.  */
466118334Speter  write_const_num_delay_slots ();
466218334Speter
466350397Sobrien  write_length_unit_log ();
466450397Sobrien
466518334Speter  fflush (stdout);
466690075Sobrien  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
466718334Speter}
4668