[qfcc] Give assignment expressions their own type

This is getting easier (know where to look, I guess). Nicely, I found
the source of those weird type aliasing bugs :)
This commit is contained in:
Bill Currie 2022-01-08 18:44:29 +09:00
parent d14f695c68
commit 65b6c366c3
8 changed files with 109 additions and 80 deletions

View File

@ -219,6 +219,11 @@ typedef struct {
struct expr_s *offset; ///< offset from the address
} ex_address_t;
typedef struct {
struct expr_s *dst; ///< destination of assignment
struct expr_s *src; ///< source of assignment
} ex_assign_t;
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
typedef struct expr_s {
@ -247,6 +252,7 @@ typedef struct expr_s {
ex_memset_t memset; ///< memset expr params
ex_alias_t alias; ///< alias expr params
ex_address_t address; ///< alias expr params
ex_assign_t assign; ///< assignment expr params
struct type_s *nil; ///< type for nil if known
} e;
} expr_t;
@ -663,6 +669,7 @@ 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);
expr_t *new_assign_expr (expr_t *dst, expr_t *src);
/** Create an expression of the correct type that references the specified
parameter slot.

View File

@ -56,5 +56,6 @@ 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)
EX_EXPR(assign) ///< assignment of src expr to dst expr
///@}

View File

@ -85,7 +85,7 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
const char *s1, *s2;
static dstring_t *temp_str;
static int valid[] = {'=', '+', LT, GT, LE, GE, EQ, NE, 0};
static int valid[] = {'+', LT, GT, LE, GE, EQ, NE, 0};
if (!valid_op (op, valid))
return error (e1, "invalid operand for string");
@ -99,7 +99,7 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2)
e->e.expr.type = &type_string;
}
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
s1 = expr_string (e1);
@ -220,27 +220,18 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
expr_t *conv;
type_t *type = &type_float;
static int valid[] = {
'=', '+', '-', '*', '/', '&', '|', '^', '%',
'+', '-', '*', '/', '&', '|', '^', '%',
SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0
};
if (!valid_op (op, valid))
return error (e1, "invalid operator for float");
if (op == '=') {
if (!is_float(type = get_type (e1))) {
//FIXME optimize casting a constant
e->e.expr.e2 = e2 = cf_cast_expr (type, e2);
} else if ((conv = convert_to_float (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
} else {
if ((conv = convert_to_float (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_float (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
if ((conv = convert_to_float (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_float (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
if (is_compare (op) || is_logic (op)) {
if (options.code.progsversion > PROG_ID_VERSION)
@ -271,7 +262,7 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
if (op == '-' && is_constant (e2) && expr_float (e2) == 0)
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
f1 = expr_float (e1);
@ -349,27 +340,18 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2)
expr_t *conv;
type_t *type = &type_double;
static int valid[] = {
'=', '+', '-', '*', '/', '%',
'+', '-', '*', '/', '%',
LT, GT, LE, GE, EQ, NE, 0
};
if (!valid_op (op, valid))
return error (e1, "invalid operator for double");
if (op == '=') {
if (!is_double(type = get_type (e1))) {
//FIXME optimize casting a constant
e->e.expr.e2 = e2 = cf_cast_expr (type, e2);
} else if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
} else {
if ((conv = convert_to_double (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
if ((conv = convert_to_double (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
if (is_compare (op) || is_logic (op)) {
type = &type_integer;
@ -397,7 +379,7 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2)
if (op == '-' && is_constant (e2) && expr_double (e2) == 0)
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
d1 = expr_double (e1);
@ -452,7 +434,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
const float *v1, *v2;
vec3_t v, float_vec;
static int valid[] = {'=', '+', '-', '*', EQ, NE, 0};
static int valid[] = {'+', '-', '*', EQ, NE, 0};
expr_t *t;
if (!is_vector(get_type (e1))) {
@ -510,7 +492,7 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2)
if (op == '-' && is_constant (e2) && VectorIsZero (expr_vector (e2)))
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
if (is_float_val (e1)) {
@ -578,7 +560,7 @@ do_op_entity (int op, expr_t *e, expr_t *e1, expr_t *e2)
e->e.expr.type = &type_float;
return e;
}
if (op != '=' || !is_entity(type))
if (!is_entity(type))
return error (e1, "invalid operator for entity");
e->e.expr.type = &type_entity;
return e;
@ -587,10 +569,7 @@ do_op_entity (int op, expr_t *e, expr_t *e1, expr_t *e2)
static expr_t *
do_op_field (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
if (op != '=')
return error (e1, "invalid operator for field");
e->e.expr.type = &type_field;
return e;
return error (e1, "invalid operator for field");
}
static expr_t *
@ -607,17 +586,14 @@ do_op_func (int op, expr_t *e, expr_t *e1, expr_t *e2)
e->e.expr.type = &type_float;
return e;
}
if (op != '=')
return error (e1, "invalid operator for func");
e->e.expr.type = &type_function;
return e;
return error (e1, "invalid operator for func");
}
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
@ -682,7 +658,7 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
const float *q1, *q2;
quat_t q, float_quat;
static int valid[] = {'=', '+', '-', '*', EQ, NE, 0};
static int valid[] = {'+', '-', '*', EQ, NE, 0};
expr_t *t;
if (!is_quaternion(get_type (e1))) {
@ -731,7 +707,7 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2)
if (op == '-' && is_constant (e2) && QuatIsZero (expr_quaternion (e2)))
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
if (is_float_val (e1)) {
@ -793,7 +769,7 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2)
int isval1 = 0, isval2 = 0;
int val1 = 0, val2 = 0;
static int valid[] = {
'=', '+', '-', '*', '/', '&', '|', '^', '%',
'+', '-', '*', '/', '&', '|', '^', '%',
SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0
};
@ -848,7 +824,7 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2)
if (op == '-' && isval2 && val2 == 0)
return e1;
if (op == '=' || !isval1 || !isval2)
if (!isval1 || !isval2)
return e;
switch (op) {
@ -927,7 +903,7 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
short i1, i2;
static int valid[] = {
'=', '+', '-', '*', '/', '&', '|', '^', '%',
'+', '-', '*', '/', '&', '|', '^', '%',
SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0
};
@ -943,7 +919,7 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2)
e->e.expr.type = &type_short;
}
if (op == '=' || !is_constant (e1) || !is_constant (e2))
if (!is_constant (e1) || !is_constant (e2))
return e;
i1 = expr_short (e1);
@ -1019,7 +995,7 @@ do_op_struct (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
type_t *type;
if (op != '=' && op != 'm')
if (op != 'm')
return error (e1, "invalid operator for struct");
if ((type = get_type (e1)) != get_type (e2))
return type_mismatch (e1, e2, op);

View File

@ -75,7 +75,6 @@ get_op_string (int op)
case GE: return ">=";
case LT: return "<";
case GT: return ">";
case '=': return "=";
case '+': return "+";
case '-': return "-";
case '*': return "*";
@ -343,22 +342,38 @@ 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);
_print_expr (dstr, e->e.address.lvalue, 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);
e->e.address.lvalue);
if (e->e.address.offset) {
_print_expr (dstr, e->e.address.offset, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"+\"];\n", indent, "", e,
e->e.alias.offset);
e->e.address.offset);
}
dstring_t *typestr = dstring_newstr();
print_type_str (typestr, e->e.alias.type);
print_type_str (typestr, e->e.address.type);
dasprintf (dstr, "%*se_%p [label=\"%s (%s)\\n%d\"];\n", indent, "", e,
"&", typestr->str, e->line);
dstring_delete (typestr);
}
static void
print_assign (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
int indent = level * 2 + 2;
_print_expr (dstr, e->e.assign.dst, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"lval\"];\n", indent, "", e,
e->e.assign.dst);
_print_expr (dstr, e->e.assign.src, level, id, next);
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"rval\"];\n", indent, "", e,
e->e.assign.src);
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
"=", e->line);
}
static void
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
@ -603,6 +618,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
[ex_memset] = print_memset,
[ex_alias] = print_alias,
[ex_address] = print_address,
[ex_assign] = print_assign,
};
int indent = level * 2 + 2;

View File

@ -262,6 +262,8 @@ get_type (expr_t *e)
return e->e.alias.type;
case ex_address:
return e->e.address.type;
case ex_assign:
return get_type (e->e.assign.dst);
case ex_count:
internal_error (e, "invalid expression");
}
@ -485,6 +487,12 @@ copy_expr (expr_t *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_assign:
n = new_expr ();
*n = *e;
n->e.assign.dst = copy_expr (e->e.assign.dst);
n->e.assign.src = copy_expr (e->e.assign.src);
return n;
case ex_count:
break;
}
@ -1296,6 +1304,16 @@ new_address_expr (type_t *lvtype, expr_t *lvalue, expr_t *offset)
return addr;
}
expr_t *
new_assign_expr (expr_t *dst, expr_t *src)
{
expr_t *addr = new_expr ();
addr->type = ex_assign;
addr->e.assign.dst = dst;
addr->e.assign.src = src;
return addr;
}
static expr_t *
param_expr (const char *name, type_t *type)
{
@ -1610,6 +1628,9 @@ has_function_call (expr_t *e)
return has_function_call (e->e.alias.expr);
case ex_address:
return has_function_call (e->e.address.lvalue);
case ex_assign:
return (has_function_call (e->e.assign.dst)
|| has_function_call (e->e.assign.src));
case ex_error:
case ex_state:
case ex_label:
@ -1733,6 +1754,7 @@ unary_expr (int op, expr_t *e)
case ex_temp:
case ex_vector:
case ex_alias:
case ex_assign:
{
expr_t *n = new_unary_expr (op, e);
@ -1819,6 +1841,7 @@ unary_expr (int op, expr_t *e)
case ex_vector:
case ex_alias:
case ex_address:
case ex_assign:
{
expr_t *n = new_unary_expr (op, e);
@ -1896,6 +1919,7 @@ unary_expr (int op, expr_t *e)
case ex_temp:
case ex_vector:
case ex_alias:
case ex_assign:
bitnot_expr:
if (options.code.progsversion == PROG_ID_VERSION) {
expr_t *n1 = new_integer_expr (-1);

View File

@ -117,6 +117,8 @@ is_lvalue (const expr_t *expr)
return is_lvalue (expr->e.alias.expr);
case ex_address:
return 0;
case ex_assign:
return 0;
case ex_uexpr:
if (expr->e.expr.op == '.') {
return 1;
@ -283,7 +285,6 @@ is_memset (expr_t *e)
expr_t *
assign_expr (expr_t *dst, expr_t *src)
{
int op = '=';
expr_t *expr;
type_t *dst_type, *src_type;
@ -355,7 +356,6 @@ assign_expr (expr_t *dst, expr_t *src)
convert_nil (src, dst_type);
}
expr = new_binary_expr (op, dst, src);
expr->e.expr.type = dst_type;
expr = new_assign_expr (dst, src);
return expr;
}

View File

@ -249,16 +249,16 @@ convert_bool (expr_t *e, int block)
{
expr_t *b;
if (e->type == ex_expr && e->e.expr.op == '=') {
if (e->type == ex_assign) {
expr_t *src;
if (!e->paren && options.warnings.precedence)
warning (e, "suggest parentheses around assignment "
"used as truth value");
src = e->e.expr.e2;
src = e->e.assign.src;
if (src->type == ex_block) {
src = new_temp_def_expr (get_type (src));
e = new_binary_expr (e->e.expr.op, e->e.expr.e1,
assign_expr (src, e->e.expr.e2));
e = new_assign_expr (e->e.assign.dst,
assign_expr (src, e->e.assign.src));
}
b = convert_bool (src, 1);
if (b->type == ex_error)

View File

@ -574,7 +574,6 @@ convert_op (int op)
case GE: return ">=";
case LT: return "<";
case GT: return ">";
case '=': return "=";
case '+': return "+";
case '-': return "-";
case '*': return "*";
@ -819,8 +818,8 @@ static sblock_t *
expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src)
{
statement_t *s;
expr_t *dst_expr = e->e.expr.e1;
expr_t *src_expr = e->e.expr.e2;
expr_t *dst_expr = e->e.assign.dst;
expr_t *src_expr = e->e.assign.src;
type_t *dst_type = get_type (dst_expr);
type_t *src_type = get_type (src_expr);
unsigned count;
@ -912,16 +911,16 @@ static sblock_t *
expr_assign (sblock_t *sblock, expr_t *e, operand_t **op)
{
statement_t *s;
expr_t *src_expr = e->e.expr.e2;
expr_t *dst_expr = e->e.expr.e1;
expr_t *src_expr = e->e.assign.src;
expr_t *dst_expr = e->e.assign.dst;
type_t *dst_type = get_type (dst_expr);
operand_t *src = 0;
operand_t *dst = 0;
operand_t *ofs = 0;
const char *opcode = convert_op (e->e.expr.op);
const char *opcode = "=";
st_type_t type;
if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') {
if (src_expr->type == ex_assign) {
sblock = statement_subexpr (sblock, src_expr, &src);
if (is_structural (dst_type)) {
return expr_assign_copy (sblock, e, op, src);
@ -1267,9 +1266,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op)
case 'c':
sblock = expr_call (sblock, e, op);
break;
case '=':
sblock = expr_assign (sblock, e, op);
break;
case 'm':
case 'M':
sblock = expr_move (sblock, e, op);
@ -1528,6 +1524,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op)
[ex_selector] = expr_selector,
[ex_alias] = expr_alias,
[ex_address] = expr_address,
[ex_assign] = expr_assign,
};
if (!e) {
*op = 0;
@ -1574,6 +1571,10 @@ build_bool_block (expr_t *block, expr_t *e)
e->next = 0;
append_expr (block, e);
return;
case ex_assign:
e->next = 0;
append_expr (block, e);
return;
case ex_expr:
if (e->e.expr.op == OR || e->e.expr.op == AND) {
build_bool_block (block, e->e.expr.e1);
@ -1735,9 +1736,6 @@ statement_expr (sblock_t *sblock, expr_t *e)
case IFA:
sblock = statement_branch (sblock, e);
break;
case '=':
sblock = expr_assign (sblock, e, 0);
break;
case 'm':
case 'M':
sblock = expr_move (sblock, e, 0);
@ -1818,6 +1816,12 @@ statement_memset (sblock_t *sblock, expr_t *e)
return sblock;
}
static sblock_t *
statement_assign (sblock_t *sblock, expr_t *e)
{
return expr_assign (sblock, e, 0);
}
static sblock_t *
statement_nonexec (sblock_t *sblock, expr_t *e)
{
@ -1844,6 +1848,7 @@ statement_slist (sblock_t *sblock, expr_t *e)
[ex_nil] = statement_nonexec,
[ex_value] = statement_nonexec,
[ex_memset] = statement_memset,
[ex_assign] = statement_assign,
};
for (/**/; e; e = e->next) {