[qfcc] Support offset aliases of values

But explicitly not for pointers (even an offset of 0 breaks the pointer
relocation).
This commit is contained in:
Bill Currie 2023-09-11 22:54:41 +09:00
parent b456f936c6
commit 73d1044bec
3 changed files with 31 additions and 3 deletions

View file

@ -67,6 +67,8 @@ void value_store (pr_type_t *dst, const struct type_s *dstType,
const struct expr_s *src); const struct expr_s *src);
const char *get_value_string (const struct ex_value_s *value); const char *get_value_string (const struct ex_value_s *value);
struct ex_value_s *offset_alias_value (struct ex_value_s *value,
struct type_s *type, int offset);
struct ex_value_s *alias_value (struct ex_value_s *value, struct type_s *type); struct ex_value_s *alias_value (struct ex_value_s *value, struct type_s *type);
struct def_s *emit_value (struct ex_value_s *value, struct def_s *def); struct def_s *emit_value (struct ex_value_s *value, struct def_s *def);
struct def_s *emit_value_core (struct ex_value_s *value, struct def_s *def, struct def_s *emit_value_core (struct ex_value_s *value, struct def_s *def,

View file

@ -154,7 +154,7 @@ _print_operand (operand_t *op)
printf ("%s", op->def->name); printf ("%s", op->def->name);
break; break;
case op_value: case op_value:
printf ("(%s) %s", pr_type_name[op->type->type], printf ("(%s) %s", get_type_string (op->type),
get_value_string (op->value)); get_value_string (op->value));
break; break;
case op_label: case op_label:
@ -514,8 +514,18 @@ offset_alias_operand (type_t *type, int offset, operand_t *aop, expr_t *expr)
def = def->alias; def = def->alias;
return def_operand (alias_def (def, type, offset), 0, expr); return def_operand (alias_def (def, type, offset), 0, expr);
} else if (aop->op_type == op_value) { } else if (aop->op_type == op_value) {
if (!is_ptr (aop->value->type)) {
auto value = offset_alias_value (aop->value, type, offset);
top = value_operand (value, expr);
} else {
// even an offset of 0 will break a pointer value because of
// relocations
if (offset) {
internal_error (expr, "offset alias of pointer value operand");
}
top = value_operand (aop->value, expr); top = value_operand (aop->value, expr);
top->type = type; top->type = type;
}
return top; return top;
} else { } else {
internal_error (expr, "invalid alias target: %s: %s", internal_error (expr, "invalid alias target: %s: %s",

View file

@ -531,6 +531,22 @@ ReuseString (const char *str)
return strpool_addstr (pr.strings, str); return strpool_addstr (pr.strings, str);
} }
ex_value_t *
offset_alias_value (ex_value_t *value, type_t *type, int offset)
{
if (type_size (type) > type_size (value->type)) {
error (0, "unable to alias to a larger sized value");
return value;
}
if (offset < 0 || offset + type_size (type) > type_size (value->type)) {
error (0, "invalid offset");
return value;
}
pr_type_t data[type_size (value->type)];
memcpy (data, &value->v, sizeof (pr_type_t) * type_size (value->type));
return new_type_value (type, data + offset);
}
ex_value_t * ex_value_t *
alias_value (ex_value_t *value, type_t *type) alias_value (ex_value_t *value, type_t *type)
{ {