mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
[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:
parent
854e45485a
commit
54d776f243
5 changed files with 91 additions and 10 deletions
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue