mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-01 05:21:02 +00:00
[qfcc] Give address expressions their own type
Definitely a pain to get working after the switch, but definitely worth the effort. Still exposing type aliasing bugs.
This commit is contained in:
parent
cf8061c4d3
commit
fa482e8ee5
8 changed files with 99 additions and 45 deletions
|
@ -213,6 +213,12 @@ typedef struct {
|
|||
struct expr_s *offset; ///< offset for alias
|
||||
} ex_alias_t;
|
||||
|
||||
typedef struct {
|
||||
struct type_s *type; ///< pointer type
|
||||
struct expr_s *lvalue; ///< the lvalue being addressed
|
||||
struct expr_s *offset; ///< offset from the address
|
||||
} ex_address_t;
|
||||
|
||||
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
|
||||
|
||||
typedef struct expr_s {
|
||||
|
@ -240,6 +246,7 @@ typedef struct expr_s {
|
|||
element_chain_t compound; ///< compound initializer
|
||||
ex_memset_t memset; ///< memset expr params
|
||||
ex_alias_t alias; ///< alias expr params
|
||||
ex_address_t address; ///< alias expr params
|
||||
struct type_s *nil; ///< type for nil if known
|
||||
} e;
|
||||
} expr_t;
|
||||
|
@ -654,6 +661,9 @@ expr_t *new_ret_expr (struct type_s *type);
|
|||
expr_t *new_alias_expr (struct type_s *type, expr_t *expr);
|
||||
expr_t *new_offset_alias_expr (struct type_s *type, expr_t *expr, int offset);
|
||||
|
||||
expr_t *new_address_expr (struct type_s *lvtype, expr_t *lvalue,
|
||||
expr_t *offset);
|
||||
|
||||
/** Create an expression of the correct type that references the specified
|
||||
parameter slot.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
expr.h
|
||||
expr_names.h
|
||||
|
||||
expression construction and manipulations
|
||||
|
||||
|
@ -55,5 +55,6 @@ EX_EXPR(value) ///< constant value (::ex_value_t)
|
|||
EX_EXPR(compound) ///< compound initializer
|
||||
EX_EXPR(memset) ///< memset needs three params...
|
||||
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t)
|
||||
EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t)
|
||||
|
||||
///@}
|
||||
|
|
|
@ -568,7 +568,7 @@ do_op_entity (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
|||
{
|
||||
type_t *type = get_type (e2);
|
||||
|
||||
if ((op == '.' || op == '&') && type->type == ev_field) {
|
||||
if (op == '.' && type->type == ev_field) {
|
||||
return e;
|
||||
}
|
||||
if (op == EQ || op == NE) {
|
||||
|
@ -617,7 +617,7 @@ static expr_t *
|
|||
do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
type_t *type;
|
||||
static int valid[] = {'=', '-', '&', 'M', '.', EQ, NE, 0};
|
||||
static int valid[] = {'=', '-', 'M', '.', EQ, NE, 0};
|
||||
|
||||
if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) {
|
||||
// pointer arithmetic
|
||||
|
@ -647,10 +647,10 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
|||
else
|
||||
e->e.expr.type = &type_float;
|
||||
}
|
||||
if (op != '.' && op != '&' && op != 'M'
|
||||
if (op != '.' && op != 'M'
|
||||
&& extract_type (e1) != extract_type (e2))
|
||||
return type_mismatch (e1, e2, op);
|
||||
if ((op == '.' || op == '&') && is_uinteger(get_type (e2)))
|
||||
if (op == '.' && is_uinteger(get_type (e2)))
|
||||
e->e.expr.e2 = cf_cast_expr (&type_integer, e2);
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -338,6 +338,27 @@ print_alias (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
|||
dstring_delete (typestr);
|
||||
}
|
||||
|
||||
static void
|
||||
print_address (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||
{
|
||||
int indent = level * 2 + 2;
|
||||
|
||||
_print_expr (dstr, e->e.alias.expr, level, id, next);
|
||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"&\"];\n", indent, "", e,
|
||||
e->e.alias.expr);
|
||||
if (e->e.alias.offset) {
|
||||
_print_expr (dstr, e->e.alias.offset, level, id, next);
|
||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"+\"];\n", indent, "", e,
|
||||
e->e.alias.offset);
|
||||
}
|
||||
|
||||
dstring_t *typestr = dstring_newstr();
|
||||
print_type_str (typestr, e->e.alias.type);
|
||||
dasprintf (dstr, "%*se_%p [label=\"%s (%s)\\n%d\"];\n", indent, "", e,
|
||||
"&", typestr->str, e->line);
|
||||
dstring_delete (typestr);
|
||||
}
|
||||
|
||||
static void
|
||||
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||
{
|
||||
|
@ -581,6 +602,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
|||
[ex_compound] = print_compound,
|
||||
[ex_memset] = print_memset,
|
||||
[ex_alias] = print_alias,
|
||||
[ex_address] = print_address,
|
||||
};
|
||||
int indent = level * 2 + 2;
|
||||
|
||||
|
|
|
@ -260,6 +260,8 @@ get_type (expr_t *e)
|
|||
return &type_SEL;
|
||||
case ex_alias:
|
||||
return e->e.alias.type;
|
||||
case ex_address:
|
||||
return e->e.address.type;
|
||||
case ex_count:
|
||||
internal_error (e, "invalid expression");
|
||||
}
|
||||
|
@ -477,6 +479,12 @@ copy_expr (expr_t *e)
|
|||
n->e.alias.expr = copy_expr (e->e.alias.expr);
|
||||
n->e.alias.offset = copy_expr (e->e.alias.offset);
|
||||
return n;
|
||||
case ex_address:
|
||||
n = new_expr ();
|
||||
*n = *e;
|
||||
n->e.address.lvalue = copy_expr (e->e.address.lvalue);
|
||||
n->e.address.offset = copy_expr (e->e.address.offset);
|
||||
return n;
|
||||
case ex_count:
|
||||
break;
|
||||
}
|
||||
|
@ -1277,6 +1285,17 @@ new_offset_alias_expr (type_t *type, expr_t *expr, int offset)
|
|||
return alias;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_address_expr (type_t *lvtype, expr_t *lvalue, expr_t *offset)
|
||||
{
|
||||
expr_t *addr = new_expr ();
|
||||
addr->type = ex_address;
|
||||
addr->e.address.type = pointer_type (lvtype);
|
||||
addr->e.address.lvalue = lvalue;
|
||||
addr->e.address.offset = offset;
|
||||
return addr;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
param_expr (const char *name, type_t *type)
|
||||
{
|
||||
|
@ -1406,8 +1425,7 @@ field_expr (expr_t *e1, expr_t *e2)
|
|||
|
||||
e2->type = ex_value;
|
||||
e2->e.value = new_short_val (field->s.offset);
|
||||
e = new_binary_expr ('&', e1, e2);
|
||||
e->e.expr.type = pointer_type (field->type);
|
||||
e = new_address_expr (field->type, e1, e2);
|
||||
return unary_expr ('.', e);
|
||||
} else if (is_class (t1->t.fldptr.type)) {
|
||||
class_t *class = t1->t.fldptr.type->t.class;
|
||||
|
@ -1420,8 +1438,7 @@ field_expr (expr_t *e1, expr_t *e2)
|
|||
return new_error_expr ();
|
||||
e2->type = ex_value;
|
||||
e2->e.value = new_short_val (ivar->s.offset);
|
||||
e = new_binary_expr ('&', e1, e2);
|
||||
e->e.expr.type = pointer_type (ivar->type);
|
||||
e = new_address_expr (ivar->type, e1, e2);
|
||||
return unary_expr ('.', e);
|
||||
}
|
||||
} else if (is_vector (t1) || is_quaternion(t1) || is_struct (t1)) {
|
||||
|
@ -1591,6 +1608,8 @@ has_function_call (expr_t *e)
|
|||
return 0;
|
||||
case ex_alias:
|
||||
return has_function_call (e->e.alias.expr);
|
||||
case ex_address:
|
||||
return has_function_call (e->e.address.lvalue);
|
||||
case ex_error:
|
||||
case ex_state:
|
||||
case ex_label:
|
||||
|
@ -1735,6 +1754,7 @@ unary_expr (int op, expr_t *e)
|
|||
return n;
|
||||
}
|
||||
case ex_nil:
|
||||
case ex_address:
|
||||
return error (e, "invalid type for unary -");
|
||||
case ex_count:
|
||||
internal_error (e, "invalid expression");
|
||||
|
@ -1798,6 +1818,7 @@ unary_expr (int op, expr_t *e)
|
|||
case ex_temp:
|
||||
case ex_vector:
|
||||
case ex_alias:
|
||||
case ex_address:
|
||||
{
|
||||
expr_t *n = new_unary_expr (op, e);
|
||||
|
||||
|
@ -1890,6 +1911,7 @@ bitnot_expr:
|
|||
return n;
|
||||
}
|
||||
case ex_nil:
|
||||
case ex_address:
|
||||
return error (e, "invalid type for unary ~");
|
||||
case ex_count:
|
||||
internal_error (e, "invalid expression");
|
||||
|
@ -2312,9 +2334,7 @@ array_expr (expr_t *array, expr_t *index)
|
|||
e = address_expr (array, index, array_type->t.array.type);
|
||||
} else {
|
||||
if (!is_short_val (index) || expr_short (index)) {
|
||||
e = new_binary_expr ('&', array, index);
|
||||
//e->e.expr.type = array_type->aux_type;
|
||||
e->e.expr.type = array_type;
|
||||
e = new_address_expr (array_type->t.array.type, array, index);
|
||||
} else {
|
||||
e = array;
|
||||
}
|
||||
|
@ -2382,9 +2402,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
|
|||
return error (e1, "invalid type for unary &");
|
||||
case ex_expr:
|
||||
if (e1->e.expr.op == '.') {
|
||||
e = e1;
|
||||
e->e.expr.op = '&';
|
||||
e->e.expr.type = pointer_type (e->e.expr.type);
|
||||
e = new_address_expr (e1->e.expr.type,
|
||||
e1->e.expr.e1, e1->e.expr.e2);
|
||||
break;
|
||||
}
|
||||
if (e1->e.expr.op == 'm') {
|
||||
|
@ -2402,8 +2421,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
|
|||
if (e1->e.expr.op == '.') {
|
||||
e = e1->e.expr.e1;
|
||||
if (e->type == ex_expr && e->e.expr.op == '.') {
|
||||
e->e.expr.type = pointer_type (e->e.expr.type);
|
||||
e->e.expr.op = '&';
|
||||
e = new_address_expr (e->e.expr.type, e->e.expr.e1, e->e.expr.e2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2411,8 +2429,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
|
|||
case ex_label:
|
||||
return new_label_ref (&e1->e.label);
|
||||
case ex_temp:
|
||||
e = new_unary_expr ('&', e1);
|
||||
e->e.expr.type = pointer_type (t);
|
||||
e = new_address_expr (t, e1, 0);
|
||||
break;
|
||||
case ex_alias:
|
||||
if (!t) {
|
||||
|
@ -2438,19 +2455,17 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
|
|||
def_t *def = e->e.value->v.pointer.def;
|
||||
e->e.value = new_pointer_val (base + offset, t, def, 0);
|
||||
} else {
|
||||
if (!is_short_val (e2) || expr_short (e2)) {
|
||||
if (e->type == ex_expr && e->e.expr.op == '&') {
|
||||
e = new_binary_expr ('&', e->e.expr.e1,
|
||||
binary_expr ('+', e->e.expr.e2, e2));
|
||||
} else {
|
||||
e = new_binary_expr ('&', e, e2);
|
||||
}
|
||||
expr_t *offset = 0;
|
||||
if (e->type == ex_address) {
|
||||
offset = e->e.address.offset;
|
||||
e1 = e->e.address.lvalue;
|
||||
} else {
|
||||
e1 = e;
|
||||
}
|
||||
if (e->type == ex_expr || e->type == ex_uexpr) {
|
||||
e->e.expr.type = pointer_type (t);
|
||||
} else if (e->type == ex_alias) {
|
||||
e->e.alias.type = pointer_type (t);
|
||||
if (offset) {
|
||||
e2 = binary_expr ('+', offset, e2);
|
||||
}
|
||||
e = new_address_expr (t, e1, e2);
|
||||
}
|
||||
}
|
||||
return e;
|
||||
|
|
|
@ -115,6 +115,8 @@ is_lvalue (const expr_t *expr)
|
|||
break;
|
||||
case ex_alias:
|
||||
return is_lvalue (expr->e.alias.expr);
|
||||
case ex_address:
|
||||
return 0;
|
||||
case ex_uexpr:
|
||||
if (expr->e.expr.op == '.') {
|
||||
return 1;
|
||||
|
|
|
@ -486,8 +486,8 @@ get_selector (expr_t *sel)
|
|||
if (sel->type == ex_selector) {
|
||||
return sel->e.selector.sel;
|
||||
}
|
||||
if (sel->type != ex_expr && sel->e.expr.op != '&'
|
||||
&& !is_SEL(sel->e.expr.type)) {
|
||||
if (sel->type != ex_address && !sel->e.address.offset
|
||||
&& !is_SEL(sel->e.address.type)) {
|
||||
error (sel, "not a selector");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -744,8 +744,11 @@ expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
{
|
||||
statement_t *s;
|
||||
s = new_statement (st_expr, "&", e);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
||||
s->opc = temp_operand (e->e.expr.type, e);
|
||||
sblock = statement_subexpr (sblock, e->e.address.lvalue, &s->opa);
|
||||
if (e->e.address.offset) {
|
||||
sblock = statement_subexpr (sblock, e->e.address.offset, &s->opb);
|
||||
}
|
||||
s->opc = temp_operand (e->e.address.type, e);
|
||||
sblock_add_statement (sblock, s);
|
||||
*(op) = s->opc;
|
||||
return sblock;
|
||||
|
@ -960,9 +963,12 @@ dereference_dst:
|
|||
// to get the pointer and switch to storep instructions.
|
||||
dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e);
|
||||
opcode = ".="; // FIXME find a nicer representation (lose strings?)
|
||||
if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) {
|
||||
sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst);
|
||||
sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs);
|
||||
if (dst_expr->type == ex_address && dst_expr->e.address.offset
|
||||
&& !is_const_ptr (dst_expr->e.address.lvalue)) {
|
||||
sblock = statement_subexpr (sblock,
|
||||
dst_expr->e.address.lvalue, &dst);
|
||||
sblock = statement_subexpr (sblock,
|
||||
dst_expr->e.address.offset, &ofs);
|
||||
} else {
|
||||
sblock = statement_subexpr (sblock, dst_expr, &dst);
|
||||
ofs = 0;
|
||||
|
@ -1127,17 +1133,17 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op)
|
|||
expr_t *e;
|
||||
|
||||
e = deref->e.expr.e1;
|
||||
if (e->type == ex_uexpr && e->e.expr.op == '&'
|
||||
&& e->e.expr.e1->type == ex_symbol) {
|
||||
if (e->type == ex_address && !e->e.address.offset
|
||||
&& e->e.address.lvalue->type == ex_symbol) {
|
||||
if (e->e.expr.e1->e.symbol->sy_type != sy_var)
|
||||
internal_error (e, "address of non-var");
|
||||
*op = def_operand (e->e.expr.e1->e.symbol->s.def, type, e);
|
||||
} else if (e->type == ex_expr && e->e.expr.op == '&') {
|
||||
} else if (e->type == ex_address && e->e.address.offset) {
|
||||
statement_t *s;
|
||||
operand_t *ptr = 0;
|
||||
operand_t *offs = 0;
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr);
|
||||
sblock = statement_subexpr (sblock, e->e.expr.e2, &offs);
|
||||
sblock = statement_subexpr (sblock, e->e.address.lvalue, &ptr);
|
||||
sblock = statement_subexpr (sblock, e->e.address.offset, &offs);
|
||||
if (!*op)
|
||||
*op = temp_operand (type, e);
|
||||
if (low_level_type (type) == ev_void) {
|
||||
|
@ -1329,9 +1335,6 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
statement_t *s;
|
||||
|
||||
switch (e->e.expr.op) {
|
||||
case '&':
|
||||
sblock = expr_address (sblock, e, op);
|
||||
break;
|
||||
case '.':
|
||||
sblock = expr_deref (sblock, e, op);
|
||||
break;
|
||||
|
@ -1524,6 +1527,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
|
|||
[ex_value] = expr_value,
|
||||
[ex_selector] = expr_selector,
|
||||
[ex_alias] = expr_alias,
|
||||
[ex_address] = expr_address,
|
||||
};
|
||||
if (!e) {
|
||||
*op = 0;
|
||||
|
|
Loading…
Reference in a new issue