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