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