[qfcc] Take operand width into account

Operand width is encoded in the instruction opcode, so the width needs
to be accounted for in order to select the correct instruction. With
this, my little test generates correct code for the ruamoko ISA (except
for return, still fails).
This commit is contained in:
Bill Currie 2022-01-20 16:49:07 +09:00
parent 854e45485a
commit 54d776f243
5 changed files with 91 additions and 10 deletions

View file

@ -68,6 +68,7 @@ typedef struct operand_s {
op_type_e op_type;
struct type_s *type; ///< possibly override def's/nil's type
int size; ///< for structures
int width; ///< for SIMD selection
struct expr_s *expr; ///< expression generating this operand
void *return_addr; ///< who created this operand
union {

View file

@ -166,6 +166,7 @@ int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure))
int type_assignable (const type_t *dst, const type_t *src);
int type_same (const type_t *dst, const type_t *src) __attribute__((pure));
int type_size (const type_t *type) __attribute__((pure));
int type_width (const type_t *type) __attribute__((pure));
void init_types (void);
void chain_initial_types (void);

View file

@ -139,6 +139,8 @@ rua_get_hash (const void *_op, void *_tab)
hash = ROTL (~op->types[0], 8) + ROTL (~op->types[1], 16)
+ ROTL (~op->types[2], 24);
hash += ROTL (~op->widths[0], 12) + ROTL (~op->widths[1], 20)
+ ROTL (~op->widths[2], 28);
return hash + Hash_String (op->opname);
}
@ -152,6 +154,9 @@ rua_compare (const void *_opa, const void *_opb, void *unused)
cmp = (opa->types[0] == opb->types[0])
&& (opa->types[1] == opb->types[1])
&& (opa->types[2] == opb->types[2]);
cmp &= (opa->widths[0] == opb->widths[0])
&& (opa->widths[1] == opb->widths[1])
&& (opa->widths[2] == opb->widths[2]);
return cmp && !strcmp (opa->opname, opb->opname);
}
@ -170,6 +175,12 @@ check_operand_type (etype_t ot1, etype_t ot2)
return 0;
}
static int
check_operand_width (int ow1, int ow2)
{
return ((ow1 == -1 && ow2) || ow1 == ow2);
}
pr_ushort_t
opcode_get (instruction_t *op)
{
@ -219,20 +230,43 @@ v6p_opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
return op;
}
static int
operand_width (operand_t *op)
{
if (!op) {
return 0;
}
return op->width;
}
static opcode_t *
rua_opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
operand_t *op_c)
{
opcode_t search_op = {};
opcode_t search_op = {
.opname = name,
.types = {
op_a ? low_level_type (op_a->type) : ev_invalid,
op_b ? low_level_type (op_b->type) : ev_invalid,
op_c ? low_level_type (op_c->type) : ev_invalid,
},
.widths = {
operand_width (op_a),
operand_width (op_b),
operand_width (op_c),
},
};
opcode_t *op;
opcode_t *sop;
void **op_list;
int i;
search_op.opname = name;
search_op.types[0] = op_a ? low_level_type (op_a->type) : ev_invalid;
search_op.types[1] = op_b ? low_level_type (op_b->type) : ev_invalid;
search_op.types[2] = op_c ? low_level_type (op_c->type) : ev_invalid;
#if 0
printf ("%s [%s %d] [%s %d] [%s %d]\n", search_op.opname,
pr_type_name[search_op.types[0]], search_op.widths[0],
pr_type_name[search_op.types[1]], search_op.widths[1],
pr_type_name[search_op.types[2]], search_op.widths[2]);
#endif
op = Hash_FindElement (rua_opcode_type_table, &search_op);
if (op)
return op;
@ -241,10 +275,23 @@ rua_opcode_find (const char *name, operand_t *op_a, operand_t *op_b,
return op;
for (i = 0; !op && op_list[i]; i++) {
sop = op_list[i];
if (check_operand_type (sop->types[0], search_op.types[0])
&& check_operand_type (sop->types[1], search_op.types[1])
&& check_operand_type (sop->types[2], search_op.types[2]))
op = sop;
if (!(check_operand_type (sop->types[0], search_op.types[0])
&& check_operand_type (sop->types[1], search_op.types[1])
&& check_operand_type (sop->types[2], search_op.types[2]))) {
continue;
}
if (!(check_operand_width (sop->widths[0], search_op.widths[0])
&& check_operand_width (sop->widths[1], search_op.widths[1])
&& check_operand_width (sop->widths[2], search_op.widths[2]))) {
#if 0
printf ("%s [%s %d] [%s %d] [%s %d]\n", sop->opname,
pr_type_name[sop->types[0]], sop->widths[0],
pr_type_name[sop->types[1]], sop->widths[1],
pr_type_name[sop->types[2]], sop->widths[2]);
#endif
continue;
}
op = sop;
}
free (op_list);
return op;

View file

@ -426,6 +426,7 @@ nil_operand (type_t *type, expr_t *expr)
op = new_operand (op_nil, expr, __builtin_return_address (0));
op->type = type;
op->size = type_size (type);
op->width = type_width (type);
return op;
}
@ -439,6 +440,7 @@ def_operand (def_t *def, type_t *type, expr_t *expr)
op = new_operand (op_def, expr, __builtin_return_address (0));
op->type = type;
op->size = type_size (type);
op->width = type_width (type);
op->def = def;
return op;
}
@ -458,6 +460,8 @@ value_operand (ex_value_t *value, expr_t *expr)
operand_t *op;
op = new_operand (op_value, expr, __builtin_return_address (0));
op->type = value->type;
op->size = type_size (value->type);
op->width = type_width (value->type);
op->value = value;
return op;
}
@ -470,6 +474,7 @@ temp_operand (type_t *type, expr_t *expr)
op->tempop.type = type;
op->type = type;
op->size = type_size (type);
op->width = type_width (type);
return op;
}
@ -544,6 +549,7 @@ alias_operand (type_t *type, operand_t *op, expr_t *expr)
aop->alias = op;
aop->type = type;
aop->size = type_size (type);
aop->width = type_width (type);
return aop;
}

View file

@ -1007,7 +1007,33 @@ type_size (const type_t *type)
case ty_alias:
return type_size (type->t.alias.aux_type);
}
return 0;
internal_error (0, "invalid type meta: %d", type->meta);
}
int
type_width (const type_t *type)
{
switch (type->meta) {
case ty_basic:
if (type->type == ev_ushort || type->type == ev_short) {
return 0;
}
return 1; //FIXME vector should be 3
case ty_struct:
case ty_union:
return 1;
case ty_enum:
if (!type->t.symtab)
return 0;
return type_width (&type_int);
case ty_array:
return type_width (type->t.array.type);
case ty_class:
return 1;
case ty_alias:
return type_width (type->t.alias.aux_type);
}
internal_error (0, "invalid type meta: %d", type->meta);
}
static void