diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index 74aa179d6..5ffc9c3ac 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -67,6 +67,8 @@ void value_store (pr_type_t *dst, const struct type_s *dstType, const struct expr_s *src); 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 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, diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index b09d0fad2..dd1a995a5 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -154,7 +154,7 @@ _print_operand (operand_t *op) printf ("%s", op->def->name); break; 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)); break; case op_label: @@ -514,8 +514,18 @@ offset_alias_operand (type_t *type, int offset, operand_t *aop, expr_t *expr) def = def->alias; return def_operand (alias_def (def, type, offset), 0, expr); } else if (aop->op_type == op_value) { - top = value_operand (aop->value, expr); - top->type = type; + 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->type = type; + } return top; } else { internal_error (expr, "invalid alias target: %s: %s", diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index e6f85c402..bf4a3a676 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -531,6 +531,22 @@ ReuseString (const char *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 * alias_value (ex_value_t *value, type_t *type) {