From 346a3d6c11e5dd2ef80d345f2ee8f231e1080efc Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Tue, 14 Apr 1998 00:00:15 +0000 Subject: [PATCH] Add support for instruction word conditionals of the form `XXX!YYY' and XXX=YYY'. See mn10300 for examples. --- sim/igen/ChangeLog | 38 +++++++ sim/igen/gen.c | 241 +++++++++++++++++++++++++++++++++++++-------- sim/igen/igen.c | 29 ++++-- sim/igen/igen.h | 2 + sim/igen/ld-insn.c | 197 ++++++++++++++++++++++++++++++------ 5 files changed, 428 insertions(+), 79 deletions(-) diff --git a/sim/igen/ChangeLog b/sim/igen/ChangeLog index c62353b0e75..537c7864e7a 100644 --- a/sim/igen/ChangeLog +++ b/sim/igen/ChangeLog @@ -1,3 +1,41 @@ +Tue Apr 14 08:44:53 1998 Andrew Cagney + + * igen.h (struct igen_trace_options): Add members insn_expansion + and insn_insertion. + + * igen.c (main): Add options -Gtrace-insn-expansion, + -Gtrace-insn-insertion and -Gtrace-all. + + * gen.c (gen_entry_expand_insns): Trace each instruction as it is + selected for expansion. + (gen_entry_expand_opcode): Trace each expanded instruction as it + is inserted into the table. + +Mon Apr 13 19:21:47 1998 Andrew Cagney + + * ld-insn.c (parse_insn_word): Parse conditional operators. + (parse_insn_word): Verify field conditionals. + + * ld-insn.h: Extend syntax to allow macros and field equality. + (struct insn_field_cond): Rename insn_field_exclusion, add type. + + * gen.c (gen_entry_expand_opcode): Check type of conditional. + (insns_bit_useless): Ditto. + + * ld-insn.c (parse_macro_record): New function. + +Mon Apr 13 22:37:47 1998 Andrew Cagney + + * ld-insn.h (enum insn_field_type): Add insn_field_invalid. + + * ld-insn.c (parse_insn_word): Check instruction field type + correctly initialized. + (print_insn_words): Ditto. + (insn_field_type_to_str): Ditto. + (dump_insn_field): Ditto. + + * gen.c (insns_bit_useless): Ditto. + Fri Apr 3 18:08:16 1998 Andrew Cagney * gen.h, igen.c (print_include_inline, print_includes, diff --git a/sim/igen/gen.c b/sim/igen/gen.c index 927f16500ad..f630b9f1739 100644 --- a/sim/igen/gen.c +++ b/sim/igen/gen.c @@ -73,8 +73,8 @@ print_gen_entry_path (line_ref *line, { if (table->parent == NULL) { - if (table->top->processor != NULL) - print (line, "%s", table->top->processor); + if (table->top->model != NULL) + print (line, "%s", table->top->model->name); else print (line, ""); } @@ -282,9 +282,9 @@ insn_list_insert (insn_list **cur_insn_ptr, /* two instructions with the same constant field values across all words and bits */ warning (insn->line, - "Location of second (duplicated?) instruction"); + "Two instructions with identical constant fields\n"); error ((*cur_insn_ptr)->insn->line, - "Two instructions with identical constant fields\n"); + "Location of second (duplicated?) instruction\n"); case merge_duplicate_insns: /* Add the opcode path to the instructions list */ if (opcodes != NULL) @@ -382,19 +382,19 @@ gen_entry_traverse_tree (lf *file, static gen_list * make_table (insn_table *isa, decode_table *rules, - char *processor) + model_entry *model) { insn_entry *insn; gen_list *entry = ZALLOC (gen_list); entry->table = ZALLOC (gen_entry); entry->table->top = entry; - entry->processor = processor; + entry->model = model; entry->isa = isa; for (insn = isa->insns; insn != NULL; insn = insn->next) { - if (processor == NULL + if (model == NULL || insn->processors == NULL - || filter_is_member (insn->processors, processor)) + || filter_is_member (insn->processors, model->name)) { insn_list_insert (&entry->table->insns, &entry->table->nr_insns, @@ -420,18 +420,21 @@ make_gen_tables (insn_table *isa, if (options.gen.multi_sim) { gen_list **last = &gen->tables; - char *processor; + model_entry *model; filter *processors; if (options.model_filter != NULL) processors = options.model_filter; else processors = isa->model->processors; - for (processor = filter_next (processors, ""); - processor != NULL; - processor = filter_next (processors, processor)) + for (model = isa->model->models; + model != NULL; + model = model->next) { - *last = make_table (isa, rules, processor); - last = &(*last)->next; + if (filter_is_member (processors, model->name)) + { + *last = make_table (isa, rules, model); + last = &(*last)->next; + } } } else @@ -495,12 +498,18 @@ insns_bit_useless (insn_list *insns, insn_list *entry; int value = -1; int is_useless = 1; /* cleared if something actually found */ + + /* check the instructions for some constant value in at least one of + the bit fields */ for (entry = insns; entry != NULL; entry = entry->next) { insn_word_entry *word = entry->insn->word[rule->word_nr]; insn_bit_entry *bit = word->bit[bit_nr]; switch (bit->field->type) { + case insn_field_invalid: + ASSERT (0); + break; case insn_field_wild: case insn_field_reserved: /* neither useless or useful - ignore */ @@ -514,7 +523,9 @@ insns_bit_useless (insn_list *insns, case decode_find_constants: case decode_find_mixed: /* an integer is useful if its value isn't the same - between all instructions? */ + between all instructions. The first time through the + value is saved, the second time through (if the + values differ) it is marked as useful. */ if (value < 0) value = bit->value; else if (value != bit->value) @@ -531,9 +542,9 @@ insns_bit_useless (insn_list *insns, break; case decode_find_constants: case decode_find_mixed: - /* a string field forced to constant */ if (filter_is_member (rule->constant_field_names, bit->field->val_string)) + /* a string field forced to constant? */ is_useless = 0; else if (rule->search == decode_find_constants) /* the string field isn't constant */ @@ -542,6 +553,77 @@ insns_bit_useless (insn_list *insns, } } } + + /* Given only one constant value has been found, check through all + the instructions to see if at least one conditional makes it + usefull */ + if (value >= 0 && is_useless) + { + for (entry = insns; entry != NULL; entry = entry->next) + { + insn_word_entry *word = entry->insn->word[rule->word_nr]; + insn_bit_entry *bit = word->bit[bit_nr]; + switch (bit->field->type) + { + case insn_field_invalid: + ASSERT (0); + break; + case insn_field_wild: + case insn_field_reserved: + case insn_field_int: + /* already processed */ + break; + case insn_field_string: + switch (rule->search) + { + case decode_find_strings: + case decode_find_constants: + /* already processed */ + break; + case decode_find_mixed: + /* string field with conditions. If this condition + eliminates the value then the compare is useful */ + if (bit->field->conditions != NULL) + { + insn_field_cond *condition; + int shift = bit->field->last - bit_nr; + for (condition = bit->field->conditions; + condition != NULL; + condition = condition->next) + { + printf ("useless %s%s\n", + (condition->type == insn_field_cond_eq ? "=" : "!"), + condition->string); + switch (condition->type) + { + case insn_field_cond_value: + switch (condition->test) + { + case insn_field_cond_ne: + if (((condition->value >> shift) & 1) == value) + /* conditional field excludes the + current value */ + is_useless = 0; + break; + case insn_field_cond_eq: + if (((condition->value >> shift) & 1) != value) + /* conditional field requires the + current value */ + is_useless = 0; + break; + } + break; + case insn_field_cond_field: + /* are these handled separatly? */ + break; + } + } + } + } + } + } + } + return is_useless; } @@ -753,6 +835,15 @@ gen_entry_expand_opcode (gen_entry *table, { /* Only include the hardwired bit information with an entry IF that entry (and hence its functions) are being duplicated. */ + if (options.trace.insn_expansion) + { + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, ": insert %d - %s.%s%s\n", + opcode_nr, + instruction->format_name, + instruction->name, + (table->opcode_rule->with_duplicates ? " (duplicated)" : "")); + } if (table->opcode_rule->with_duplicates) { gen_entry_insert_insn (table, instruction, @@ -762,6 +853,10 @@ gen_entry_expand_opcode (gen_entry *table, } else { + if (options.trace.insn_insertion) + { + + } gen_entry_insert_insn (table, instruction, table->opcode->word_nr, table->nr_prefetched_words, @@ -773,9 +868,11 @@ gen_entry_expand_opcode (gen_entry *table, insn_word_entry *word = instruction->word[table->opcode->word_nr]; insn_field_entry *field = word->bit[bit_nr]->field; int last_pos = ((field->last < table->opcode->last) - ? field->last : table->opcode->last); + ? field->last + : table->opcode->last); int first_pos = ((field->first > table->opcode->first) - ? field->first : table->opcode->first); + ? field->first + : table->opcode->first); int width = last_pos - first_pos + 1; switch (field->type) { @@ -800,21 +897,77 @@ gen_entry_expand_opcode (gen_entry *table, { int val; int last_val = (table->opcode->is_boolean - ? 2 : (1 << width)); + ? 2 + : (1 << width)); for (val = 0; val < last_val; val++) { - /* check to see if the value has been limited */ - insn_field_exclusion *exclusion; - for (exclusion = field->exclusions; - exclusion != NULL; - exclusion = exclusion->next) + /* check to see if the value has been precluded + (by a conditional) in some way */ + int is_precluded; + insn_field_cond *condition; + for (condition = field->conditions, is_precluded = 0; + condition != NULL && !is_precluded; + condition = condition->next) { - int value = sub_val (exclusion->value, field, - first_pos, last_pos); - if (value == val) - break; + switch (condition->type) + { + case insn_field_cond_value: + { + int value = sub_val (condition->value, field, + first_pos, last_pos); + switch (condition->test) + { + case insn_field_cond_ne: + if (value == val) + is_precluded = 1; + break; + case insn_field_cond_eq: + if (value != val) + is_precluded = 1; + break; + } + break; + } + case insn_field_cond_field: + { + int value; + /* Find a value for the conditional by + looking back through the previously + defined bits for the specified + conditonal field */ + opcode_bits *bit = bits; + for (bit = bits; + bit != NULL; + bit = bit->next) + { + if (bit->field == condition->field + && (bit->last - bit->first + 1 == condition->field->width)) + /* the bit field fully specified + the conditional field's value */ + break; + } + if (bit == NULL) + error (instruction->line, + "Conditional `%s' of field `%s' isn't expanded", + condition->string, field->val_string); + value = sub_val (bit->value, field, + first_pos, last_pos); + switch (condition->test) + { + case insn_field_cond_ne: + if (value == val) + is_precluded = 1; + break; + case insn_field_cond_eq: + if (value != val) + is_precluded = 1; + break; + } + break; + } + } } - if (exclusion == NULL) + if (!is_precluded) { /* Only add additional hardwired bit information if the entry is not going to @@ -985,10 +1138,10 @@ gen_entry_expand_insns (gen_entry *table) opcode_rule = opcode_rule->next) { char *discard_reason; - if (table->top->processor != NULL + if (table->top->model != NULL && opcode_rule->model_names != NULL && !filter_is_member (opcode_rule->model_names, - table->top->processor)) + table->top->model->name)) { /* the rule isn't applicable to this processor */ discard_reason = "wrong model"; @@ -1075,15 +1228,7 @@ gen_entry_expand_insns (gen_entry *table) table->opcode->parent = table->parent->opcode; } - /* expand the raw instructions according to the opcode */ - { - insn_list *entry; - for (entry = table->insns; entry != NULL; entry = entry->next) - { - gen_entry_insert_expanding (table, entry->insn); - } - } - + /* report the rule being used to expand the instructions */ if (options.trace.rule_selection) { print_gen_entry_path (table->opcode_rule->line, table, notify); @@ -1098,6 +1243,22 @@ gen_entry_expand_insns (gen_entry *table) table->nr_entries); } + /* expand the raw instructions according to the opcode */ + { + insn_list *entry; + for (entry = table->insns; entry != NULL; entry = entry->next) + { + if (options.trace.insn_expansion) + { + print_gen_entry_path (table->opcode_rule->line, table, notify); + notify (NULL, ": expand - %s.%s\n", + entry->insn->format_name, + entry->insn->name); + } + gen_entry_insert_expanding (table, entry->insn); + } + } + /* dump the results */ if (options.trace.entries) { diff --git a/sim/igen/igen.c b/sim/igen/igen.c index fd9b20d9360..4a95f2fbb63 100644 --- a/sim/igen/igen.c +++ b/sim/igen/igen.c @@ -1101,14 +1101,17 @@ main (int argc, printf ("\t trace-entries - report entries after a rules application\n"); printf ("\t trace-rule-rejection - report each rule as rejected\n"); printf ("\t trace-rule-selection - report each rule as selected\n"); + printf ("\t trace-insn-insertion - report each instruction as it is inserted into a decode table\n"); + printf ("\t trace-rule-expansion - report each instruction as it is expanded (before insertion into a decode table)\n"); + printf ("\t trace-all - enable all trace options\n"); printf ("\n"); - printf ("\t field-widths - instruction formats specify widths (depreciated)\n"); - printf ("\t By default, an instruction format specifies bit\n"); - printf ("\t positions\n"); - printf ("\t This option can now be set directly in the\n"); - printf ("\t instruction table\n"); - printf ("\t jumps - use jumps instead of function calls\n"); - printf ("\t omit-line-numbers - do not include line number information in the output\n"); + printf ("\t field-widths - instruction formats specify widths (depreciated)\n"); + printf ("\t By default, an instruction format specifies bit\n"); + printf ("\t positions\n"); + printf ("\t This option can now be set directly in the\n"); + printf ("\t instruction table\n"); + printf ("\t jumps - use jumps instead of function calls\n"); + printf ("\t omit-line-numbers - do not include line number information in the output\n"); printf ("\n"); printf ("Input options:\n"); printf ("\n"); @@ -1426,6 +1429,10 @@ main (int argc, { options.gen.nia = nia_is_void; } + else if (strcmp (argp, "trace-all") == 0) + { + memset (&options.trace, enable_p, sizeof (options.trace)); + } else if (strcmp (argp, "trace-combine") == 0) { options.trace.combine = enable_p; @@ -1442,6 +1449,14 @@ main (int argc, { options.trace.rule_selection = enable_p; } + else if (strcmp (argp, "trace-insn-insertion") == 0) + { + options.trace.insn_insertion = enable_p; + } + else if (strcmp (argp, "trace-insn-expansion") == 0) + { + options.trace.insn_expansion = enable_p; + } else if (strcmp (argp, "jumps") == 0) { options.gen.code = generate_jumps; diff --git a/sim/igen/igen.h b/sim/igen/igen.h index 7aa70efc007..6977e0674ea 100644 --- a/sim/igen/igen.h +++ b/sim/igen/igen.h @@ -86,6 +86,8 @@ typedef struct _igen_trace_options igen_trace_options; struct _igen_trace_options { int rule_selection; int rule_rejection; + int insn_insertion; + int insn_expansion; int entries; int combine; }; diff --git a/sim/igen/ld-insn.c b/sim/igen/ld-insn.c index ca573069330..2fc6cf3187f 100644 --- a/sim/igen/ld-insn.c +++ b/sim/igen/ld-insn.c @@ -118,36 +118,69 @@ parse_insn_word (line_ref *line, if (strlen_val == 0) error (line, "Empty value field\n"); - /* break out any conditional fields - { "!" } */ - while (*chp == '!') + /* break out any conditional fields - { [ "!" | "=" [ | } */ + while (*chp == '!' || *chp == '=') { char *start; + char *end; int len; - insn_field_exclusion *new_exclusion = ZALLOC (insn_field_exclusion); - insn_field_exclusion **last; + insn_field_cond *new_cond = ZALLOC (insn_field_cond); + insn_field_cond **last; - /* what type of conditional field */ + /* determine the conditional test */ + switch (*chp) + { + case '=': + new_cond->test = insn_field_cond_eq; + break; + case '!': + new_cond->test = insn_field_cond_ne; + break; + default: + ASSERT (0); + } + + /* save the value */ chp++; chp = skip_spaces (chp); - /* the value */ start = chp; - chp = skip_digits (chp); - len = chp - start; + chp = skip_to_separator (chp, "+,:"); + end = back_spaces (start, chp); + len = end - start; if (len == 0) error (line, "Missing or invalid conditional value\n"); - /* fill in the entry */ - new_exclusion->string = NZALLOC (char, len + 1); - strncpy (new_exclusion->string, start, len); - new_exclusion->value = a2i (new_exclusion->string); + new_cond->string = NZALLOC (char, len + 1); + strncpy (new_cond->string, start, len); + + /* determine the conditional type */ + if (isdigit (*start)) + { + /* [ "!" | "=" ] */ + new_cond->type = insn_field_cond_value; + new_cond->value = a2i (new_cond->string); + } + else + { + /* [ "!" | "=" ] - check field valid */ + new_cond->type = insn_field_cond_field; + /* new_cond->field is determined in later */ + } + + /* Only a single `=' is permitted. */ + if ((new_cond->test == insn_field_cond_eq + && new_field->conditions != NULL) + || (new_field->conditions != NULL + && new_field->conditions->test == insn_field_cond_eq)) + error (line, "Only single conditional when `=' allowed\n"); + /* insert it */ - last = &new_field->exclusions; + last = &new_field->conditions; while (*last != NULL) last = &(*last)->next; - *last = new_exclusion; - chp = skip_spaces (chp); + *last = new_cond; } - /* NOW verify that the field ws finished */ + /* NOW verify that the field was finished */ if (*chp == ',') { chp = skip_spaces (chp + 1); @@ -156,7 +189,7 @@ parse_insn_word (line_ref *line, } else if (*chp != '\0') { - error (line, "Missing field separator"); + error (line, "Missing field separator\n"); } /* copy the value */ @@ -203,8 +236,8 @@ parse_insn_word (line_ref *line, filter_parse (&word->field_names, new_field->val_string); } if (new_field->type != insn_field_string - && new_field->exclusions != NULL) - error (line, "Exclusions only apply to name fields\n"); + && new_field->conditions != NULL) + error (line, "Conditionals can only be applied to named fields\n"); /* the copy the position */ new_field->pos_string = NZALLOC (char, strlen_pos + 1); @@ -281,6 +314,9 @@ parse_insn_word (line_ref *line, word->bit[i]->field = field; switch (field->type) { + case insn_field_invalid: + ASSERT (0); + break; case insn_field_int: word->bit[i]->mask = 1; word->bit[i]->value = ((field->val_int @@ -295,6 +331,51 @@ parse_insn_word (line_ref *line, } } + /* go over all fields that have conditionals refering to other + fields. Link the fields up. Verify that the two fields have the + same size. Verify that the two fields are different */ + { + insn_field_entry *f; + for (f = word->first; + f->last < options.insn_bit_size; + f = f->next) + { + insn_field_cond *cond; + for (cond = f->conditions; + cond != NULL; + cond = cond->next) + { + if (cond->type == insn_field_cond_field) + { + insn_field_entry *field; + if (strcmp (cond->string, f->val_string) == 0) + error (line, "Conditional of field `%s' refers to its self\n", + f->val_string); + for (field = word->first; + field != NULL; + field = field->next) + { + if (field->type == insn_field_string + && strcmp (field->val_string, cond->string) == 0) + { + /* found field being refered to by conditonal */ + cond->field = field; + /* check refered to and this field are the + same size */ + if (f->width != field->width) + error (line, "Conditional `%s' of field `%s' has different size\n", + field->width, f->width); + break; + } + } + if (cond->field == NULL) + error (line, "Condition field refers to non-existant field `%s'\n", + cond->string); + } + } + } + } + return word; } @@ -635,7 +716,8 @@ parse_function_record (table *file, table_entry *record, function_entry **list, function_entry **list_entry, - int is_internal) + int is_internal, + model_table *model) { function_entry *new_function; new_function = ZALLOC (function_entry); @@ -669,8 +751,12 @@ parse_function_record (table *file, while (record != NULL && record_prefix_is (record, '*', nr_function_model_fields)) { - filter_parse (&new_function->models, - record->field[function_model_name_field] + 1 /*skip `*'*/); + char *model_name = record->field[function_model_name_field] + 1; /*skip `*'*/ + filter_parse (&new_function->models, model_name); + if (!filter_is_subset (model->processors, new_function->models)) + { + error (record->line, "machine model `%s' undefined\n", model_name); + } record = table_read (file); } /* parse the function body */ @@ -683,12 +769,15 @@ parse_function_record (table *file, if (!filter_is_subset (options.flags_filter, new_function->flags)) { if (options.warn.discard) - notify (new_function->line, "Discarding function entry - filter flags\n"); + notify (new_function->line, "Discarding function %s - filter flags\n", + new_function->name); } - else if (!filter_is_subset (options.model_filter, new_function->models)) + else if (new_function->models != NULL + && !filter_is_common (options.model_filter, new_function->models)) { if (options.warn.discard) - notify (new_function->line, "Discarding function entry - filter models\n"); + notify (new_function->line, "Discarding function %s - filter models\n", + new_function->name); } else { @@ -803,6 +892,34 @@ parse_insn_mnemonic_record (table *file, } +static table_entry * +parse_macro_record (table *file, + table_entry *record) +{ +#if 1 + error (record->line, "Macros are not implemented"); +#else + /* parse the define record */ + if (record->nr_fields < nr_define_fields) + error (record->line, "Incorrect nr fields for define record\n"); + /* process it */ + if (!is_filtered_out (options.flags_filter, + record->field[record_filter_flags_field]) + && !is_filtered_out (options.model_filter, + record->field[record_filter_models_field])) + { + table_define (file, + record->line, + record->field[macro_name_field], + record->field[macro_args_field], + record->field[macro_expr_field]); + } + record = table_read (file); +#endif + return record; +} + + insn_table * load_insn_table (char *file_name, cache_entry *cache) @@ -842,7 +959,8 @@ load_insn_table (char *file_name, record = parse_function_record (file, record, &isa->functions, &function, - 0/*is-internal*/); + 0/*is-internal*/, + model); /* convert a string function record into an internal function */ if (function != NULL) { @@ -863,7 +981,8 @@ load_insn_table (char *file_name, record = parse_function_record (file, record, &isa->functions, NULL, - 0/*is-internal*/); + 0/*is-internal*/, + model); break; } @@ -874,7 +993,8 @@ load_insn_table (char *file_name, record = parse_function_record (file, record, &isa->functions, &function, - 1/*is-internal*/); + 1/*is-internal*/, + model); /* check what was inserted to see if a pseudo-instruction entry also needs to be created */ if (function != NULL) @@ -1015,21 +1135,24 @@ load_insn_table (char *file_name, record = parse_function_record (file, record, &model->statics, NULL, - 0/*is internal*/); + 0/*is internal*/, + model); break; case model_internal_record: record = parse_function_record (file, record, &model->internals, NULL, - 1/*is internal*/); + 1/*is internal*/, + model); break; case model_function_record: record = parse_function_record (file, record, &model->functions, NULL, - 0/*is internal*/); + 0/*is internal*/, + model); break; case insn_record: /* instruction records */ @@ -1118,8 +1241,11 @@ load_insn_table (char *file_name, break; } - case unknown_record: case define_record: + record = parse_macro_record (file, record); + break; + + case unknown_record: case code_record: error (record->line, "Unknown or unexpected entry\n"); @@ -1148,6 +1274,9 @@ print_insn_words (lf *file, lf_printf (file, "%d.", i2target (options.hi_bit_nr, field->first)); switch (field->type) { + case insn_field_invalid: + ASSERT (0); + break; case insn_field_int: lf_printf (file, "0x%lx", (long) field->val_int); break; @@ -1397,6 +1526,7 @@ insn_field_type_to_str (insn_field_type type) { switch (type) { + case insn_field_invalid: ASSERT (0); return "(invalid)"; case insn_field_int: return "int"; case insn_field_reserved: return "reserved"; case insn_field_wild: return "wild"; @@ -1423,6 +1553,9 @@ dump_insn_field (lf *file, lf_printf (file, "%s(type %s)", sep, insn_field_type_to_str (field->type)); switch (field->type) { + case insn_field_invalid: + ASSERT (0); + break; case insn_field_int: lf_printf (file, "%s(val 0x%lx)", sep, (long) field->val_int); break; -- 2.30.2