diff options
author | bonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-07-20 07:27:18 +0000 |
---|---|---|
committer | bonzini <bonzini@138bc75d-0d04-0410-961f-82ee72b054a4> | 2004-07-20 07:27:18 +0000 |
commit | 67900a4f263f802b9aa076b2ae90954046835da3 (patch) | |
tree | caaa05106e5030ca7ddaa15e73f4d0f45302ff30 /gcc/genattrtab.c | |
parent | 9d47a7f1a6248b1454cc9250261402274b9fc655 (diff) | |
download | gcc-67900a4f263f802b9aa076b2ae90954046835da3.tar.gz |
2004-07-19 Paolo Bonzini <bonzini@gnu.org>
* genattr.c (struct range, struct function_unit,
write_units, extend_range, init_range): Remove them.
(main): Remove code dealing with DEFINE_FUNCTION_UNIT.
Output "#define INSN_SCHEDULING" here.
* genattrtab.c (struct range, struct function_unit_op,
struct function_unit, struct dimension, enum operator,
operate_exp, expand_units, simplify_knowing,
encode_units_mask, simplify_by_exploding,
find_and_mark_used_attributes, unmark_used_attributes,
add_values_to_cover, increment_current_value,
test_for_current_value, simplify_with_current_value,
simplify_with_current_value_aux, gen_unit,
write_unit_name, write_function_unit_info,
write_complex_function, write_toplevel_expr,
find_single_value, extend_range): Remove.
(write_attr_get): Do not handle common_av->value
being an FFS.
(struct attr_desc): Remove func_units_p and blockage_p.
(write_attr_valueq): Do not handle them.
(find_attr): Do not clear them.
(make_internal_attr): Do not initialize them.
(main): Remove code dealing with DEFINE_FUNCTION_UNIT.
* sched-vis.c (init_target_units, insn_print_units,
init_block_visualization, print_block_visualization,
visualize_scheduled_insns, visualize_no_unit,
visualize_stall_cycles, visualize_alloc,
visualize_free, target_units, get_visual_tbl_length,
MAX_VISUAL_LINES, INSN_LEN, n_visual_lines,
visual_tbl_line_length, visual_tbl, n_vis_no_unit,
MAX_VISUAL_NO_UNIT, vis_no_unit): Remove.
* haifa-sched.c (blockage_range, clear_units,
schedule_unit, actual_hazard, potential_hazard,
insn_unit, unit_last_insn, unit_tick,
actual_hazard_this_instance, potential_hazard,
schedule_unit, max_insn_queue_index_value): Remove.
(MAX_INSN_QUEUE_INDEX): Removed, renamed throughout to
max_insn_queue_index.
* rtl.def (DEFINE_FUNCTION_UNIT): Remove.
* doc/md.texi (Processor pipeline description): Remove
references to old pipeline descriptions.
(Automaton pipeline description): Merge with the above.
(Old pipeline description, Comparison of the two descriptions):
Remove.
* bt-load.c (migrate_btr_def): Remove references to
use_pipeline_interface.
* haifa-sched.c (insn_cost, schedule_insn,
schedule_block, advance_one_cycle, sched_init,
queue_to_ready, sched_finish): Likewise.
* modulo-sched.c (sms_schedule, advance_one_cycle,
ps_has_conflicts): Likewise.
* sched-rgn.c (init_ready): Likewise.
(debug_dependencies): Likewise, and remove an "if (1)".
* target.h (use_dfa_pipeline_interface): Remove.
* config/alpha/alpha.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/arc/arc.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/arm/arm.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/c4x/c4x.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/frv/frv.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/i386/i386.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/ia64/ia64.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/iq2000/iq2000.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/m32r/m32r.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/mcore/mcore.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/mips/mips.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/pa/pa.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/rs6000/rs6000.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/s390/s390.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/sh/sh.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/sparc/sparc.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/v850/v850.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* config/xtensa/xtensa.c (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
* doc/tm.texi (TARGET_USE_DFA_PIPELINE_INTERFACE): Remove.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@84944 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/genattrtab.c')
-rw-r--r-- | gcc/genattrtab.c | 1651 |
1 files changed, 23 insertions, 1628 deletions
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index c701488951e..f1bbaf52314 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -21,7 +21,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This program handles insn attributes and the DEFINE_DELAY and - DEFINE_FUNCTION_UNIT definitions. + DEFINE_INSN_RESERVATION definitions. It produces a series of functions named `get_attr_...', one for each insn attribute. Each of these is given the rtx for an insn and returns a member @@ -54,7 +54,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA used. Internal attributes are defined to handle DEFINE_DELAY and - DEFINE_FUNCTION_UNIT. Special routines are output for these cases. + DEFINE_INSN_RESERVATION. Special routines are output for these cases. This program works by keeping a list of possible values for each attribute. These include the basic attribute choices, default values for attribute, and @@ -70,9 +70,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA indicates when the attribute has the specified value for the insn. This avoids recursive calls during compilation. - The strategy used when processing DEFINE_DELAY and DEFINE_FUNCTION_UNIT - definitions is to create arbitrarily complex expressions and have the - optimization simplify them. + The strategy used when processing DEFINE_DELAY definitions is to create + arbitrarily complex expressions and have the optimization simplify them. Once optimization is complete, any required routines and definitions will be written. @@ -193,21 +192,11 @@ struct attr_desc unsigned unsigned_p : 1; /* Make the output function unsigned int. */ unsigned is_const : 1; /* Attribute value constant for each run. */ unsigned is_special : 1; /* Don't call `write_attr_set'. */ - unsigned func_units_p : 1; /* This is the function_units attribute. */ - unsigned blockage_p : 1; /* This is the blockage range function. */ unsigned static_p : 1; /* Make the output function static. */ }; #define NULL_ATTR (struct attr_desc *) NULL -/* A range of values. */ - -struct range -{ - int min; - int max; -}; - /* Structure for each DEFINE_DELAY. */ struct delay_desc @@ -218,43 +207,6 @@ struct delay_desc int lineno; /* Line number. */ }; -/* Record information about each DEFINE_FUNCTION_UNIT. */ - -struct function_unit_op -{ - rtx condexp; /* Expression TRUE for applicable insn. */ - struct function_unit_op *next; /* Next operation for this function unit. */ - int num; /* Ordinal for this operation type in unit. */ - int ready; /* Cost until data is ready. */ - int issue_delay; /* Cost until unit can accept another insn. */ - rtx conflict_exp; /* Expression TRUE for insns incurring issue delay. */ - rtx issue_exp; /* Expression computing issue delay. */ - int lineno; /* Line number. */ -}; - -/* Record information about each function unit mentioned in a - DEFINE_FUNCTION_UNIT. */ - -struct function_unit -{ - const char *name; /* Function unit name. */ - struct function_unit *next; /* Next function unit. */ - int num; /* Ordinal of this unit type. */ - int multiplicity; /* Number of units of this type. */ - int simultaneity; /* Maximum number of simultaneous insns - on this function unit or 0 if unlimited. */ - rtx condexp; /* Expression TRUE for insn needing unit. */ - int num_opclasses; /* Number of different operation types. */ - struct function_unit_op *ops; /* Pointer to first operation type. */ - int needs_conflict_function; /* Nonzero if a conflict function required. */ - int needs_blockage_function; /* Nonzero if a blockage function required. */ - int needs_range_function; /* Nonzero if blockage range function needed. */ - rtx default_cost; /* Conflict cost, if constant. */ - struct range issue_delay; /* Range of issue delay values. */ - int max_blockage; /* Maximum time an insn blocks the unit. */ - int first_lineno; /* First seen line number. */ -}; - /* Listheads of above structures. */ /* This one is indexed by the first character of the attribute name. */ @@ -262,50 +214,6 @@ struct function_unit static struct attr_desc *attrs[MAX_ATTRS_INDEX]; static struct insn_def *defs; static struct delay_desc *delays; -static struct function_unit *units; - -/* An expression where all the unknown terms are EQ_ATTR tests can be - rearranged into a COND provided we can enumerate all possible - combinations of the unknown values. The set of combinations become the - tests of the COND; the value of the expression given that combination is - computed and becomes the corresponding value. To do this, we must be - able to enumerate all values for each attribute used in the expression - (currently, we give up if we find a numeric attribute). - - If the set of EQ_ATTR tests used in an expression tests the value of N - different attributes, the list of all possible combinations can be made - by walking the N-dimensional attribute space defined by those - attributes. We record each of these as a struct dimension. - - The algorithm relies on sharing EQ_ATTR nodes: if two nodes in an - expression are the same, the will also have the same address. We find - all the EQ_ATTR nodes by marking them ATTR_EQ_ATTR_P. This bit later - represents the value of an EQ_ATTR node, so once all nodes are marked, - they are also given an initial value of FALSE. - - We then separate the set of EQ_ATTR nodes into dimensions for each - attribute and put them on the VALUES list. Terms are added as needed by - `add_values_to_cover' so that all possible values of the attribute are - tested. - - Each dimension also has a current value. This is the node that is - currently considered to be TRUE. If this is one of the nodes added by - `add_values_to_cover', all the EQ_ATTR tests in the original expression - will be FALSE. Otherwise, only the CURRENT_VALUE will be true. - - NUM_VALUES is simply the length of the VALUES list and is there for - convenience. - - Once the dimensions are created, the algorithm enumerates all possible - values and computes the current value of the given expression. */ - -struct dimension -{ - struct attr_desc *attr; /* Attribute for this dimension. */ - rtx values; /* List of attribute values used. */ - rtx current_value; /* Position in the list for the TRUE value. */ - int num_values; /* Length of the values list. */ -}; /* Other variables. */ @@ -318,15 +226,10 @@ static int address_used; static int length_used; static int num_delays; static int have_annul_true, have_annul_false; -static int num_units, num_unit_opclasses; static int num_insn_ents; int num_dfa_decls; -/* Used as operand to `operate_exp': */ - -enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP}; - /* Stores, for each insn code, the number of constraint alternatives. */ static int *insn_n_alternatives; @@ -401,10 +304,6 @@ static struct attr_value *get_attr_value (rtx, struct attr_desc *, int); static rtx copy_rtx_unchanging (rtx); static rtx copy_boolean (rtx); static void expand_delays (void); -static rtx operate_exp (enum operator, rtx, rtx); -static void expand_units (void); -static rtx simplify_knowing (rtx, rtx); -static rtx encode_units_mask (rtx); static void fill_attr (struct attr_desc *); static rtx substitute_address (rtx, rtx (*) (rtx), rtx (*) (rtx)); static void make_length_attrs (void); @@ -414,14 +313,6 @@ static rtx one_fn (rtx); static rtx max_fn (rtx); static void write_length_unit_log (void); static rtx simplify_cond (rtx, int, int); -static rtx simplify_by_exploding (rtx); -static int find_and_mark_used_attributes (rtx, rtx *, int *); -static void unmark_used_attributes (rtx, struct dimension *, int); -static int add_values_to_cover (struct dimension *); -static int increment_current_value (struct dimension *, int); -static rtx test_for_current_value (struct dimension *, int); -static rtx simplify_with_current_value (rtx, struct dimension *, int); -static rtx simplify_with_current_value_aux (rtx); static void clear_struct_flag (rtx); static void remove_insn_ent (struct attr_value *, struct insn_ent *); static void insert_insn_ent (struct attr_value *, struct insn_ent *); @@ -440,7 +331,6 @@ static int compares_alternatives_p (rtx); static int contained_in_p (rtx, rtx); static void gen_insn (rtx, int); static void gen_delay (rtx, int); -static void gen_unit (rtx, int); static void write_test_expr (rtx, int); static int max_attr_value (rtx, int*); static int or_attr_value (rtx, int*); @@ -452,23 +342,16 @@ static void write_attr_set (struct attr_desc *, int, rtx, int, int); static void write_attr_case (struct attr_desc *, struct attr_value *, int, const char *, const char *, int, rtx); -static void write_unit_name (const char *, int, const char *); static void write_attr_valueq (struct attr_desc *, const char *); static void write_attr_value (struct attr_desc *, rtx); static void write_upcase (const char *); static void write_indent (int); static void write_eligible_delay (const char *); -static void write_function_unit_info (void); -static void write_complex_function (struct function_unit *, const char *, - const char *); static int write_expr_attr_cache (rtx, struct attr_desc *); -static void write_toplevel_expr (rtx); static void write_const_num_delay_slots (void); static char *next_comma_elt (const char **); static struct attr_desc *find_attr (const char **, int); static struct attr_value *find_most_used (struct attr_desc *); -static rtx find_single_value (struct attr_desc *); -static void extend_range (struct range *, int, int); static rtx attr_eq (const char *, const char *); static const char *attr_numeral (int); static int attr_equal_p (rtx, rtx); @@ -1606,654 +1489,6 @@ expand_delays (void) } } -/* This function is given a left and right side expression and an operator. - Each side is a conditional expression, each alternative of which has a - numerical value. The function returns another conditional expression - which, for every possible set of condition values, returns a value that is - the operator applied to the values of the two sides. - - Since this is called early, it must also support IF_THEN_ELSE. */ - -static rtx -operate_exp (enum operator op, rtx left, rtx right) -{ - int left_value, right_value; - rtx newexp; - int i; - - /* If left is a string, apply operator to it and the right side. */ - if (GET_CODE (left) == CONST_STRING) - { - /* If right is also a string, just perform the operation. */ - if (GET_CODE (right) == CONST_STRING) - { - left_value = atoi (XSTR (left, 0)); - right_value = atoi (XSTR (right, 0)); - switch (op) - { - case PLUS_OP: - i = left_value + right_value; - break; - - case MINUS_OP: - i = left_value - right_value; - break; - - case POS_MINUS_OP: /* The positive part of LEFT - RIGHT. */ - if (left_value > right_value) - i = left_value - right_value; - else - i = 0; - break; - - case OR_OP: - case ORX_OP: - i = left_value | right_value; - break; - - case EQ_OP: - i = left_value == right_value; - break; - - case RANGE_OP: - i = (left_value << (HOST_BITS_PER_INT / 2)) | right_value; - break; - - case MAX_OP: - if (left_value > right_value) - i = left_value; - else - i = right_value; - break; - - case MIN_OP: - if (left_value < right_value) - i = left_value; - else - i = right_value; - break; - - default: - abort (); - } - - if (i == left_value) - return left; - if (i == right_value) - return right; - return make_numeric_value (i); - } - else if (GET_CODE (right) == IF_THEN_ELSE) - { - /* Apply recursively to all values within. */ - rtx newleft = operate_exp (op, left, XEXP (right, 1)); - rtx newright = operate_exp (op, left, XEXP (right, 2)); - if (rtx_equal_p (newleft, newright)) - return newleft; - return attr_rtx (IF_THEN_ELSE, XEXP (right, 0), newleft, newright); - } - else if (GET_CODE (right) == COND) - { - int allsame = 1; - rtx defval; - - newexp = rtx_alloc (COND); - XVEC (newexp, 0) = rtvec_alloc (XVECLEN (right, 0)); - defval = XEXP (newexp, 1) = operate_exp (op, left, XEXP (right, 1)); - - for (i = 0; i < XVECLEN (right, 0); i += 2) - { - XVECEXP (newexp, 0, i) = XVECEXP (right, 0, i); - XVECEXP (newexp, 0, i + 1) - = operate_exp (op, left, XVECEXP (right, 0, i + 1)); - if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), - defval)) - allsame = 0; - } - - /* If the resulting cond is trivial (all alternatives - give the same value), optimize it away. */ - if (allsame) - return operate_exp (op, left, XEXP (right, 1)); - - return newexp; - } - else - fatal ("badly formed attribute value"); - } - - /* A hack to prevent expand_units from completely blowing up: ORX_OP does - not associate through IF_THEN_ELSE. */ - else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE) - { - return attr_rtx (IOR, left, right); - } - - /* Otherwise, do recursion the other way. */ - else if (GET_CODE (left) == IF_THEN_ELSE) - { - rtx newleft = operate_exp (op, XEXP (left, 1), right); - rtx newright = operate_exp (op, XEXP (left, 2), right); - if (rtx_equal_p (newleft, newright)) - return newleft; - return attr_rtx (IF_THEN_ELSE, XEXP (left, 0), newleft, newright); - } - else if (GET_CODE (left) == COND) - { - int allsame = 1; - rtx defval; - - newexp = rtx_alloc (COND); - XVEC (newexp, 0) = rtvec_alloc (XVECLEN (left, 0)); - defval = XEXP (newexp, 1) = operate_exp (op, XEXP (left, 1), right); - - for (i = 0; i < XVECLEN (left, 0); i += 2) - { - XVECEXP (newexp, 0, i) = XVECEXP (left, 0, i); - XVECEXP (newexp, 0, i + 1) - = operate_exp (op, XVECEXP (left, 0, i + 1), right); - if (! rtx_equal_p (XVECEXP (newexp, 0, i + 1), - defval)) - allsame = 0; - } - - /* If the cond is trivial (all alternatives give the same value), - optimize it away. */ - if (allsame) - return operate_exp (op, XEXP (left, 1), right); - - /* If the result is the same as the LEFT operand, - just use that. */ - if (rtx_equal_p (newexp, left)) - return left; - - return newexp; - } - - else - fatal ("badly formed attribute value"); - /* NOTREACHED */ - return NULL; -} - -/* Once all attributes and DEFINE_FUNCTION_UNITs have been read, we - construct a number of attributes. - - The first produces a function `function_units_used' which is given an - insn and produces an encoding showing which function units are required - for the execution of that insn. If the value is non-negative, the insn - uses that unit; otherwise, the value is a one's complement mask of units - used. - - The second produces a function `result_ready_cost' which is used to - determine the time that the result of an insn will be ready and hence - a worst-case schedule. - - Both of these produce quite complex expressions which are then set as the - default value of internal attributes. Normal attribute simplification - should produce reasonable expressions. - - For each unit, a `<name>_unit_ready_cost' function will take an - insn and give the delay until that unit will be ready with the result - and a `<name>_unit_conflict_cost' function is given an insn already - executing on the unit and a candidate to execute and will give the - cost from the time the executing insn started until the candidate - can start (ignore limitations on the number of simultaneous insns). - - For each unit, a `<name>_unit_blockage' function is given an insn - already executing on the unit and a candidate to execute and will - give the delay incurred due to function unit conflicts. The range of - blockage cost values for a given executing insn is given by the - `<name>_unit_blockage_range' function. These values are encoded in - an int where the upper half gives the minimum value and the lower - half gives the maximum value. */ - -static void -expand_units (void) -{ - struct function_unit *unit, **unit_num; - struct function_unit_op *op, **op_array, ***unit_ops; - rtx unitsmask; - rtx readycost; - rtx newexp; - const char *str; - int i, j, u, num, nvalues; - - /* Rebuild the condition for the unit to share the RTL expressions. - Sharing is required by simplify_by_exploding. Build the issue delay - expressions. Validate the expressions we were given for the conditions - and conflict vector. Then make attributes for use in the conflict - function. */ - - for (unit = units; unit; unit = unit->next) - { - unit->condexp = check_attr_test (unit->condexp, 0, unit->first_lineno); - - for (op = unit->ops; op; op = op->next) - { - rtx issue_delay = make_numeric_value (op->issue_delay); - rtx issue_exp = issue_delay; - - /* Build, validate, and simplify the issue delay expression. */ - if (op->conflict_exp != true_rtx) - issue_exp = attr_rtx (IF_THEN_ELSE, op->conflict_exp, - issue_exp, make_numeric_value (0)); - issue_exp = check_attr_value (make_canonical (NULL_ATTR, - issue_exp), - NULL_ATTR); - issue_exp = simplify_knowing (issue_exp, unit->condexp); - op->issue_exp = issue_exp; - - /* Make an attribute for use in the conflict function if needed. */ - unit->needs_conflict_function = (unit->issue_delay.min - != unit->issue_delay.max); - if (unit->needs_conflict_function) - { - str = attr_printf ((strlen (unit->name) + sizeof "*_cost_" - + MAX_DIGITS), - "*%s_cost_%d", unit->name, op->num); - make_internal_attr (str, issue_exp, ATTR_SPECIAL); - } - - /* Validate the condition. */ - op->condexp = check_attr_test (op->condexp, 0, op->lineno); - } - } - - /* Compute the mask of function units used. Initially, the unitsmask is - zero. Set up a conditional to compute each unit's contribution. */ - unitsmask = make_numeric_value (0); - newexp = rtx_alloc (IF_THEN_ELSE); - XEXP (newexp, 2) = make_numeric_value (0); - - /* If we have just a few units, we may be all right expanding the whole - thing. But the expansion is 2**N in space on the number of opclasses, - so we can't do this for very long -- Alpha and MIPS in particular have - problems with this. So in that situation, we fall back on an alternate - implementation method. */ -#define NUM_UNITOP_CUTOFF 20 - - if (num_unit_opclasses < NUM_UNITOP_CUTOFF) - { - /* Merge each function unit into the unit mask attributes. */ - for (unit = units; unit; unit = unit->next) - { - XEXP (newexp, 0) = unit->condexp; - XEXP (newexp, 1) = make_numeric_value (1 << unit->num); - unitsmask = operate_exp (OR_OP, unitsmask, newexp); - } - } - else - { - /* Merge each function unit into the unit mask attributes. */ - for (unit = units; unit; unit = unit->next) - { - XEXP (newexp, 0) = unit->condexp; - XEXP (newexp, 1) = make_numeric_value (1 << unit->num); - unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp)); - } - } - - /* Simplify the unit mask expression, encode it, and make an attribute - for the function_units_used function. */ - unitsmask = simplify_by_exploding (unitsmask); - - if (num_unit_opclasses < NUM_UNITOP_CUTOFF) - unitsmask = encode_units_mask (unitsmask); - else - { - /* We can no longer encode unitsmask at compile time, so emit code to - calculate it at runtime. Rather, put a marker for where we'd do - the code, and actually output it in write_attr_get(). */ - unitsmask = attr_rtx (FFS, unitsmask); - } - - make_internal_attr ("*function_units_used", unitsmask, - (ATTR_NEGATIVE_OK | ATTR_FUNC_UNITS)); - - /* Create an array of ops for each unit. Add an extra unit for the - result_ready_cost function that has the ops of all other units. */ - unit_ops = xmalloc ((num_units + 1) * sizeof (struct function_unit_op **)); - unit_num = xmalloc ((num_units + 1) * sizeof (struct function_unit *)); - - unit_num[num_units] = unit = xmalloc (sizeof (struct function_unit)); - unit->num = num_units; - unit->num_opclasses = 0; - - for (unit = units; unit; unit = unit->next) - { - unit_num[num_units]->num_opclasses += unit->num_opclasses; - unit_num[unit->num] = unit; - unit_ops[unit->num] = op_array = - xmalloc (unit->num_opclasses * sizeof (struct function_unit_op *)); - - for (op = unit->ops; op; op = op->next) - op_array[op->num] = op; - } - - /* Compose the array of ops for the extra unit. */ - unit_ops[num_units] = op_array = - xmalloc (unit_num[num_units]->num_opclasses - * sizeof (struct function_unit_op *)); - - for (unit = units, i = 0; unit; i += unit->num_opclasses, unit = unit->next) - memcpy (&op_array[i], unit_ops[unit->num], - unit->num_opclasses * sizeof (struct function_unit_op *)); - - /* Compute the ready cost function for each unit by computing the - condition for each non-default value. */ - for (u = 0; u <= num_units; u++) - { - rtx orexp; - int value; - - unit = unit_num[u]; - op_array = unit_ops[unit->num]; - num = unit->num_opclasses; - - /* Sort the array of ops into increasing ready cost order. */ - for (i = 0; i < num; i++) - for (j = num - 1; j > i; j--) - if (op_array[j - 1]->ready < op_array[j]->ready) - { - op = op_array[j]; - op_array[j] = op_array[j - 1]; - op_array[j - 1] = op; - } - - /* Determine how many distinct non-default ready cost values there - are. We use a default ready cost value of 1. */ - nvalues = 0; value = 1; - for (i = num - 1; i >= 0; i--) - if (op_array[i]->ready > value) - { - value = op_array[i]->ready; - nvalues++; - } - - if (nvalues == 0) - readycost = make_numeric_value (1); - else - { - /* Construct the ready cost expression as a COND of each value from - the largest to the smallest. */ - readycost = rtx_alloc (COND); - XVEC (readycost, 0) = rtvec_alloc (nvalues * 2); - XEXP (readycost, 1) = make_numeric_value (1); - - nvalues = 0; - orexp = false_rtx; - value = op_array[0]->ready; - for (i = 0; i < num; i++) - { - op = op_array[i]; - if (op->ready <= 1) - break; - else if (op->ready == value) - orexp = insert_right_side (IOR, orexp, op->condexp, -2, -2); - else - { - XVECEXP (readycost, 0, nvalues * 2) = orexp; - XVECEXP (readycost, 0, nvalues * 2 + 1) - = make_numeric_value (value); - nvalues++; - value = op->ready; - orexp = op->condexp; - } - } - XVECEXP (readycost, 0, nvalues * 2) = orexp; - XVECEXP (readycost, 0, nvalues * 2 + 1) = make_numeric_value (value); - } - - if (u < num_units) - { - rtx max_blockage = 0, min_blockage = 0; - - /* Simplify the readycost expression by only considering insns - that use the unit. */ - readycost = simplify_knowing (readycost, unit->condexp); - - /* Determine the blockage cost the executing insn (E) given - the candidate insn (C). This is the maximum of the issue - delay, the pipeline delay, and the simultaneity constraint. - Each function_unit_op represents the characteristics of the - candidate insn, so in the expressions below, C is a known - term and E is an unknown term. - - We compute the blockage cost for each E for every possible C. - Thus OP represents E, and READYCOST is a list of values for - every possible C. - - The issue delay function for C is op->issue_exp and is used to - write the `<name>_unit_conflict_cost' function. Symbolically - this is "ISSUE-DELAY (E,C)". - - The pipeline delay results form the FIFO constraint on the - function unit and is "READY-COST (E) + 1 - READY-COST (C)". - - The simultaneity constraint is based on how long it takes to - fill the unit given the minimum issue delay. FILL-TIME is the - constant "MIN (ISSUE-DELAY (*,*)) * (SIMULTANEITY - 1)", and - the simultaneity constraint is "READY-COST (E) - FILL-TIME" - if SIMULTANEITY is nonzero and zero otherwise. - - Thus, BLOCKAGE (E,C) when SIMULTANEITY is zero is - - MAX (ISSUE-DELAY (E,C), - READY-COST (E) - (READY-COST (C) - 1)) - - and otherwise - - MAX (ISSUE-DELAY (E,C), - READY-COST (E) - (READY-COST (C) - 1), - READY-COST (E) - FILL-TIME) - - The `<name>_unit_blockage' function is computed by determining - this value for each candidate insn. As these values are - computed, we also compute the upper and lower bounds for - BLOCKAGE (E,*). These are combined to form the function - `<name>_unit_blockage_range'. Finally, the maximum blockage - cost, MAX (BLOCKAGE (*,*)), is computed. */ - - for (op = unit->ops; op; op = op->next) - { - rtx blockage = op->issue_exp; - blockage = simplify_knowing (blockage, unit->condexp); - - /* Add this op's contribution to MAX (BLOCKAGE (E,*)) and - MIN (BLOCKAGE (E,*)). */ - if (max_blockage == 0) - max_blockage = min_blockage = blockage; - else - { - max_blockage - = simplify_knowing (operate_exp (MAX_OP, max_blockage, - blockage), - unit->condexp); - min_blockage - = simplify_knowing (operate_exp (MIN_OP, min_blockage, - blockage), - unit->condexp); - } - - /* Make an attribute for use in the blockage function. */ - str = attr_printf ((strlen (unit->name) + sizeof "*_block_" - + MAX_DIGITS), - "*%s_block_%d", unit->name, op->num); - make_internal_attr (str, blockage, ATTR_SPECIAL); - } - - /* Record MAX (BLOCKAGE (*,*)). */ - { - int unknown; - unit->max_blockage = max_attr_value (max_blockage, &unknown); - } - - /* See if the upper and lower bounds of BLOCKAGE (E,*) are the - same. If so, the blockage function carries no additional - information and is not written. */ - newexp = operate_exp (EQ_OP, max_blockage, min_blockage); - newexp = simplify_knowing (newexp, unit->condexp); - unit->needs_blockage_function - = (GET_CODE (newexp) != CONST_STRING - || atoi (XSTR (newexp, 0)) != 1); - - /* If the all values of BLOCKAGE (E,C) have the same value, - neither blockage function is written. */ - unit->needs_range_function - = (unit->needs_blockage_function - || GET_CODE (max_blockage) != CONST_STRING); - - if (unit->needs_range_function) - { - /* Compute the blockage range function and make an attribute - for writing its value. */ - newexp = operate_exp (RANGE_OP, min_blockage, max_blockage); - newexp = simplify_knowing (newexp, unit->condexp); - - str = attr_printf ((strlen (unit->name) - + sizeof "*_unit_blockage_range"), - "*%s_unit_blockage_range", unit->name); - make_internal_attr (str, newexp, (ATTR_STATIC|ATTR_BLOCKAGE|ATTR_UNSIGNED)); - } - - str = attr_printf (strlen (unit->name) + sizeof "*_unit_ready_cost", - "*%s_unit_ready_cost", unit->name); - make_internal_attr (str, readycost, ATTR_STATIC); - } - else - { - /* Make an attribute for the ready_cost function. Simplifying - further with simplify_by_exploding doesn't win. */ - str = "*result_ready_cost"; - make_internal_attr (str, readycost, ATTR_NONE); - } - } - - /* For each unit that requires a conflict cost function, make an attribute - that maps insns to the operation number. */ - for (unit = units; unit; unit = unit->next) - { - rtx caseexp; - - if (! unit->needs_conflict_function - && ! unit->needs_blockage_function) - continue; - - caseexp = rtx_alloc (COND); - XVEC (caseexp, 0) = rtvec_alloc ((unit->num_opclasses - 1) * 2); - - for (op = unit->ops; op; op = op->next) - { - /* Make our adjustment to the COND being computed. If we are the - last operation class, place our values into the default of the - COND. */ - if (op->num == unit->num_opclasses - 1) - { - XEXP (caseexp, 1) = make_numeric_value (op->num); - } - else - { - XVECEXP (caseexp, 0, op->num * 2) = op->condexp; - XVECEXP (caseexp, 0, op->num * 2 + 1) - = make_numeric_value (op->num); - } - } - - /* Simplifying caseexp with simplify_by_exploding doesn't win. */ - str = attr_printf (strlen (unit->name) + sizeof "*_cases", - "*%s_cases", unit->name); - make_internal_attr (str, caseexp, ATTR_SPECIAL); - } -} - -/* Simplify EXP given KNOWN_TRUE. */ - -static rtx -simplify_knowing (rtx exp, rtx known_true) -{ - if (GET_CODE (exp) != CONST_STRING) - { - int unknown = 0, max; - max = max_attr_value (exp, &unknown); - if (! unknown) - { - exp = attr_rtx (IF_THEN_ELSE, known_true, exp, - make_numeric_value (max)); - exp = simplify_by_exploding (exp); - } - } - return exp; -} - -/* Translate the CONST_STRING expressions in X to change the encoding of - value. On input, the value is a bitmask with a one bit for each unit - used; on output, the value is the unit number (zero based) if one - and only one unit is used or the one's complement of the bitmask. */ - -static rtx -encode_units_mask (rtx x) -{ - int i; - int j; - enum rtx_code code; - const char *fmt; - - code = GET_CODE (x); - - switch (code) - { - case CONST_STRING: - i = atoi (XSTR (x, 0)); - if (i < 0) - /* The sign bit encodes a one's complement mask. */ - abort (); - else if (i != 0 && i == (i & -i)) - /* Only one bit is set, so yield that unit number. */ - for (j = 0; (i >>= 1) != 0; j++) - ; - else - j = ~i; - return attr_rtx (CONST_STRING, attr_printf (MAX_DIGITS, "%d", j)); - - case REG: - case CONST_INT: - case CONST_DOUBLE: - case CONST_VECTOR: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case CC0: - case EQ_ATTR: - case EQ_ATTR_ALT: - return x; - - default: - break; - } - - /* Compare the elements. If any pair of corresponding elements - fail to match, return 0 for the whole things. */ - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - switch (fmt[i]) - { - case 'V': - case 'E': - for (j = 0; j < XVECLEN (x, i); j++) - XVECEXP (x, i, j) = encode_units_mask (XVECEXP (x, i, j)); - break; - - case 'e': - XEXP (x, i) = encode_units_mask (XEXP (x, i)); - break; - } - } - return x; -} - /* Once all attributes and insns have been read and checked, we construct for each attribute value a list of all the insns that have that value for the attribute. */ @@ -3715,444 +2950,6 @@ optimize_attrs (void) free (insn_code_values - 2); } -/* If EXP is a suitable expression, reorganize it by constructing an - equivalent expression that is a COND with the tests being all combinations - of attribute values and the values being simple constants. */ - -static rtx -simplify_by_exploding (rtx exp) -{ - rtx list = 0, link, condexp, defval = NULL_RTX; - struct dimension *space; - rtx *condtest, *condval; - int i, j, total, ndim = 0; - int most_tests, num_marks, new_marks; - rtx ret; - - /* Locate all the EQ_ATTR expressions. */ - if (! find_and_mark_used_attributes (exp, &list, &ndim) || ndim == 0) - { - unmark_used_attributes (list, 0, 0); - return exp; - } - - /* Create an attribute space from the list of used attributes. For each - dimension in the attribute space, record the attribute, list of values - used, and number of values used. Add members to the list of values to - cover the domain of the attribute. This makes the expanded COND form - order independent. */ - - space = xmalloc (ndim * sizeof (struct dimension)); - - total = 1; - for (ndim = 0; list; ndim++) - { - /* Pull the first attribute value from the list and record that - attribute as another dimension in the attribute space. */ - const char *name = XSTR (XEXP (list, 0), 0); - rtx *prev; - - space[ndim].attr = find_attr (&name, 0); - XSTR (XEXP (list, 0), 0) = name; - - if (space[ndim].attr == 0 - || space[ndim].attr->is_numeric) - { - unmark_used_attributes (list, space, ndim); - return exp; - } - - /* Add all remaining attribute values that refer to this attribute. */ - space[ndim].num_values = 0; - space[ndim].values = 0; - prev = &list; - for (link = list; link; link = *prev) - if (! strcmp_check (XSTR (XEXP (link, 0), 0), name)) - { - space[ndim].num_values++; - *prev = XEXP (link, 1); - XEXP (link, 1) = space[ndim].values; - space[ndim].values = link; - } - else - prev = &XEXP (link, 1); - - /* Add sufficient members to the list of values to make the list - mutually exclusive and record the total size of the attribute - space. */ - total *= add_values_to_cover (&space[ndim]); - } - - /* Sort the attribute space so that the attributes go from non-constant - to constant and from most values to least values. */ - for (i = 0; i < ndim; i++) - for (j = ndim - 1; j > i; j--) - if ((space[j-1].attr->is_const && !space[j].attr->is_const) - || space[j-1].num_values < space[j].num_values) - { - struct dimension tmp; - tmp = space[j]; - space[j] = space[j - 1]; - space[j - 1] = tmp; - } - - /* Establish the initial current value. */ - for (i = 0; i < ndim; i++) - space[i].current_value = space[i].values; - - condtest = xmalloc (total * sizeof (rtx)); - condval = xmalloc (total * sizeof (rtx)); - - /* Expand the tests and values by iterating over all values in the - attribute space. */ - for (i = 0;; i++) - { - condtest[i] = test_for_current_value (space, ndim); - condval[i] = simplify_with_current_value (exp, space, ndim); - if (! increment_current_value (space, ndim)) - break; - } - if (i != total - 1) - abort (); - - /* We are now finished with the original expression. */ - unmark_used_attributes (0, space, ndim); - free (space); - - /* Find the most used constant value and make that the default. */ - most_tests = -1; - for (i = num_marks = 0; i < total; i++) - if (GET_CODE (condval[i]) == CONST_STRING - && ! ATTR_EQ_ATTR_P (condval[i])) - { - /* Mark the unmarked constant value and count how many are marked. */ - ATTR_EQ_ATTR_P (condval[i]) = 1; - for (j = new_marks = 0; j < total; j++) - if (GET_CODE (condval[j]) == CONST_STRING - && ATTR_EQ_ATTR_P (condval[j])) - new_marks++; - if (new_marks - num_marks > most_tests) - { - most_tests = new_marks - num_marks; - defval = condval[i]; - } - num_marks = new_marks; - } - /* Clear all the marks. */ - for (i = 0; i < total; i++) - ATTR_EQ_ATTR_P (condval[i]) = 0; - - /* Give up if nothing is constant. */ - if (num_marks == 0) - ret = exp; - - /* If all values are the default, use that. */ - else if (total == most_tests) - ret = defval; - - /* Make a COND with the most common constant value the default. (A more - complex method where tests with the same value were combined didn't - seem to improve things.) */ - else - { - condexp = rtx_alloc (COND); - XVEC (condexp, 0) = rtvec_alloc ((total - most_tests) * 2); - XEXP (condexp, 1) = defval; - for (i = j = 0; i < total; i++) - if (condval[i] != defval) - { - XVECEXP (condexp, 0, 2 * j) = condtest[i]; - XVECEXP (condexp, 0, 2 * j + 1) = condval[i]; - j++; - } - ret = condexp; - } - free (condtest); - free (condval); - return ret; -} - -/* Set the ATTR_EQ_ATTR_P flag for all EQ_ATTR expressions in EXP and - verify that EXP can be simplified to a constant term if all the EQ_ATTR - tests have known value. */ - -static int -find_and_mark_used_attributes (rtx exp, rtx *terms, int *nterms) -{ - int i; - - switch (GET_CODE (exp)) - { - case EQ_ATTR: - if (! ATTR_EQ_ATTR_P (exp)) - { - rtx link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = exp; - XEXP (link, 1) = *terms; - *terms = link; - *nterms += 1; - ATTR_EQ_ATTR_P (exp) = 1; - } - return 1; - - case CONST_STRING: - case CONST_INT: - return 1; - - case IF_THEN_ELSE: - if (! find_and_mark_used_attributes (XEXP (exp, 2), terms, nterms)) - return 0; - case IOR: - case AND: - if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms)) - return 0; - case NOT: - if (! find_and_mark_used_attributes (XEXP (exp, 0), terms, nterms)) - return 0; - return 1; - - case COND: - for (i = 0; i < XVECLEN (exp, 0); i++) - if (! find_and_mark_used_attributes (XVECEXP (exp, 0, i), terms, nterms)) - return 0; - if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms)) - return 0; - return 1; - - default: - return 0; - } -} - -/* Clear the ATTR_EQ_ATTR_P flag in all EQ_ATTR expressions on LIST and - in the values of the NDIM-dimensional attribute space SPACE. */ - -static void -unmark_used_attributes (rtx list, struct dimension *space, int ndim) -{ - rtx link, exp; - int i; - - for (i = 0; i < ndim; i++) - unmark_used_attributes (space[i].values, 0, 0); - - for (link = list; link; link = XEXP (link, 1)) - { - exp = XEXP (link, 0); - if (GET_CODE (exp) == EQ_ATTR) - ATTR_EQ_ATTR_P (exp) = 0; - } -} - -/* Update the attribute dimension DIM so that all values of the attribute - are tested. Return the updated number of values. */ - -static int -add_values_to_cover (struct dimension *dim) -{ - struct attr_value *av; - rtx exp, link, *prev; - int nalt = 0; - - for (av = dim->attr->first_value; av; av = av->next) - if (GET_CODE (av->value) == CONST_STRING) - nalt++; - - if (nalt < dim->num_values) - abort (); - else if (nalt == dim->num_values) - /* OK. */ - ; - else if (nalt * 2 < dim->num_values * 3) - { - /* Most all the values of the attribute are used, so add all the unused - values. */ - prev = &dim->values; - for (link = dim->values; link; link = *prev) - prev = &XEXP (link, 1); - - for (av = dim->attr->first_value; av; av = av->next) - if (GET_CODE (av->value) == CONST_STRING) - { - exp = attr_eq (dim->attr->name, XSTR (av->value, 0)); - if (ATTR_EQ_ATTR_P (exp)) - continue; - - link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = exp; - XEXP (link, 1) = 0; - *prev = link; - prev = &XEXP (link, 1); - } - dim->num_values = nalt; - } - else - { - rtx orexp = false_rtx; - - /* Very few values are used, so compute a mutually exclusive - expression. (We could do this for numeric values if that becomes - important.) */ - prev = &dim->values; - for (link = dim->values; link; link = *prev) - { - orexp = insert_right_side (IOR, orexp, XEXP (link, 0), -2, -2); - prev = &XEXP (link, 1); - } - link = rtx_alloc (EXPR_LIST); - XEXP (link, 0) = attr_rtx (NOT, orexp); - XEXP (link, 1) = 0; - *prev = link; - dim->num_values++; - } - return dim->num_values; -} - -/* Increment the current value for the NDIM-dimensional attribute space SPACE - and return FALSE if the increment overflowed. */ - -static int -increment_current_value (struct dimension *space, int ndim) -{ - int i; - - for (i = ndim - 1; i >= 0; i--) - { - if ((space[i].current_value = XEXP (space[i].current_value, 1)) == 0) - space[i].current_value = space[i].values; - else - return 1; - } - return 0; -} - -/* Construct an expression corresponding to the current value for the - NDIM-dimensional attribute space SPACE. */ - -static rtx -test_for_current_value (struct dimension *space, int ndim) -{ - int i; - rtx exp = true_rtx; - - for (i = 0; i < ndim; i++) - exp = insert_right_side (AND, exp, XEXP (space[i].current_value, 0), - -2, -2); - - return exp; -} - -/* Given the current value of the NDIM-dimensional attribute space SPACE, - set the corresponding EQ_ATTR expressions to that value and reduce - the expression EXP as much as possible. On input [and output], all - known EQ_ATTR expressions are set to FALSE. */ - -static rtx -simplify_with_current_value (rtx exp, struct dimension *space, int ndim) -{ - int i; - rtx x; - - /* Mark each current value as TRUE. */ - for (i = 0; i < ndim; i++) - { - x = XEXP (space[i].current_value, 0); - if (GET_CODE (x) == EQ_ATTR) - ATTR_EQ_ATTR_P (x) = 0; - } - - exp = simplify_with_current_value_aux (exp); - - /* Change each current value back to FALSE. */ - for (i = 0; i < ndim; i++) - { - x = XEXP (space[i].current_value, 0); - if (GET_CODE (x) == EQ_ATTR) - ATTR_EQ_ATTR_P (x) = 1; - } - - return exp; -} - -/* Reduce the expression EXP based on the ATTR_EQ_ATTR_P settings of - all EQ_ATTR expressions. */ - -static rtx -simplify_with_current_value_aux (rtx exp) -{ - int i; - rtx cond; - - switch (GET_CODE (exp)) - { - case EQ_ATTR: - if (ATTR_EQ_ATTR_P (exp)) - return false_rtx; - else - return true_rtx; - case CONST_STRING: - case CONST_INT: - return exp; - - case IF_THEN_ELSE: - cond = simplify_with_current_value_aux (XEXP (exp, 0)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XEXP (exp, 1)); - else if (cond == false_rtx) - return simplify_with_current_value_aux (XEXP (exp, 2)); - else - return attr_rtx (IF_THEN_ELSE, cond, - simplify_with_current_value_aux (XEXP (exp, 1)), - simplify_with_current_value_aux (XEXP (exp, 2))); - - case IOR: - cond = simplify_with_current_value_aux (XEXP (exp, 1)); - if (cond == true_rtx) - return cond; - else if (cond == false_rtx) - return simplify_with_current_value_aux (XEXP (exp, 0)); - else - return attr_rtx (IOR, cond, - simplify_with_current_value_aux (XEXP (exp, 0))); - - case AND: - cond = simplify_with_current_value_aux (XEXP (exp, 1)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XEXP (exp, 0)); - else if (cond == false_rtx) - return cond; - else - return attr_rtx (AND, cond, - simplify_with_current_value_aux (XEXP (exp, 0))); - - case NOT: - cond = simplify_with_current_value_aux (XEXP (exp, 0)); - if (cond == true_rtx) - return false_rtx; - else if (cond == false_rtx) - return true_rtx; - else - return attr_rtx (NOT, cond); - - case COND: - for (i = 0; i < XVECLEN (exp, 0); i += 2) - { - cond = simplify_with_current_value_aux (XVECEXP (exp, 0, i)); - if (cond == true_rtx) - return simplify_with_current_value_aux (XVECEXP (exp, 0, i + 1)); - else if (cond == false_rtx) - continue; - else - abort (); /* With all EQ_ATTR's of known value, a case should - have been selected. */ - } - return simplify_with_current_value_aux (XEXP (exp, 1)); - - default: - abort (); - } -} - /* Clear the ATTR_CURR_SIMPLIFIED_P flag in EXP and its subexpressions. */ static void @@ -4454,97 +3251,6 @@ gen_delay (rtx def, int lineno) delays = delay; } -/* Process a DEFINE_FUNCTION_UNIT. - - This gives information about a function unit contained in the CPU. - We fill in a `struct function_unit_op' and a `struct function_unit' - with information used later by `expand_unit'. */ - -static void -gen_unit (rtx def, int lineno) -{ - struct function_unit *unit; - struct function_unit_op *op; - const char *name = XSTR (def, 0); - int multiplicity = XINT (def, 1); - int simultaneity = XINT (def, 2); - rtx condexp = XEXP (def, 3); - int ready_cost = MAX (XINT (def, 4), 1); - int issue_delay = MAX (XINT (def, 5), 1); - - /* See if we have already seen this function unit. If so, check that - the multiplicity and simultaneity values are the same. If not, make - a structure for this function unit. */ - for (unit = units; unit; unit = unit->next) - if (! strcmp (unit->name, name)) - { - if (unit->multiplicity != multiplicity - || unit->simultaneity != simultaneity) - { - message_with_line (lineno, - "differing specifications given for function unit %s", - unit->name); - message_with_line (unit->first_lineno, "previous definition"); - have_error = 1; - return; - } - break; - } - - if (unit == 0) - { - unit = oballoc (sizeof (struct function_unit)); - unit->name = name; - unit->multiplicity = multiplicity; - unit->simultaneity = simultaneity; - unit->issue_delay.min = unit->issue_delay.max = issue_delay; - unit->num = num_units++; - unit->num_opclasses = 0; - unit->condexp = false_rtx; - unit->ops = 0; - unit->next = units; - unit->first_lineno = lineno; - units = unit; - } - else - XSTR (def, 0) = unit->name; - - /* Make a new operation class structure entry and initialize it. */ - op = oballoc (sizeof (struct function_unit_op)); - op->condexp = condexp; - op->num = unit->num_opclasses++; - op->ready = ready_cost; - op->issue_delay = issue_delay; - op->next = unit->ops; - op->lineno = lineno; - unit->ops = op; - num_unit_opclasses++; - - /* Set our issue expression based on whether or not an optional conflict - vector was specified. */ - if (XVEC (def, 6)) - { - /* Compute the IOR of all the specified expressions. */ - rtx orexp = false_rtx; - int i; - - for (i = 0; i < XVECLEN (def, 6); i++) - orexp = insert_right_side (IOR, orexp, XVECEXP (def, 6, i), -2, -2); - - op->conflict_exp = orexp; - extend_range (&unit->issue_delay, 1, issue_delay); - } - else - { - op->conflict_exp = true_rtx; - extend_range (&unit->issue_delay, issue_delay, issue_delay); - } - - /* Merge our conditional into that of the function unit so we can determine - which insns are used by the function unit. */ - unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2); -} - /* Given a piece of RTX, print a C expression to test its truth value. We use AND and IOR both for logical and bit-wise operations, so interpret them as logical unless they are inside a comparison expression. @@ -5041,37 +3747,15 @@ write_attr_get (struct attr_desc *attr) } printf ("{\n"); + printf (" switch (recog_memoized (insn))\n"); + printf (" {\n"); - if (GET_CODE (common_av->value) == FFS) - { - rtx p = XEXP (common_av->value, 0); - - /* No need to emit code to abort if the insn is unrecognized; the - other get_attr_foo functions will do that when we call them. */ - - write_toplevel_expr (p); - - printf ("\n if (accum && accum == (accum & -accum))\n"); - printf (" {\n"); - printf (" int i;\n"); - printf (" for (i = 0; accum >>= 1; ++i) continue;\n"); - printf (" accum = i;\n"); - printf (" }\n else\n"); - printf (" accum = ~accum;\n"); - printf (" return accum;\n}\n\n"); - } - else - { - printf (" switch (recog_memoized (insn))\n"); - printf (" {\n"); - - for (av = attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (attr, av, 1, "return", ";", 4, true_rtx); + for (av = attr->first_value; av; av = av->next) + if (av != common_av) + write_attr_case (attr, av, 1, "return", ";", 4, true_rtx); - write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx); - printf (" }\n}\n\n"); - } + write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx); + printf (" }\n}\n\n"); } /* Given an AND tree of known true terms (because we are inside an `if' with @@ -5307,56 +3991,7 @@ write_expr_attr_cache (rtx p, struct attr_desc *attr) return 0; } -/* Evaluate an expression at top level. A front end to write_test_expr, - in which we cache attribute values and break up excessively large - expressions to cater to older compilers. */ - -static void -write_toplevel_expr (rtx p) -{ - struct attr_desc *attr; - int i; - - for (i = 0; i < MAX_ATTRS_INDEX; ++i) - for (attr = attrs[i]; attr; attr = attr->next) - if (!attr->is_const) - write_expr_attr_cache (p, attr); - - printf (" unsigned long accum = 0;\n\n"); - - while (GET_CODE (p) == IOR) - { - rtx e; - if (GET_CODE (XEXP (p, 0)) == IOR) - e = XEXP (p, 1), p = XEXP (p, 0); - else - e = XEXP (p, 0), p = XEXP (p, 1); - - printf (" accum |= "); - write_test_expr (e, 3); - printf (";\n"); - } - printf (" accum |= "); - write_test_expr (p, 3); - printf (";\n"); -} - -/* Utilities to write names in various forms. */ - -static void -write_unit_name (const char *prefix, int num, const char *suffix) -{ - struct function_unit *unit; - - for (unit = units; unit; unit = unit->next) - if (unit->num == num) - { - printf ("%s%s%s", prefix, unit->name, suffix); - return; - } - - printf ("%s<unknown>%s", prefix, suffix); -} +/* Utilities to write in various forms. */ static void write_attr_valueq (struct attr_desc *attr, const char *s) @@ -5367,32 +4002,7 @@ write_attr_valueq (struct attr_desc *attr, const char *s) printf ("%d", num); - /* Make the blockage range values and function units used values easier - to read. */ - if (attr->func_units_p) - { - if (num == -1) - printf (" /* units: none */"); - else if (num >= 0) - write_unit_name (" /* units: ", num, " */"); - else - { - int i; - const char *sep = " /* units: "; - for (i = 0, num = ~num; num; i++, num >>= 1) - if (num & 1) - { - write_unit_name (sep, i, (num == 1) ? " */" : ""); - sep = ", "; - } - } - } - - else if (attr->blockage_p) - printf (" /* min %d, max %d */", num >> (HOST_BITS_PER_INT / 2), - num & ((1 << (HOST_BITS_PER_INT / 2)) - 1)); - - else if (num > 9 || num < 0) + if (num > 9 || num < 0) printf (" /* 0x%x */", num); } else @@ -5613,175 +4223,6 @@ write_eligible_delay (const char *kind) printf ("}\n\n"); } -/* Write routines to compute conflict cost for function units. Then write a - table describing the available function units. */ - -static void -write_function_unit_info (void) -{ - struct function_unit *unit; - int i; - - /* Write out conflict routines for function units. Don't bother writing - one if there is only one issue delay value. */ - - for (unit = units; unit; unit = unit->next) - { - if (unit->needs_blockage_function) - write_complex_function (unit, "blockage", "block"); - - /* If the minimum and maximum conflict costs are the same, there - is only one value, so we don't need a function. */ - if (! unit->needs_conflict_function) - { - unit->default_cost = make_numeric_value (unit->issue_delay.max); - continue; - } - - /* The function first computes the case from the candidate insn. */ - unit->default_cost = make_numeric_value (0); - write_complex_function (unit, "conflict_cost", "cost"); - } - - /* Now that all functions have been written, write the table describing - the function units. The name is included for documentation purposes - only. */ - - printf ("const struct function_unit_desc function_units[] = {\n"); - - /* Write out the descriptions in numeric order, but don't force that order - on the list. Doing so increases the runtime of genattrtab.c. */ - for (i = 0; i < num_units; i++) - { - for (unit = units; unit; unit = unit->next) - if (unit->num == i) - break; - - printf (" {\"%s\", %d, %d, %d, %s, %d, %s_unit_ready_cost, ", - unit->name, 1 << unit->num, unit->multiplicity, - unit->simultaneity, XSTR (unit->default_cost, 0), - unit->issue_delay.max, unit->name); - - if (unit->needs_conflict_function) - printf ("%s_unit_conflict_cost, ", unit->name); - else - printf ("0, "); - - printf ("%d, ", unit->max_blockage); - - if (unit->needs_range_function) - printf ("%s_unit_blockage_range, ", unit->name); - else - printf ("0, "); - - if (unit->needs_blockage_function) - printf ("%s_unit_blockage", unit->name); - else - printf ("0"); - - printf ("}, \n"); - } - - if (num_units == 0) - printf ("{\"dummy\", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* a dummy element */"); - printf ("};\n\n"); -} - -static void -write_complex_function (struct function_unit *unit, - const char *name, - const char *connection) -{ - struct attr_desc *case_attr, *attr; - struct attr_value *av, *common_av; - rtx value; - char str[256]; - const char *pstr; - int using_case; - int i; - - printf ("static int\n"); - printf ("%s_unit_%s (rtx executing_insn, rtx candidate_insn)\n", - unit->name, name); - printf ("{\n"); - printf (" rtx insn;\n"); - printf (" int casenum;\n\n"); - printf (" insn = executing_insn;\n"); - printf (" switch (recog_memoized (insn))\n"); - printf (" {\n"); - - /* Write the `switch' statement to get the case value. */ - if (strlen (unit->name) + sizeof "*_cases" > 256) - abort (); - sprintf (str, "*%s_cases", unit->name); - pstr = str; - case_attr = find_attr (&pstr, 0); - if (! case_attr) - abort (); - common_av = find_most_used (case_attr); - - for (av = case_attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (case_attr, av, 1, - "casenum =", ";", 4, unit->condexp); - - write_attr_case (case_attr, common_av, 0, - "casenum =", ";", 4, unit->condexp); - printf (" }\n\n"); - - /* Now write an outer switch statement on each case. Then write - the tests on the executing function within each. */ - printf (" insn = candidate_insn;\n"); - printf (" switch (casenum)\n"); - printf (" {\n"); - - for (i = 0; i < unit->num_opclasses; i++) - { - /* Ensure using this case. */ - using_case = 0; - for (av = case_attr->first_value; av; av = av->next) - if (av->num_insns - && contained_in_p (make_numeric_value (i), av->value)) - using_case = 1; - - if (! using_case) - continue; - - printf (" case %d:\n", i); - sprintf (str, "*%s_%s_%d", unit->name, connection, i); - pstr = str; - attr = find_attr (&pstr, 0); - if (! attr) - abort (); - - /* If single value, just write it. */ - value = find_single_value (attr); - if (value) - write_attr_set (attr, 6, value, "return", ";\n", true_rtx, -2, -2); - else - { - common_av = find_most_used (attr); - printf (" switch (recog_memoized (insn))\n"); - printf ("\t{\n"); - - for (av = attr->first_value; av; av = av->next) - if (av != common_av) - write_attr_case (attr, av, 1, - "return", ";", 8, unit->condexp); - - write_attr_case (attr, common_av, 0, - "return", ";", 8, unit->condexp); - printf (" }\n\n"); - } - } - - /* This default case should not be needed, but gcc's analysis is not - good enough to realize that the default case is not needed for the - second switch statement. */ - printf (" default:\n abort ();\n"); - printf (" }\n}\n\n"); -} - /* This page contains miscellaneous utility routines. */ /* Given a pointer to a (char *), return a malloc'ed string containing the @@ -5837,7 +4278,7 @@ find_attr (const char **name_p, int create) attr->name = DEF_ATTR_STRING (name); attr->first_value = attr->default_val = NULL; attr->is_numeric = attr->negative_ok = attr->is_const = attr->is_special = 0; - attr->unsigned_p = attr->func_units_p = attr->blockage_p = attr->static_p = 0; + attr->unsigned_p = attr->static_p = 0; attr->next = attrs[index]; attrs[index] = attr; @@ -5862,8 +4303,6 @@ make_internal_attr (const char *name, rtx value, int special) attr->is_special = (special & ATTR_SPECIAL) != 0; attr->negative_ok = (special & ATTR_NEGATIVE_OK) != 0; attr->unsigned_p = (special & ATTR_UNSIGNED) != 0; - attr->func_units_p = (special & ATTR_FUNC_UNITS) != 0; - attr->blockage_p = (special & ATTR_BLOCKAGE) != 0; attr->static_p = (special & ATTR_STATIC) != 0; attr->default_val = get_attr_value (value, attr, -2); } @@ -5887,28 +4326,6 @@ find_most_used (struct attr_desc *attr) return most_used; } -/* If an attribute only has a single value used, return it. Otherwise - return NULL. */ - -static rtx -find_single_value (struct attr_desc *attr) -{ - struct attr_value *av; - rtx unique_value; - - unique_value = NULL; - for (av = attr->first_value; av; av = av->next) - if (av->num_insns) - { - if (unique_value) - return NULL; - else - unique_value = av->value; - } - - return unique_value; -} - /* Return (attr_value "n") */ rtx @@ -5933,15 +4350,6 @@ make_numeric_value (int n) return exp; } -static void -extend_range (struct range *range, int min, int max) -{ - if (range->min > min) - range->min = min; - if (range->max < max) - range->max = max; -} - static rtx copy_rtx_unchanging (rtx orig) { @@ -6052,10 +4460,6 @@ from the machine description file `md'. */\n\n"); gen_delay (desc, lineno); break; - case DEFINE_FUNCTION_UNIT: - gen_unit (desc, lineno); - break; - case DEFINE_CPU_UNIT: gen_cpu_unit (desc); break; @@ -6128,14 +4532,10 @@ from the machine description file `md'. */\n\n"); if (num_delays) expand_delays (); - if (num_units || num_dfa_decls) - { - /* Expand DEFINE_FUNCTION_UNIT information into new attributes. */ - expand_units (); - /* Build DFA, output some functions and expand DFA information - into new attributes. */ - expand_automata (); - } + /* Build DFA, output some functions and expand DFA information + to new attributes. */ + if (num_dfa_decls) + expand_automata (); printf ("#include \"config.h\"\n"); printf ("#include \"system.h\"\n"); @@ -6191,8 +4591,7 @@ from the machine description file `md'. */\n\n"); optimize_attrs (); /* Now write out all the `gen_attr_...' routines. Do these before the - special routines (specifically before write_function_unit_info), so - that they get defined before they are used. */ + special routines so that they get defined before they are used. */ for (i = 0; i < MAX_ATTRS_INDEX; i++) for (attr = attrs[i]; attr; attr = attr->next) @@ -6224,14 +4623,10 @@ from the machine description file `md'. */\n\n"); write_eligible_delay ("annul_false"); } - if (num_units || num_dfa_decls) - { - /* Write out information about function units. */ - write_function_unit_info (); - /* Output code for pipeline hazards recognition based on DFA - (deterministic finite state automata. */ - write_automata (); - } + /* Output code for pipeline hazards recognition based on DFA + (deterministic finite-state automata). */ + if (num_dfa_decls) + write_automata (); /* Write out constant delay slot info. */ write_const_num_delay_slots (); |