#include "misc.h"
#include "lf.h"
#include "table.h"
#include "filter.h"
#include "igen.h"
#include "ld-insn.h"
#include "ld-decode.h"
#include "gen.h"
static insn_uint
sub_val (insn_uint val, int val_last_pos, int first_pos, int last_pos)
{
return ((val >> (val_last_pos - last_pos))
& (((insn_uint) 1 << (last_pos - first_pos + 1)) - 1));
}
static void
update_depth (lf *file, gen_entry *entry, int depth, void *data)
{
int *max_depth = (int *) data;
if (*max_depth < depth)
*max_depth = depth;
}
int
gen_entry_depth (gen_entry *table)
{
int depth = 0;
gen_entry_traverse_tree (NULL, table, 1, NULL,
update_depth, NULL,
&depth);
return depth;
}
static void
print_gen_entry_path (line_ref *line, gen_entry *table, error_func *print)
{
if (table->parent == NULL)
{
if (table->top->model != NULL)
print (line, "%s", table->top->model->name);
else
print (line, "");
}
else
{
print_gen_entry_path (line, table->parent, print);
print (NULL, ".%d", table->opcode_nr);
}
}
static void
print_gen_entry_insns (gen_entry *table,
error_func *print,
char *first_message, char *next_message)
{
insn_list *i;
char *message;
message = first_message;
for (i = table->insns; i != NULL; i = i->next)
{
insn_entry *insn = i->insn;
print_gen_entry_path (insn->line, table, print);
print (NULL, ": %s.%s %s\n", insn->format_name, insn->name, message);
if (next_message != NULL)
message = next_message;
}
}
static int
insn_field_cmp (insn_word_entry *l, insn_word_entry *r)
{
while (1)
{
int bit_nr;
if (l == NULL && r == NULL)
return 0;
if (l == NULL)
return -1;
if (r == NULL)
return +1;
for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
{
if (l->bit[bit_nr]->field->type != insn_field_string)
continue;
if (r->bit[bit_nr]->field->type != insn_field_string)
continue;
if (l->bit[bit_nr]->field->conditions == NULL)
continue;
if (r->bit[bit_nr]->field->conditions == NULL)
continue;
if (0)
printf ("%s%s%s VS %s%s%s\n",
l->bit[bit_nr]->field->val_string,
l->bit[bit_nr]->field->conditions->test ==
insn_field_cond_eq ? "=" : "!",
l->bit[bit_nr]->field->conditions->string,
r->bit[bit_nr]->field->val_string,
r->bit[bit_nr]->field->conditions->test ==
insn_field_cond_eq ? "=" : "!",
r->bit[bit_nr]->field->conditions->string);
if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq
&& r->bit[bit_nr]->field->conditions->test ==
insn_field_cond_eq)
{
if (l->bit[bit_nr]->field->conditions->type ==
insn_field_cond_field
&& r->bit[bit_nr]->field->conditions->type ==
insn_field_cond_field)
{
int cmp = strcmp (l->bit[bit_nr]->field->conditions->string,
r->bit[bit_nr]->field->conditions->
string);
if (cmp != 0)
return cmp;
else
continue;
}
if (l->bit[bit_nr]->field->conditions->type ==
insn_field_cond_field)
return +1;
if (r->bit[bit_nr]->field->conditions->type ==
insn_field_cond_field)
return -1;
continue;
}
if (l->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
return +1;
if (r->bit[bit_nr]->field->conditions->test == insn_field_cond_eq)
return -1;
continue;
}
l = l->next;
r = r->next;
}
}
static int
insn_word_cmp (insn_word_entry *l, insn_word_entry *r)
{
while (1)
{
int bit_nr;
if (l == NULL && r == NULL)
return 0;
if (l == NULL)
return -1;
if (r == NULL)
return +1;
for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
{
if (l->bit[bit_nr]->mask < r->bit[bit_nr]->mask)
return -1;
if (l->bit[bit_nr]->mask > r->bit[bit_nr]->mask)
return 1;
if (l->bit[bit_nr]->value < r->bit[bit_nr]->value)
return -1;
if (l->bit[bit_nr]->value > r->bit[bit_nr]->value)
return 1;
}
l = l->next;
r = r->next;
}
}
static int
opcode_bit_cmp (opcode_bits *l, opcode_bits *r)
{
if (l == NULL && r == NULL)
return 0;
if (l == NULL)
return -1;
if (r == NULL)
return +1;
if (l->field->word_nr < r->field->word_nr)
return +1;
if (l->field->word_nr > r->field->word_nr)
return -1;
if (l->first < r->first)
return +1;
if (l->first > r->first)
return -1;
if (l->last < r->last)
return +1;
if (l->last > r->last)
return -1;
if (l->value < r->value)
return -1;
if (l->value > r->value)
return 1;
return 0;
}
static int
opcode_bits_cmp (opcode_bits *l, opcode_bits *r)
{
while (1)
{
int cmp;
if (l == NULL && r == NULL)
return 0;
cmp = opcode_bit_cmp (l, r);
if (cmp != 0)
return cmp;
l = l->next;
r = r->next;
}
}
static opcode_bits *
new_opcode_bits (opcode_bits *old_bits,
int value,
int first,
int last, insn_field_entry *field, opcode_field *opcode)
{
opcode_bits *new_bits = ZALLOC (opcode_bits);
new_bits->field = field;
new_bits->value = value;
new_bits->first = first;
new_bits->last = last;
new_bits->opcode = opcode;
if (old_bits != NULL)
{
opcode_bits *new_list;
opcode_bits **last = &new_list;
new_list = new_opcode_bits (old_bits->next,
old_bits->value,
old_bits->first,
old_bits->last,
old_bits->field, old_bits->opcode);
while (*last != NULL)
{
int cmp = opcode_bit_cmp (new_bits, *last);
if (cmp < 0)
{
break;
}
if (cmp == 0)
{
ERROR ("Duplicated insn bits in list");
}
last = &(*last)->next;
}
new_bits->next = *last;
*last = new_bits;
return new_list;
}
else
{
return new_bits;
}
}
static int
name_cmp (const char *l, const char *r)
{
if (l == NULL && r == NULL)
return 0;
if (l != NULL && r == NULL)
return -1;
if (l == NULL && r != NULL)
return +1;
return strcmp (l, r);
}
typedef enum
{
merge_duplicate_insns,
report_duplicate_insns,
}
duplicate_insn_actions;
static insn_list *
insn_list_insert (insn_list **cur_insn_ptr,
int *nr_insns,
insn_entry * insn,
opcode_bits *expanded_bits,
opcode_field *opcodes,
int nr_prefetched_words,
duplicate_insn_actions duplicate_action)
{
for (; (*cur_insn_ptr) != NULL; cur_insn_ptr = &(*cur_insn_ptr)->next)
{
int cmp;
cmp = insn_word_cmp (insn->words, (*cur_insn_ptr)->insn->words);
if (cmp < 0)
break;
else if (cmp > 0)
continue;
cmp = opcode_bits_cmp (expanded_bits, (*cur_insn_ptr)->expanded_bits);
if (cmp < 0)
break;
else if (cmp > 0)
continue;
cmp = insn_field_cmp (insn->words, (*cur_insn_ptr)->insn->words);
if (cmp < 0)
break;
else if (cmp > 0)
continue;
if (duplicate_action == merge_duplicate_insns)
{
int cmp = name_cmp (insn->format_name,
(*cur_insn_ptr)->insn->format_name);
if (cmp < 0)
break;
else if (cmp > 0)
continue;
}
if (duplicate_action == merge_duplicate_insns)
{
int cmp = name_cmp (insn->name, (*cur_insn_ptr)->insn->name);
if (cmp < 0)
break;
else if (cmp > 0)
continue;
}
switch (duplicate_action)
{
case report_duplicate_insns:
warning (insn->line,
"Two instructions with identical constant fields\n");
error ((*cur_insn_ptr)->insn->line,
"Location of duplicate instruction\n");
case merge_duplicate_insns:
if (options.trace.insn_insertion)
{
notify ((*cur_insn_ptr)->insn->line,
"%s.%s: insert merge %s.%s\n",
(*cur_insn_ptr)->insn->format_name,
(*cur_insn_ptr)->insn->name,
insn->format_name,
insn->name);
}
if (opcodes != NULL)
{
insn_opcodes **last = &(*cur_insn_ptr)->opcodes;
while (*last != NULL)
{
last = &(*last)->next;
}
(*last) = ZALLOC (insn_opcodes);
(*last)->opcode = opcodes;
}
if ((*cur_insn_ptr)->nr_prefetched_words < nr_prefetched_words)
(*cur_insn_ptr)->nr_prefetched_words = nr_prefetched_words;
return (*cur_insn_ptr);
}
}
{
insn_list *new_insn = ZALLOC (insn_list);
if (options.trace.insn_insertion)
{
notify (insn->line,
"%s.%s: insert new\n",
insn->format_name,
insn->name);
}
new_insn->insn = insn;
new_insn->expanded_bits = expanded_bits;
new_insn->next = (*cur_insn_ptr);
new_insn->nr_prefetched_words = nr_prefetched_words;
if (opcodes != NULL)
{
new_insn->opcodes = ZALLOC (insn_opcodes);
new_insn->opcodes->opcode = opcodes;
}
(*cur_insn_ptr) = new_insn;
}
*nr_insns += 1;
return (*cur_insn_ptr);
}
extern void
gen_entry_traverse_tree (lf *file,
gen_entry *table,
int depth,
gen_entry_handler * start,
gen_entry_handler * leaf,
gen_entry_handler * end, void *data)
{
gen_entry *entry;
ASSERT (table !=NULL);
ASSERT (table->opcode != NULL);
ASSERT (table->nr_entries > 0);
ASSERT (table->entries != 0);
if (start != NULL && depth >= 0)
{
start (file, table, depth, data);
}
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
if (entry->entries != NULL && depth != 0)
{
gen_entry_traverse_tree (file, entry, depth + 1,
start, leaf, end, data);
}
else if (depth >= 0)
{
if (leaf != NULL)
{
leaf (file, entry, depth, data);
}
}
}
if (end != NULL && depth >= 0)
{
end (file, table, depth, data);
}
}
static gen_list *
make_table (insn_table *isa, decode_table *rules, model_entry *model)
{
insn_entry *insn;
gen_list *entry = ZALLOC (gen_list);
entry->table = ZALLOC (gen_entry);
entry->table->top = entry;
entry->model = model;
entry->isa = isa;
for (insn = isa->insns; insn != NULL; insn = insn->next)
{
if (model == NULL
|| insn->processors == NULL
|| filter_is_member (insn->processors, model->name))
{
insn_list_insert (&entry->table->insns, &entry->table->nr_insns, insn, NULL,
NULL,
0,
report_duplicate_insns);
}
}
entry->table->opcode_rule = rules;
return entry;
}
gen_table *
make_gen_tables (insn_table *isa, decode_table *rules)
{
gen_table *gen = ZALLOC (gen_table);
gen->isa = isa;
gen->rules = rules;
if (options.gen.multi_sim)
{
gen_list **last = &gen->tables;
model_entry *model;
filter *processors;
if (options.model_filter != NULL)
processors = options.model_filter;
else
processors = isa->model->processors;
for (model = isa->model->models; model != NULL; model = model->next)
{
if (filter_is_member (processors, model->name))
{
*last = make_table (isa, rules, model);
last = &(*last)->next;
}
}
}
else
{
gen->tables = make_table (isa, rules, NULL);
}
return gen;
}
#if 0
typedef enum
{
field_is_not_constant = 0,
field_constant_int = 1,
field_constant_reserved = 2,
field_constant_string = 3
}
constant_field_types;
static constant_field_types
insn_field_is_constant (insn_field * field, decode_table *rule)
{
switch (field->type)
{
case insn_field_int:
return field_constant_int;
case insn_field_reserved:
if (rule->with_zero_reserved)
return field_constant_reserved;
else
return field_is_not_constant;
case insn_field_wild:
return field_is_not_constant;
case insn_field_string:
if (filter_is_member (rule->constant_field_names, field->val_string))
return field_constant_string;
else
return field_is_not_constant;
}
ERROR ("Internal error");
return field_is_not_constant;
}
#endif
static int
insns_bit_useless (insn_list *insns, decode_table *rule, int bit_nr)
{
insn_list *entry;
int value = -1;
int is_useless = 1;
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:
break;
case insn_field_int:
switch (rule->search)
{
case decode_find_strings:
return 1;
case decode_find_constants:
case decode_find_mixed:
if (value < 0)
value = bit->value;
else if (value != bit->value)
is_useless = 0;
break;
}
break;
case insn_field_string:
switch (rule->search)
{
case decode_find_strings:
is_useless = 0;
break;
case decode_find_constants:
case decode_find_mixed:
if (filter_is_member (rule->constant_field_names,
bit->field->val_string))
is_useless = 0;
else if (rule->search == decode_find_constants)
return 1;
break;
}
}
}
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:
break;
case insn_field_string:
switch (rule->search)
{
case decode_find_strings:
case decode_find_constants:
break;
case decode_find_mixed:
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)
{
switch (condition->type)
{
case insn_field_cond_value:
switch (condition->test)
{
case insn_field_cond_ne:
if (((condition->value >> shift) & 1)
== (unsigned) value)
is_useless = 0;
break;
case insn_field_cond_eq:
if (((condition->value >> shift) & 1)
!= (unsigned) value)
is_useless = 0;
break;
}
break;
case insn_field_cond_field:
break;
}
}
}
}
}
}
}
return is_useless;
}
static opcode_field *
gen_entry_find_opcode_field (insn_list *insns,
decode_table *rule, int string_only)
{
opcode_field curr_opcode;
ASSERT (rule != NULL);
memset (&curr_opcode, 0, sizeof (curr_opcode));
curr_opcode.word_nr = rule->word_nr;
curr_opcode.first = rule->first;
curr_opcode.last = rule->last;
while (curr_opcode.first <= rule->last)
{
if (insns_bit_useless (insns, rule, curr_opcode.first))
curr_opcode.first++;
else
break;
}
while (curr_opcode.last >= rule->first)
{
if (insns_bit_useless (insns, rule, curr_opcode.last))
curr_opcode.last--;
else
break;
}
#if 0
for (entry = insns; entry != NULL; entry = entry->next)
{
insn_word_entry *fields = entry->insn->word[rule->word_nr];
opcode_field new_opcode;
ASSERT (fields != NULL);
new_opcode.first = rule->first;
while (new_opcode.first <= rule->last
&& (!string_only
||
(insn_field_is_constant (fields->bit[new_opcode.first], rule)
!= field_constant_string)) && (string_only
||
(insn_field_is_constant
(fields->
bit[new_opcode.first],
rule) ==
field_is_not_constant)))
{
int new_first = fields->bit[new_opcode.first]->last + 1;
ASSERT (new_first > new_opcode.first);
new_opcode.first = new_first;
}
ASSERT (new_opcode.first > rule->last
|| (string_only
&& insn_field_is_constant (fields->bit[new_opcode.first],
rule) == field_constant_string)
|| (!string_only
&& insn_field_is_constant (fields->bit[new_opcode.first],
rule)));
new_opcode.last = rule->last;
while (new_opcode.last >= rule->first
&& (!string_only
|| insn_field_is_constant (fields->bit[new_opcode.last],
rule) != field_constant_string)
&& (string_only
|| !insn_field_is_constant (fields->bit[new_opcode.last],
rule)))
{
int new_last = fields->bit[new_opcode.last]->first - 1;
ASSERT (new_last < new_opcode.last);
new_opcode.last = new_last;
}
ASSERT (new_opcode.last < rule->first
|| (string_only
&& insn_field_is_constant (fields->bit[new_opcode.last],
rule) == field_constant_string)
|| (!string_only
&& insn_field_is_constant (fields->bit[new_opcode.last],
rule)));
if (new_opcode.first <= rule->last
&& curr_opcode.first > new_opcode.first)
curr_opcode.first = new_opcode.first;
if (new_opcode.last >= rule->first
&& curr_opcode.last < new_opcode.last)
curr_opcode.last = new_opcode.last;
}
#endif
if (curr_opcode.first > curr_opcode.last)
{
return NULL;
}
ASSERT (curr_opcode.last >= rule->first);
ASSERT (curr_opcode.first <= rule->last);
ASSERT (curr_opcode.first <= curr_opcode.last);
if (!string_only && curr_opcode.first > rule->force_first)
{
curr_opcode.first = rule->force_first;
}
if (!string_only && curr_opcode.last < rule->force_last)
{
curr_opcode.last = rule->force_last;
}
if (string_only && rule->force_last == options.insn_bit_size - 1)
{
curr_opcode.last = options.insn_bit_size - 1;
}
switch (rule->type)
{
case normal_decode_rule:
curr_opcode.nr_opcodes =
(1 << (curr_opcode.last - curr_opcode.first + 1));
break;
case boolean_rule:
curr_opcode.is_boolean = 1;
curr_opcode.boolean_constant = rule->constant;
curr_opcode.nr_opcodes = 2;
break;
}
{
opcode_field *new_field = ZALLOC (opcode_field);
memcpy (new_field, &curr_opcode, sizeof (opcode_field));
return new_field;
}
}
static void
gen_entry_insert_insn (gen_entry *table,
insn_entry * old_insn,
int new_word_nr,
int new_nr_prefetched_words,
int new_opcode_nr, opcode_bits *new_bits)
{
gen_entry **entry = &table->entries;
while ((*entry) != NULL && (*entry)->opcode_nr < new_opcode_nr)
{
entry = &(*entry)->sibling;
}
if ((*entry) == NULL || (*entry)->opcode_nr != new_opcode_nr)
{
gen_entry *new_entry = ZALLOC (gen_entry);
new_entry->sibling = (*entry);
(*entry) = new_entry;
table->nr_entries++;
new_entry->top = table->top;
new_entry->opcode_nr = new_opcode_nr;
new_entry->word_nr = new_word_nr;
new_entry->expanded_bits = new_bits;
new_entry->opcode_rule = table->opcode_rule->next;
new_entry->parent = table;
new_entry->nr_prefetched_words = new_nr_prefetched_words;
}
ASSERT ((*entry) != NULL && (*entry)->opcode_nr == new_opcode_nr);
insn_list_insert (&(*entry)->insns, &(*entry)->nr_insns, old_insn, NULL,
NULL,
new_nr_prefetched_words,
report_duplicate_insns);
}
static void
gen_entry_expand_opcode (gen_entry *table,
insn_entry * instruction,
int bit_nr, int opcode_nr, opcode_bits *bits)
{
if (bit_nr > table->opcode->last)
{
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,
table->opcode->word_nr,
table->nr_prefetched_words, opcode_nr, bits);
}
else
{
gen_entry_insert_insn (table, instruction,
table->opcode->word_nr,
table->nr_prefetched_words, opcode_nr, NULL);
}
}
else
{
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);
int first_pos = ((field->first > table->opcode->first)
? field->first : table->opcode->first);
int width = last_pos - first_pos + 1;
switch (field->type)
{
case insn_field_int:
{
int val;
val = sub_val (field->val_int, field->last, first_pos, last_pos);
gen_entry_expand_opcode (table, instruction,
last_pos + 1,
((opcode_nr << width) | val), bits);
break;
}
default:
{
if (field->type == insn_field_reserved)
gen_entry_expand_opcode (table, instruction,
last_pos + 1,
((opcode_nr << width)), bits);
else
{
int val;
int last_val = (table->opcode->is_boolean ? 2 : (1 << width));
for (val = 0; val < last_val; val++)
{
int is_precluded;
insn_field_cond *condition;
for (condition = field->conditions, is_precluded = 0;
condition != NULL && !is_precluded;
condition = condition->next)
{
switch (condition->type)
{
case insn_field_cond_value:
{
int value =
sub_val (condition->value, field->last,
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 = -1;
opcode_bits *bit;
gen_entry *t = NULL;
for (bit = bits; bit != NULL; bit = bit->next)
{
if (bit->field->word_nr ==
condition->field->word_nr
&& bit->first <= condition->field->first
&& bit->last >= condition->field->last)
{
value = sub_val (bit->value, bit->last,
condition->field->
first,
condition->field->
last);
}
}
if (bit == NULL)
{
for (t = table;
t->parent != NULL; t = t->parent)
{
if (t->parent->opcode->word_nr ==
condition->field->word_nr
&& t->parent->opcode->first <=
condition->field->first
&& t->parent->opcode->last >=
condition->field->last)
{
value =
sub_val (t->opcode_nr,
t->parent->opcode->last,
condition->field->first,
condition->field->last);
ASSERT ((condition->field->first -
condition->field->last) ==
(first_pos - last_pos));
printf
("value=%d, opcode_nr=%d, last=%d, [%d..%d]\n",
value, t->opcode_nr,
t->parent->opcode->last,
condition->field->first,
condition->field->last);
}
}
}
if (bit == NULL && t == NULL)
error (instruction->line,
"Conditional `%s' of field `%s' isn't expanded",
condition->string, field->val_string);
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 (!is_precluded)
{
if (table->opcode_rule->with_combine)
{
gen_entry_expand_opcode (table, instruction,
last_pos + 1,
((opcode_nr << width) |
val), bits);
}
else
{
opcode_bits *new_bits =
new_opcode_bits (bits, val,
first_pos, last_pos,
field,
table->opcode);
gen_entry_expand_opcode (table, instruction,
last_pos + 1,
((opcode_nr << width) |
val), new_bits);
}
}
}
}
}
}
}
}
static void
gen_entry_insert_expanding (gen_entry *table, insn_entry * instruction)
{
gen_entry_expand_opcode (table,
instruction,
table->opcode->first, 0, table->expanded_bits);
}
static int
insns_match_format_names (insn_list *insns, filter *format_names)
{
if (format_names != NULL)
{
insn_list *i;
for (i = insns; i != NULL; i = i->next)
{
if (i->insn->format_name != NULL
&& !filter_is_member (format_names, i->insn->format_name))
return 0;
}
}
return 1;
}
static int
table_matches_path (gen_entry *table, decode_path_list *paths)
{
if (paths == NULL)
return 1;
while (paths != NULL)
{
gen_entry *entry = table;
decode_path *path = paths->path;
while (1)
{
if (entry == NULL && path == NULL)
return 1;
if (entry == NULL || path == NULL)
break;
if (entry->opcode_nr != path->opcode_nr)
break;
entry = entry->parent;
path = path->parent;
}
paths = paths->next;
}
return 0;
}
static int
insns_match_conditions (insn_list *insns, decode_cond *conditions)
{
if (conditions != NULL)
{
insn_list *i;
for (i = insns; i != NULL; i = i->next)
{
decode_cond *cond;
for (cond = conditions; cond != NULL; cond = cond->next)
{
int bit_nr;
if (i->insn->nr_words <= cond->word_nr)
return 0;
for (bit_nr = 0; bit_nr < options.insn_bit_size; bit_nr++)
{
if (!cond->mask[bit_nr])
continue;
if (!i->insn->word[cond->word_nr]->bit[bit_nr]->mask)
return 0;
if ((i->insn->word[cond->word_nr]->bit[bit_nr]->value
== cond->value[bit_nr]) == !cond->is_equal)
return 0;
}
}
}
}
return 1;
}
static int
insns_match_nr_words (insn_list *insns, int nr_words)
{
insn_list *i;
for (i = insns; i != NULL; i = i->next)
{
if (i->insn->nr_words < nr_words)
return 0;
}
return 1;
}
static int
insn_list_cmp (insn_list *l, insn_list *r)
{
while (1)
{
insn_entry *insn;
if (l == NULL && r == NULL)
return 0;
if (l == NULL)
return -1;
if (r == NULL)
return 1;
if (l->insn != r->insn)
return -1;
insn = l->insn;
while (l != NULL && l->insn == insn)
l = l->next;
while (r != NULL && r->insn == insn)
r = r->next;
}
}
static void
gen_entry_expand_insns (gen_entry *table)
{
decode_table *opcode_rule;
ASSERT (table->nr_insns >= 1);
for (opcode_rule = table->opcode_rule;
opcode_rule != NULL; opcode_rule = opcode_rule->next)
{
char *discard_reason;
if (table->top->model != NULL
&& opcode_rule->model_names != NULL
&& !filter_is_member (opcode_rule->model_names,
table->top->model->name))
{
discard_reason = "wrong model";
}
else if (table->nr_insns == 1 && opcode_rule->conditions == NULL)
{
discard_reason = "need pre-condition when nr-insn == 1";
}
else if (table->nr_insns == 1 && !opcode_rule->with_duplicates)
{
discard_reason = "need duplication with nr-insns == 1";
}
else
if (!insns_match_format_names
(table->insns, opcode_rule->format_names))
{
discard_reason = "wrong format name";
}
else if (!insns_match_nr_words (table->insns, opcode_rule->word_nr + 1))
{
discard_reason = "wrong nr words";
}
else if (!table_matches_path (table, opcode_rule->paths))
{
discard_reason = "path failed";
}
else
if (!insns_match_conditions (table->insns, opcode_rule->conditions))
{
discard_reason = "condition failed";
}
else
{
discard_reason = "no opcode field";
table->opcode = gen_entry_find_opcode_field (table->insns,
opcode_rule,
table->nr_insns == 1
);
if (table->opcode != NULL)
{
table->opcode_rule = opcode_rule;
break;
}
}
if (options.trace.rule_rejection)
{
print_gen_entry_path (opcode_rule->line, table, notify);
notify (NULL, ": rule discarded - %s\n", discard_reason);
}
}
if (opcode_rule == NULL)
{
if (table->nr_insns > 1)
{
print_gen_entry_insns (table, warning,
"was not uniquely decoded",
"decodes to the same entry");
error (NULL, "");
}
return;
}
if (table->parent == NULL)
table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
else if (table->opcode_rule->word_nr + 1 >
table->parent->nr_prefetched_words)
table->nr_prefetched_words = table->opcode_rule->word_nr + 1;
else
table->nr_prefetched_words = table->parent->nr_prefetched_words;
if (table->parent != NULL)
{
ASSERT (table->parent->opcode != NULL);
table->opcode->parent = table->parent->opcode;
}
if (options.trace.rule_selection)
{
print_gen_entry_path (table->opcode_rule->line, table, notify);
notify (NULL,
": decode - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d\n",
table->opcode->word_nr,
i2target (options.hi_bit_nr, table->opcode->first),
i2target (options.hi_bit_nr, table->opcode->last),
i2target (options.hi_bit_nr, table->opcode_rule->first),
i2target (options.hi_bit_nr, table->opcode_rule->last),
table->opcode->nr_opcodes, table->nr_entries);
}
{
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);
}
}
if (options.trace.entries)
{
gen_entry *entry;
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
insn_list *l;
print_gen_entry_path (table->opcode_rule->line, entry, notify);
notify (NULL, ": %d - entries %d -",
entry->opcode_nr, entry->nr_insns);
for (l = entry->insns; l != NULL; l = l->next)
notify (NULL, " %s.%s", l->insn->format_name, l->insn->name);
notify (NULL, "\n");
}
}
if (table->opcode_rule->with_combine)
{
gen_entry *entry;
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
if (entry->combined_parent == NULL)
{
gen_entry **last = &entry->combined_next;
gen_entry *alt;
for (alt = entry->sibling; alt != NULL; alt = alt->sibling)
{
if (alt->combined_parent == NULL
&& insn_list_cmp (entry->insns, alt->insns) == 0)
{
alt->combined_parent = entry;
*last = alt;
last = &alt->combined_next;
}
}
}
}
if (options.trace.combine)
{
int nr_unique = 0;
gen_entry *entry;
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
if (entry->combined_parent == NULL)
{
insn_list *l;
gen_entry *duplicate;
nr_unique++;
print_gen_entry_path (table->opcode_rule->line, entry,
notify);
for (duplicate = entry->combined_next; duplicate != NULL;
duplicate = duplicate->combined_next)
{
notify (NULL, "+%d", duplicate->opcode_nr);
}
notify (NULL, ": entries %d -", entry->nr_insns);
for (l = entry->insns; l != NULL; l = l->next)
{
notify (NULL, " %s.%s",
l->insn->format_name, l->insn->name);
}
notify (NULL, "\n");
}
}
print_gen_entry_path (table->opcode_rule->line, table, notify);
notify (NULL,
": combine - word %d, bits [%d..%d] in [%d..%d], opcodes %d, entries %d, unique %d\n",
table->opcode->word_nr, i2target (options.hi_bit_nr,
table->opcode->first),
i2target (options.hi_bit_nr, table->opcode->last),
i2target (options.hi_bit_nr, table->opcode_rule->first),
i2target (options.hi_bit_nr, table->opcode_rule->last),
table->opcode->nr_opcodes, table->nr_entries, nr_unique);
}
}
{
gen_entry *entry;
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
if (entry->combined_parent == NULL)
{
if (insn_list_cmp (table->insns, entry->insns) == 0)
{
print_gen_entry_path (table->opcode_rule->line, table,
warning);
warning (NULL,
": Applying rule just copied all instructions\n");
print_gen_entry_insns (entry, warning, "Copied", NULL);
error (NULL, "");
}
}
}
}
switch (table->opcode_rule->gen)
{
case padded_switch_gen:
case array_gen:
case goto_switch_gen:
if (!table->opcode->is_boolean)
{
gen_entry **entry = &table->entries;
gen_entry *illegals = NULL;
gen_entry **last_illegal = &illegals;
int opcode_nr = 0;
while (opcode_nr < table->opcode->nr_opcodes)
{
if ((*entry) == NULL || (*entry)->opcode_nr != opcode_nr)
{
gen_entry_insert_insn (table, table->top->isa->illegal_insn, table->opcode->word_nr, 0,
opcode_nr, NULL);
ASSERT ((*entry) != NULL);
ASSERT ((*entry)->opcode_nr == opcode_nr);
(*last_illegal) = *entry;
(*last_illegal)->combined_parent = illegals;
last_illegal = &(*last_illegal)->combined_next;
}
entry = &(*entry)->sibling;
opcode_nr++;
}
if (illegals != NULL)
illegals->combined_parent = NULL;
}
break;
case switch_gen:
case invalid_gen:
break;
}
{
gen_entry *entry;
for (entry = table->entries; entry != NULL; entry = entry->sibling)
{
if (entry->combined_parent == NULL)
{
gen_entry_expand_insns (entry);
}
}
}
}
void
gen_tables_expand_insns (gen_table *gen)
{
gen_list *entry;
for (entry = gen->tables; entry != NULL; entry = entry->next)
{
gen_entry_expand_insns (entry->table);
}
}
static void
make_gen_semantics_list (lf *file, gen_entry *entry, int depth, void *data)
{
gen_table *gen = (gen_table *) data;
insn_list *insn;
if (entry->combined_parent != NULL)
return;
ASSERT (entry->nr_insns == 1);
insn = insn_list_insert (&gen->semantics, &gen->nr_semantics,
entry->insns->insn,
entry->expanded_bits,
entry->parent->opcode,
entry->insns->nr_prefetched_words,
merge_duplicate_insns);
ASSERT (insn != NULL);
entry->insns->semantic = insn;
}
void
gen_tables_expand_semantics (gen_table *gen)
{
gen_list *entry;
for (entry = gen->tables; entry != NULL; entry = entry->next)
{
gen_entry_traverse_tree (NULL, entry->table, 1,
NULL,
make_gen_semantics_list,
NULL,
gen);
}
}
#ifdef MAIN
static void
dump_opcode_field (lf *file,
char *prefix,
opcode_field *field, char *suffix, int levels)
{
lf_printf (file, "%s(opcode_field *) 0x%lx", prefix, (long) field);
if (levels && field != NULL)
{
lf_indent (file, +1);
lf_printf (file, "\n(first %d)", field->first);
lf_printf (file, "\n(last %d)", field->last);
lf_printf (file, "\n(nr_opcodes %d)", field->nr_opcodes);
lf_printf (file, "\n(is_boolean %d)", field->is_boolean);
lf_printf (file, "\n(boolean_constant %d)", field->boolean_constant);
dump_opcode_field (file, "\n(parent ", field->parent, ")", levels - 1);
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
static void
dump_opcode_bits (lf *file,
char *prefix, opcode_bits *bits, char *suffix, int levels)
{
lf_printf (file, "%s(opcode_bits *) 0x%lx", prefix, (long) bits);
if (levels && bits != NULL)
{
lf_indent (file, +1);
lf_printf (file, "\n(value %d)", bits->value);
dump_opcode_field (file, "\n(opcode ", bits->opcode, ")", 0);
dump_insn_field (file, "\n(field ", bits->field, ")");
dump_opcode_bits (file, "\n(next ", bits->next, ")", levels - 1);
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
static void
dump_insn_list (lf *file, char *prefix, insn_list *entry, char *suffix)
{
lf_printf (file, "%s(insn_list *) 0x%lx", prefix, (long) entry);
if (entry != NULL)
{
lf_indent (file, +1);
dump_insn_entry (file, "\n(insn ", entry->insn, ")");
lf_printf (file, "\n(next 0x%lx)", (long) entry->next);
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
static void
dump_insn_word_entry_list_entries (lf *file,
char *prefix,
insn_list *entry, char *suffix)
{
lf_printf (file, "%s", prefix);
while (entry != NULL)
{
dump_insn_list (file, "\n(", entry, ")");
entry = entry->next;
}
lf_printf (file, "%s", suffix);
}
static void
dump_gen_entry (lf *file,
char *prefix, gen_entry *table, char *suffix, int levels)
{
lf_printf (file, "%s(gen_entry *) 0x%lx", prefix, (long) table);
if (levels && table !=NULL)
{
lf_indent (file, +1);
lf_printf (file, "\n(opcode_nr %d)", table->opcode_nr);
lf_printf (file, "\n(word_nr %d)", table->word_nr);
dump_opcode_bits (file, "\n(expanded_bits ", table->expanded_bits, ")",
-1);
lf_printf (file, "\n(nr_insns %d)", table->nr_insns);
dump_insn_word_entry_list_entries (file, "\n(insns ", table->insns,
")");
dump_decode_rule (file, "\n(opcode_rule ", table->opcode_rule, ")");
dump_opcode_field (file, "\n(opcode ", table->opcode, ")", 0);
lf_printf (file, "\n(nr_entries %d)", table->nr_entries);
dump_gen_entry (file, "\n(entries ", table->entries, ")",
table->nr_entries);
dump_gen_entry (file, "\n(sibling ", table->sibling, ")", levels - 1);
dump_gen_entry (file, "\n(parent ", table->parent, ")", 0);
lf_indent (file, -1);
}
lf_printf (file, "%s", suffix);
}
static void
dump_gen_list (lf *file,
char *prefix, gen_list *entry, char *suffix, int levels)
{
while (entry != NULL)
{
lf_printf (file, "%s(gen_list *) 0x%lx", prefix, (long) entry);
dump_gen_entry (file, "\n(", entry->table, ")", levels);
lf_printf (file, "\n(next (gen_list *) 0x%lx)", (long) entry->next);
lf_printf (file, "%s", suffix);
}
}
static void
dump_gen_table (lf *file,
char *prefix, gen_table *gen, char *suffix, int levels)
{
lf_printf (file, "%s(gen_table *) 0x%lx", prefix, (long) gen);
lf_printf (file, "\n(isa (insn_table *) 0x%lx)", (long) gen->isa);
lf_printf (file, "\n(rules (decode_table *) 0x%lx)", (long) gen->rules);
dump_gen_list (file, "\n(", gen->tables, ")", levels);
lf_printf (file, "%s", suffix);
}
igen_options options;
int
main (int argc, char **argv)
{
decode_table *decode_rules;
insn_table *instructions;
gen_table *gen;
lf *l;
if (argc != 7)
error (NULL,
"Usage: insn <filter-in> <hi-bit-nr> <insn-bit-size> <widths> <decode-table> <insn-table>\n");
INIT_OPTIONS (options);
filter_parse (&options.flags_filter, argv[1]);
options.hi_bit_nr = a2i (argv[2]);
options.insn_bit_size = a2i (argv[3]);
options.insn_specifying_widths = a2i (argv[4]);
ASSERT (options.hi_bit_nr < options.insn_bit_size);
instructions = load_insn_table (argv[6], NULL);
decode_rules = load_decode_table (argv[5]);
gen = make_gen_tables (instructions, decode_rules);
gen_tables_expand_insns (gen);
l = lf_open ("-", "stdout", lf_omit_references, lf_is_text, "tmp-ld-insn");
dump_gen_table (l, "(", gen, ")\n", -1);
return 0;
}
#endif