mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-20 07:50:45 +00:00
[qfcc] Give branch expressions their own type
This includes calls and unconditional jumps, relative and through a table. The parameters are all lumped into the one object, with some being unused by the different types (eg, args and ret_type used only by call expressions). Just having nice names for the parameters (instead of e1 and e2) makes it nice, even with all the sub-types lumped together. No mysterious type aliasing bugs this time ;)
This commit is contained in:
parent
09002c17e6
commit
563de20208
11 changed files with 263 additions and 198 deletions
|
@ -224,6 +224,15 @@ typedef struct {
|
||||||
struct expr_s *src; ///< source of assignment
|
struct expr_s *src; ///< source of assignment
|
||||||
} ex_assign_t;
|
} ex_assign_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pr_branch_e type; ///< type of branch
|
||||||
|
struct expr_s *target; ///< destination of branch
|
||||||
|
struct expr_s *index; ///< index for indirect branches
|
||||||
|
struct expr_s *test; ///< test expression (null for jump/call)
|
||||||
|
struct expr_s *args; ///< only for call
|
||||||
|
struct type_s *ret_type; ///< void for non-call
|
||||||
|
} ex_branch_t;
|
||||||
|
|
||||||
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
|
#define POINTER_VAL(p) (((p).def ? (p).def->offset : 0) + (p).val)
|
||||||
|
|
||||||
typedef struct expr_s {
|
typedef struct expr_s {
|
||||||
|
@ -253,6 +262,7 @@ typedef struct expr_s {
|
||||||
ex_alias_t alias; ///< alias expr params
|
ex_alias_t alias; ///< alias expr params
|
||||||
ex_address_t address; ///< alias expr params
|
ex_address_t address; ///< alias expr params
|
||||||
ex_assign_t assign; ///< assignment expr params
|
ex_assign_t assign; ///< assignment expr params
|
||||||
|
ex_branch_t branch; ///< branch expr params
|
||||||
struct type_s *nil; ///< type for nil if known
|
struct type_s *nil; ///< type for nil if known
|
||||||
} e;
|
} e;
|
||||||
} expr_t;
|
} expr_t;
|
||||||
|
@ -718,6 +728,8 @@ expr_t *function_expr (expr_t *e1, expr_t *e2);
|
||||||
struct function_s;
|
struct function_s;
|
||||||
expr_t *branch_expr (int op, expr_t *test, expr_t *label);
|
expr_t *branch_expr (int op, expr_t *test, expr_t *label);
|
||||||
expr_t *goto_expr (expr_t *label);
|
expr_t *goto_expr (expr_t *label);
|
||||||
|
expr_t *jump_table_expr (expr_t *table, expr_t *index);
|
||||||
|
expr_t *call_expr (expr_t *func, expr_t *args, struct type_s *ret_type);
|
||||||
expr_t *return_expr (struct function_s *f, expr_t *e);
|
expr_t *return_expr (struct function_s *f, expr_t *e);
|
||||||
expr_t *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2);
|
expr_t *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2);
|
||||||
expr_t *incop_expr (int op, expr_t *e, int postop);
|
expr_t *incop_expr (int op, expr_t *e, int postop);
|
||||||
|
|
|
@ -56,6 +56,7 @@ EX_EXPR(compound) ///< compound initializer
|
||||||
EX_EXPR(memset) ///< memset needs three params...
|
EX_EXPR(memset) ///< memset needs three params...
|
||||||
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t)
|
EX_EXPR(alias) ///< view expression as different type (::ex_alias_t)
|
||||||
EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t)
|
EX_EXPR(address) ///< address of an lvalue expression (::ex_address_t)
|
||||||
EX_EXPR(assign) ///< assignment of src expr to dst expr
|
EX_EXPR(assign) ///< assignment of src expr to dst expr (::ex_assing_t)
|
||||||
|
EX_EXPR(branch) ///< branch expression (::ex_branch_t)
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
|
@ -575,10 +575,6 @@ do_op_field (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
static expr_t *
|
static expr_t *
|
||||||
do_op_func (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
do_op_func (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
{
|
{
|
||||||
if (op == 'c') {
|
|
||||||
e->e.expr.type = get_type (e1)->t.func.type;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
if (op == EQ || op == NE) {
|
if (op == EQ || op == NE) {
|
||||||
if (options.code.progsversion > PROG_ID_VERSION)
|
if (options.code.progsversion > PROG_ID_VERSION)
|
||||||
e->e.expr.type = &type_integer;
|
e->e.expr.type = &type_integer;
|
||||||
|
@ -593,7 +589,7 @@ static expr_t *
|
||||||
do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
{
|
{
|
||||||
type_t *type;
|
type_t *type;
|
||||||
static int valid[] = {'-', 'M', '.', EQ, NE, 0};
|
static int valid[] = {'-', '.', EQ, NE, 0};
|
||||||
|
|
||||||
if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) {
|
if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) {
|
||||||
// pointer arithmetic
|
// pointer arithmetic
|
||||||
|
@ -623,8 +619,7 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
else
|
else
|
||||||
e->e.expr.type = &type_float;
|
e->e.expr.type = &type_float;
|
||||||
}
|
}
|
||||||
if (op != '.' && op != 'M'
|
if (op != '.' && extract_type (e1) != extract_type (e2))
|
||||||
&& extract_type (e1) != extract_type (e2))
|
|
||||||
return type_mismatch (e1, e2, op);
|
return type_mismatch (e1, e2, op);
|
||||||
if (op == '.' && is_uinteger(get_type (e2)))
|
if (op == '.' && is_uinteger(get_type (e2)))
|
||||||
e->e.expr.e2 = cf_cast_expr (&type_integer, e2);
|
e->e.expr.e2 = cf_cast_expr (&type_integer, e2);
|
||||||
|
@ -993,14 +988,7 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
static expr_t *
|
static expr_t *
|
||||||
do_op_struct (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
do_op_struct (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
{
|
{
|
||||||
type_t *type;
|
return error (e1, "invalid operator for struct");
|
||||||
|
|
||||||
if (op != 'm')
|
|
||||||
return error (e1, "invalid operator for struct");
|
|
||||||
if ((type = get_type (e1)) != get_type (e2))
|
|
||||||
return type_mismatch (e1, e2, op);
|
|
||||||
e->e.expr.type = type;
|
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static expr_t *
|
static expr_t *
|
||||||
|
@ -1036,8 +1024,6 @@ do_op_invalid (int op, expr_t *e, expr_t *e1, expr_t *e2)
|
||||||
type_t *t1 = get_type (e1);
|
type_t *t1 = get_type (e1);
|
||||||
type_t *t2 = get_type (e2);
|
type_t *t2 = get_type (e2);
|
||||||
|
|
||||||
if (e->e.expr.op == 'm')
|
|
||||||
return e; // assume the rest of the compiler got it right
|
|
||||||
if (is_scalar (t1) && is_scalar (t2)) {
|
if (is_scalar (t1) && is_scalar (t2)) {
|
||||||
// one or both expressions are an enum, and the other is one of
|
// one or both expressions are an enum, and the other is one of
|
||||||
// int, float or short. Treat the enum as the other type, or as
|
// int, float or short. Treat the enum as the other type, or as
|
||||||
|
@ -1694,7 +1680,7 @@ fold_constants (expr_t *e)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
op = e->e.expr.op;
|
op = e->e.expr.op;
|
||||||
if (op == 'g' || op == 'r')
|
if (op == 'r')
|
||||||
return e;
|
return e;
|
||||||
t1 = extract_type (e1);
|
t1 = extract_type (e1);
|
||||||
if (t1 >= ev_type_count || !do_unary_op[t1]) {
|
if (t1 >= ev_type_count || !do_unary_op[t1]) {
|
||||||
|
@ -1710,9 +1696,6 @@ fold_constants (expr_t *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
op = e->e.expr.op;
|
op = e->e.expr.op;
|
||||||
if (op == 'i' || op == 'n' || op == 'c') {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
t1 = extract_type (e1);
|
t1 = extract_type (e1);
|
||||||
t2 = extract_type (e2);
|
t2 = extract_type (e2);
|
||||||
|
|
|
@ -89,18 +89,8 @@ get_op_string (int op)
|
||||||
case SHL: return "<<";
|
case SHL: return "<<";
|
||||||
case SHR: return ">>";
|
case SHR: return ">>";
|
||||||
case '.': return ".";
|
case '.': return ".";
|
||||||
case 'i': return "<if>";
|
|
||||||
case 'n': return "<ifnot>";
|
|
||||||
case IFBE: return "<ifbe>";
|
|
||||||
case IFB: return "<ifb>";
|
|
||||||
case IFAE: return "<ifae>";
|
|
||||||
case IFA: return "<ifa>";
|
|
||||||
case 'g': return "<goto>";
|
|
||||||
case 'r': return "<return>";
|
case 'r': return "<return>";
|
||||||
case 'c': return "<call>";
|
|
||||||
case 'C': return "<cast>";
|
case 'C': return "<cast>";
|
||||||
case 'M': return "<move>";
|
|
||||||
case 'm': return "<move>";
|
|
||||||
default:
|
default:
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
@ -255,62 +245,17 @@ print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
print_call (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
|
||||||
{
|
|
||||||
int indent = level * 2 + 2;
|
|
||||||
expr_t *p;
|
|
||||||
int i, count;
|
|
||||||
expr_t **args;
|
|
||||||
|
|
||||||
for (count = 0, p = e->e.expr.e2; p; p = p->next)
|
|
||||||
count++;
|
|
||||||
args = alloca (count * sizeof (expr_t *));
|
|
||||||
for (i = 0, p = e->e.expr.e2; p; p = p->next, i++)
|
|
||||||
args[count - 1 - i] = p;
|
|
||||||
|
|
||||||
_print_expr (dstr, e->e.expr.e1, level, id, next);
|
|
||||||
dasprintf (dstr, "%*se_%p [label=\"<c>call", indent, "", e);
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
dasprintf (dstr, "|<p%d>p%d", i, i);
|
|
||||||
dasprintf (dstr, "\",shape=record];\n");
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
_print_expr (dstr, args[i], level + 1, id, next);
|
|
||||||
dasprintf (dstr, "%*se_%p:p%d -> e_%p;\n", indent + 2, "", e, i,
|
|
||||||
args[i]);
|
|
||||||
}
|
|
||||||
dasprintf (dstr, "%*se_%p:c -> e_%p;\n", indent, "", e, e->e.expr.e1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
{
|
{
|
||||||
int indent = level * 2 + 2;
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
if (e->e.expr.op == 'c') {
|
_print_expr (dstr, e->e.expr.e1, level, id, next);
|
||||||
print_call (dstr, e, level, id, next);
|
_print_expr (dstr, e->e.expr.e2, level, id, next);
|
||||||
return;
|
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"l\"];\n", indent, "", e,
|
||||||
} else if (e->e.expr.op == 'i' || e->e.expr.op == 'n'
|
e->e.expr.e1);
|
||||||
|| e->e.expr.op == IFB || e->e.expr.op ==IFBE
|
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"r\"];\n", indent, "", e,
|
||||||
|| e->e.expr.op == IFA || e->e.expr.op ==IFAE) {
|
e->e.expr.e2);
|
||||||
_print_expr (dstr, e->e.expr.e1, level, id, next);
|
|
||||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"t\"];\n", indent, "", e,
|
|
||||||
e->e.expr.e1);
|
|
||||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"g\"];\n", indent, "", e,
|
|
||||||
e->e.expr.e2);
|
|
||||||
if (e->next)
|
|
||||||
next = e->next;
|
|
||||||
if (next)
|
|
||||||
dasprintf (dstr, "%*se_%p -> e_%p [constraint=true,"
|
|
||||||
"style=dashed];\n", indent, "", e, next);
|
|
||||||
} else {
|
|
||||||
_print_expr (dstr, e->e.expr.e1, level, id, next);
|
|
||||||
_print_expr (dstr, e->e.expr.e2, level, id, next);
|
|
||||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"l\"];\n", indent, "", e,
|
|
||||||
e->e.expr.e1);
|
|
||||||
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"r\"];\n", indent, "", e,
|
|
||||||
e->e.expr.e2);
|
|
||||||
}
|
|
||||||
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
|
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
|
||||||
get_op_string (e->e.expr.op), e->line);
|
get_op_string (e->e.expr.op), e->line);
|
||||||
}
|
}
|
||||||
|
@ -373,13 +318,94 @@ print_assign (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
"=", e->line);
|
"=", e->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_conditional (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
|
{
|
||||||
|
int indent = level * 2 + 2;
|
||||||
|
static const char *condition[] = {
|
||||||
|
"ifz", "ifb", "ifa", 0, "ifnz", "ifnb", "ifna", 0
|
||||||
|
};
|
||||||
|
|
||||||
|
_print_expr (dstr, e->e.branch.test, level, id, next);
|
||||||
|
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"t\"];\n", indent, "", e,
|
||||||
|
e->e.branch.test);
|
||||||
|
dasprintf (dstr, "%*se_%p -> \"e_%p\" [label=\"g\"];\n", indent, "", e,
|
||||||
|
e->e.branch.target);
|
||||||
|
if (e->next) {
|
||||||
|
next = e->next;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
dasprintf (dstr, "%*se_%p -> e_%p [constraint=true,"
|
||||||
|
"style=dashed];\n", indent, "", e, next);
|
||||||
|
}
|
||||||
|
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
|
||||||
|
condition [e->e.branch.type], e->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_jump (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
|
{
|
||||||
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
_print_expr (dstr, e->e.branch.target, level, id, next);
|
||||||
|
dasprintf (dstr, "%*se_%p [label=\"%s\\n%d\"];\n", indent, "", e,
|
||||||
|
"jump", e->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_call (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
|
{
|
||||||
|
int indent = level * 2 + 2;
|
||||||
|
expr_t *p;
|
||||||
|
int i, count;
|
||||||
|
expr_t **args;
|
||||||
|
|
||||||
|
for (count = 0, p = e->e.branch.args; p; p = p->next)
|
||||||
|
count++;
|
||||||
|
args = alloca (count * sizeof (expr_t *));
|
||||||
|
for (i = 0, p = e->e.branch.args; p; p = p->next, i++)
|
||||||
|
args[count - 1 - i] = p;
|
||||||
|
|
||||||
|
_print_expr (dstr, e->e.branch.target, level, id, next);
|
||||||
|
dasprintf (dstr, "%*se_%p [label=\"<c>call", indent, "", e);
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
dasprintf (dstr, "|<p%d>p%d", i, i);
|
||||||
|
dasprintf (dstr, "\",shape=record];\n");
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
_print_expr (dstr, args[i], level + 1, id, next);
|
||||||
|
dasprintf (dstr, "%*se_%p:p%d -> e_%p;\n", indent + 2, "", e, i,
|
||||||
|
args[i]);
|
||||||
|
}
|
||||||
|
dasprintf (dstr, "%*se_%p:c -> e_%p;\n", indent, "", e,
|
||||||
|
e->e.branch.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_branch (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
|
{
|
||||||
|
switch (e->e.branch.type) {
|
||||||
|
case pr_branch_eq:
|
||||||
|
case pr_branch_lt:
|
||||||
|
case pr_branch_gt:
|
||||||
|
case pr_branch_ne:
|
||||||
|
case pr_branch_ge:
|
||||||
|
case pr_branch_le:
|
||||||
|
print_conditional (dstr, e, level, id, next);
|
||||||
|
break;
|
||||||
|
case pr_branch_jump:
|
||||||
|
print_jump (dstr, e, level, id, next);
|
||||||
|
break;
|
||||||
|
case pr_branch_call:
|
||||||
|
print_call (dstr, e, level, id, next);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
{
|
{
|
||||||
int indent = level * 2 + 2;
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
if (e->e.expr.op != 'g' && e->e.expr.e1)
|
|
||||||
_print_expr (dstr, e->e.expr.e1, level, id, next);
|
|
||||||
if (e->e.expr.op != 'r' || e->e.expr.e1)
|
if (e->e.expr.op != 'r' || e->e.expr.e1)
|
||||||
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e,
|
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e,
|
||||||
e->e.expr.e1);
|
e->e.expr.e1);
|
||||||
|
@ -618,6 +644,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
[ex_alias] = print_alias,
|
[ex_alias] = print_alias,
|
||||||
[ex_address] = print_address,
|
[ex_address] = print_address,
|
||||||
[ex_assign] = print_assign,
|
[ex_assign] = print_assign,
|
||||||
|
[ex_branch] = print_branch,
|
||||||
};
|
};
|
||||||
int indent = level * 2 + 2;
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
|
|
@ -215,8 +215,10 @@ get_type (expr_t *e)
|
||||||
const type_t *type = 0;
|
const type_t *type = 0;
|
||||||
convert_name (e);
|
convert_name (e);
|
||||||
switch (e->type) {
|
switch (e->type) {
|
||||||
|
case ex_branch:
|
||||||
case ex_labelref:
|
case ex_labelref:
|
||||||
return &type_void;
|
type = e->e.branch.ret_type;
|
||||||
|
break;
|
||||||
case ex_memset:
|
case ex_memset:
|
||||||
return e->e.memset.type;
|
return e->e.memset.type;
|
||||||
case ex_label:
|
case ex_label:
|
||||||
|
@ -495,6 +497,13 @@ copy_expr (expr_t *e)
|
||||||
n->e.assign.dst = copy_expr (e->e.assign.dst);
|
n->e.assign.dst = copy_expr (e->e.assign.dst);
|
||||||
n->e.assign.src = copy_expr (e->e.assign.src);
|
n->e.assign.src = copy_expr (e->e.assign.src);
|
||||||
return n;
|
return n;
|
||||||
|
case ex_branch:
|
||||||
|
n = new_expr ();
|
||||||
|
*n = *e;
|
||||||
|
n->e.branch.target = copy_expr (e->e.branch.target);
|
||||||
|
n->e.branch.test = copy_expr (e->e.branch.test);
|
||||||
|
n->e.branch.args = copy_expr (e->e.branch.args);
|
||||||
|
return n;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1591,14 +1600,10 @@ has_function_call (expr_t *e)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
case ex_expr:
|
case ex_expr:
|
||||||
if (e->e.expr.op == 'c')
|
|
||||||
return 1;
|
|
||||||
return (has_function_call (e->e.expr.e1)
|
return (has_function_call (e->e.expr.e1)
|
||||||
|| has_function_call (e->e.expr.e2));
|
|| has_function_call (e->e.expr.e2));
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op != 'g')
|
return has_function_call (e->e.expr.e1);
|
||||||
return has_function_call (e->e.expr.e1);
|
|
||||||
return 0;
|
|
||||||
case ex_alias:
|
case ex_alias:
|
||||||
return has_function_call (e->e.alias.expr);
|
return has_function_call (e->e.alias.expr);
|
||||||
case ex_address:
|
case ex_address:
|
||||||
|
@ -1606,6 +1611,14 @@ has_function_call (expr_t *e)
|
||||||
case ex_assign:
|
case ex_assign:
|
||||||
return (has_function_call (e->e.assign.dst)
|
return (has_function_call (e->e.assign.dst)
|
||||||
|| has_function_call (e->e.assign.src));
|
|| has_function_call (e->e.assign.src));
|
||||||
|
case ex_branch:
|
||||||
|
if (e->e.branch.type == pr_branch_call) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (e->e.branch.type == pr_branch_jump) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return has_function_call (e->e.branch.test);
|
||||||
case ex_error:
|
case ex_error:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
case ex_label:
|
case ex_label:
|
||||||
|
@ -1724,6 +1737,8 @@ unary_expr (int op, expr_t *e)
|
||||||
n->e.expr.type = get_type (e);
|
n->e.expr.type = get_type (e);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
case ex_branch:
|
||||||
|
return error (e, "invalid type for unary -");
|
||||||
case ex_expr:
|
case ex_expr:
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
case ex_temp:
|
case ex_temp:
|
||||||
|
@ -1826,6 +1841,7 @@ unary_expr (int op, expr_t *e)
|
||||||
n->e.expr.type = &type_float;
|
n->e.expr.type = &type_float;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
case ex_branch:
|
||||||
case ex_nil:
|
case ex_nil:
|
||||||
return error (e, "invalid type for unary !");
|
return error (e, "invalid type for unary !");
|
||||||
case ex_count:
|
case ex_count:
|
||||||
|
@ -1887,6 +1903,8 @@ unary_expr (int op, expr_t *e)
|
||||||
if (!e->e.block.result)
|
if (!e->e.block.result)
|
||||||
return error (e, "invalid type for unary ~");
|
return error (e, "invalid type for unary ~");
|
||||||
goto bitnot_expr;
|
goto bitnot_expr;
|
||||||
|
case ex_branch:
|
||||||
|
return error (e, "invalid type for unary ~");
|
||||||
case ex_expr:
|
case ex_expr:
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
case ex_def:
|
case ex_def:
|
||||||
|
@ -2072,8 +2090,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]);
|
e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]);
|
||||||
append_expr (call, e);
|
append_expr (call, e);
|
||||||
}
|
}
|
||||||
e = expr_file_line (new_binary_expr ('c', fexpr, args), fexpr);
|
e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr);
|
||||||
e->e.expr.type = ftype->t.func.type;
|
|
||||||
append_expr (call, e);
|
append_expr (call, e);
|
||||||
if (!is_void(ftype->t.func.type)) {
|
if (!is_void(ftype->t.func.type)) {
|
||||||
call->e.block.result = new_ret_expr (ftype->t.func.type);
|
call->e.block.result = new_ret_expr (ftype->t.func.type);
|
||||||
|
@ -2118,21 +2135,70 @@ function_expr (expr_t *fexpr, expr_t *params)
|
||||||
expr_t *
|
expr_t *
|
||||||
branch_expr (int op, expr_t *test, expr_t *label)
|
branch_expr (int op, expr_t *test, expr_t *label)
|
||||||
{
|
{
|
||||||
if (label && label->type != ex_label)
|
// need to translated op due to precedence rules dictating the layout
|
||||||
|
// of the token ids
|
||||||
|
static pr_branch_e branch_type [] = {
|
||||||
|
pr_branch_eq,
|
||||||
|
pr_branch_ne,
|
||||||
|
pr_branch_lt,
|
||||||
|
pr_branch_gt,
|
||||||
|
pr_branch_le,
|
||||||
|
pr_branch_ge,
|
||||||
|
};
|
||||||
|
if (op < EQ || op > LE) {
|
||||||
|
internal_error (label, "invalid op: %d", op);
|
||||||
|
}
|
||||||
|
if (label && label->type != ex_label) {
|
||||||
internal_error (label, "not a label");
|
internal_error (label, "not a label");
|
||||||
if (label)
|
}
|
||||||
|
if (label) {
|
||||||
label->e.label.used++;
|
label->e.label.used++;
|
||||||
return new_binary_expr (op, test, label);
|
}
|
||||||
|
expr_t *branch = new_expr ();
|
||||||
|
branch->type = ex_branch;
|
||||||
|
branch->e.branch.type = branch_type[op - EQ];
|
||||||
|
branch->e.branch.target = label;
|
||||||
|
branch->e.branch.test = test;
|
||||||
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_t *
|
expr_t *
|
||||||
goto_expr (expr_t *label)
|
goto_expr (expr_t *label)
|
||||||
{
|
{
|
||||||
if (label && label->type != ex_label)
|
if (label && label->type != ex_label) {
|
||||||
internal_error (label, "not a label");
|
internal_error (label, "not a label");
|
||||||
if (label)
|
}
|
||||||
|
if (label) {
|
||||||
label->e.label.used++;
|
label->e.label.used++;
|
||||||
return new_unary_expr ('g', label);
|
}
|
||||||
|
expr_t *branch = new_expr ();
|
||||||
|
branch->type = ex_branch;
|
||||||
|
branch->e.branch.type = pr_branch_jump;
|
||||||
|
branch->e.branch.target = label;
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
jump_table_expr (expr_t *table, expr_t *index)
|
||||||
|
{
|
||||||
|
expr_t *branch = new_expr ();
|
||||||
|
branch->type = ex_branch;
|
||||||
|
branch->e.branch.type = pr_branch_jump;
|
||||||
|
branch->e.branch.target = table;//FIXME separate? all branch types can
|
||||||
|
branch->e.branch.index = index;
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
call_expr (expr_t *func, expr_t *args, type_t *ret_type)
|
||||||
|
{
|
||||||
|
expr_t *branch = new_expr ();
|
||||||
|
branch->type = ex_branch;
|
||||||
|
branch->e.branch.type = pr_branch_call;
|
||||||
|
branch->e.branch.target = func;
|
||||||
|
branch->e.branch.args = args;
|
||||||
|
branch->e.branch.ret_type = ret_type;
|
||||||
|
return branch;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_t *
|
expr_t *
|
||||||
|
|
|
@ -124,6 +124,7 @@ is_lvalue (const expr_t *expr)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ex_branch:
|
||||||
case ex_memset:
|
case ex_memset:
|
||||||
case ex_compound:
|
case ex_compound:
|
||||||
case ex_state:
|
case ex_state:
|
||||||
|
|
|
@ -165,12 +165,9 @@ backpatch (ex_list_t *list, expr_t *label)
|
||||||
|
|
||||||
for (i = 0; i < list->size; i++) {
|
for (i = 0; i < list->size; i++) {
|
||||||
e = list->e[i];
|
e = list->e[i];
|
||||||
if (e->type == ex_uexpr && e->e.expr.op == 'g')
|
if (e->type == ex_branch && e->e.branch.type < pr_branch_call) {
|
||||||
e->e.expr.e1 = label;
|
e->e.branch.target = label;
|
||||||
else if (e->type == ex_expr && (e->e.expr.op == 'i'
|
} else {
|
||||||
|| e->e.expr.op == 'n'))
|
|
||||||
e->e.expr.e2 = label;
|
|
||||||
else {
|
|
||||||
internal_error (e, 0);
|
internal_error (e, 0);
|
||||||
}
|
}
|
||||||
label->e.label.used++;
|
label->e.label.used++;
|
||||||
|
@ -299,7 +296,7 @@ convert_bool (expr_t *e, int block)
|
||||||
e = new_bool_expr (0, make_list (b), b);
|
e = new_bool_expr (0, make_list (b), b);
|
||||||
} else {
|
} else {
|
||||||
b = new_block_expr ();
|
b = new_block_expr ();
|
||||||
append_expr (b, branch_expr ('i', e, 0));
|
append_expr (b, branch_expr (NE, e, 0));
|
||||||
append_expr (b, goto_expr (0));
|
append_expr (b, goto_expr (0));
|
||||||
e = new_bool_expr (make_list (b->e.block.head),
|
e = new_bool_expr (make_list (b->e.block.head),
|
||||||
make_list (b->e.block.head->next), b);
|
make_list (b->e.block.head->next), b);
|
||||||
|
|
|
@ -132,7 +132,7 @@ int yylex (void);
|
||||||
%left '^'
|
%left '^'
|
||||||
%left '&'
|
%left '&'
|
||||||
%left EQ NE
|
%left EQ NE
|
||||||
%left LE GE LT GT
|
%left LT GT GE LE
|
||||||
// end of tokens common between qc and qp
|
// end of tokens common between qc and qp
|
||||||
|
|
||||||
%left SHL SHR
|
%left SHL SHR
|
||||||
|
@ -146,7 +146,7 @@ int yylex (void);
|
||||||
%token <expr> VALUE STRING
|
%token <expr> VALUE STRING
|
||||||
|
|
||||||
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS
|
%token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS
|
||||||
%token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM
|
%token NIL GOTO SWITCH CASE DEFAULT ENUM
|
||||||
%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT
|
%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT
|
||||||
%token <op> STRUCT
|
%token <op> STRUCT
|
||||||
%token <type> TYPE
|
%token <type> TYPE
|
||||||
|
|
|
@ -113,7 +113,7 @@ int yylex (void);
|
||||||
%left '^'
|
%left '^'
|
||||||
%left '&'
|
%left '&'
|
||||||
%left EQ NE
|
%left EQ NE
|
||||||
%left LE GE LT GT
|
%left LT GT GE LE
|
||||||
// end of tokens common between qc and qp
|
// end of tokens common between qc and qp
|
||||||
|
|
||||||
%left <op> RELOP
|
%left <op> RELOP
|
||||||
|
|
|
@ -588,12 +588,6 @@ convert_op (int op)
|
||||||
case SHL: return "<<";
|
case SHL: return "<<";
|
||||||
case SHR: return ">>";
|
case SHR: return ">>";
|
||||||
case '.': return ".";
|
case '.': return ".";
|
||||||
case 'i': return "<IF>";
|
|
||||||
case 'n': return "<IFNOT>";
|
|
||||||
case IFBE: return "<IFBE>";
|
|
||||||
case IFB: return "<IFB>";
|
|
||||||
case IFAE: return "<IFAE>";
|
|
||||||
case IFA: return "<IFA>";
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -709,33 +703,6 @@ static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e,
|
||||||
operand_t **op);
|
operand_t **op);
|
||||||
static sblock_t *statement_slist (sblock_t *sblock, expr_t *e);
|
static sblock_t *statement_slist (sblock_t *sblock, expr_t *e);
|
||||||
|
|
||||||
static sblock_t *
|
|
||||||
statement_branch (sblock_t *sblock, expr_t *e)
|
|
||||||
{
|
|
||||||
statement_t *s = 0;
|
|
||||||
const char *opcode;
|
|
||||||
|
|
||||||
if (e->type == ex_uexpr && e->e.expr.op == 'g') {
|
|
||||||
s = new_statement (st_flow, "<GOTO>", e);
|
|
||||||
s->opa = label_operand (e->e.expr.e1);
|
|
||||||
} else {
|
|
||||||
if (e->e.expr.op == 'g') {
|
|
||||||
s = new_statement (st_flow, "<JUMPB>", e);
|
|
||||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
|
||||||
sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb);
|
|
||||||
} else {
|
|
||||||
opcode = convert_op (e->e.expr.op);
|
|
||||||
s = new_statement (st_flow, opcode, e);
|
|
||||||
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
|
|
||||||
s->opb = label_operand (e->e.expr.e2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sblock_add_statement (sblock, s);
|
|
||||||
sblock->next = new_sblock ();
|
|
||||||
return sblock->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
expr_address (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||||
{
|
{
|
||||||
|
@ -1047,12 +1014,11 @@ vector_call (sblock_t *sblock, expr_t *earg, expr_t *param, int ind,
|
||||||
return sblock;
|
return sblock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
{
|
{
|
||||||
expr_t *func = call->e.expr.e1;
|
expr_t *func = call->e.branch.target;
|
||||||
expr_t *args = call->e.expr.e2;
|
expr_t *args = call->e.branch.args;
|
||||||
expr_t *a;
|
expr_t *a;
|
||||||
expr_t *param;
|
expr_t *param;
|
||||||
operand_t *arguments[2] = {0, 0};
|
operand_t *arguments[2] = {0, 0};
|
||||||
|
@ -1113,6 +1079,46 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
return sblock->next;
|
return sblock->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static sblock_t *
|
||||||
|
statement_branch (sblock_t *sblock, expr_t *e)
|
||||||
|
{
|
||||||
|
static const char *opcodes[] = {
|
||||||
|
"<IFNOT>",
|
||||||
|
"<IFB>",
|
||||||
|
"<IFA>",
|
||||||
|
0, // special handling
|
||||||
|
"<IF>",
|
||||||
|
"<IFAE>",
|
||||||
|
"<IFBE>",
|
||||||
|
0, // not used here
|
||||||
|
};
|
||||||
|
statement_t *s = 0;
|
||||||
|
const char *opcode;
|
||||||
|
|
||||||
|
if (e->e.branch.type == pr_branch_call) {
|
||||||
|
return expr_call (sblock, e, 0);
|
||||||
|
}
|
||||||
|
if (e->e.branch.type == pr_branch_jump) {
|
||||||
|
if (e->e.branch.index) {
|
||||||
|
s = new_statement (st_flow, "<JUMPB>", e);
|
||||||
|
sblock = statement_subexpr (sblock, e->e.branch.target, &s->opa);
|
||||||
|
sblock = statement_subexpr (sblock, e->e.branch.index, &s->opb);
|
||||||
|
} else {
|
||||||
|
s = new_statement (st_flow, "<GOTO>", e);
|
||||||
|
s->opa = label_operand (e->e.branch.target);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opcode = opcodes [e->e.branch.type];
|
||||||
|
s = new_statement (st_flow, opcode, e);
|
||||||
|
sblock = statement_subexpr (sblock, e->e.branch.test, &s->opa);
|
||||||
|
s->opb = label_operand (e->e.branch.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
sblock_add_statement (sblock, s);
|
||||||
|
sblock->next = new_sblock ();
|
||||||
|
return sblock->next;
|
||||||
|
}
|
||||||
|
|
||||||
static statement_t *
|
static statement_t *
|
||||||
lea_statement (operand_t *pointer, operand_t *offset, expr_t *e)
|
lea_statement (operand_t *pointer, operand_t *offset, expr_t *e)
|
||||||
{
|
{
|
||||||
|
@ -1261,9 +1267,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op)
|
||||||
statement_t *s;
|
statement_t *s;
|
||||||
|
|
||||||
switch (e->e.expr.op) {
|
switch (e->e.expr.op) {
|
||||||
case 'c':
|
|
||||||
sblock = expr_call (sblock, e, op);
|
|
||||||
break;
|
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
sblock = expr_move (sblock, e, op);
|
sblock = expr_move (sblock, e, op);
|
||||||
|
@ -1573,27 +1576,20 @@ build_bool_block (expr_t *block, expr_t *e)
|
||||||
e->next = 0;
|
e->next = 0;
|
||||||
append_expr (block, e);
|
append_expr (block, e);
|
||||||
return;
|
return;
|
||||||
|
case ex_branch:
|
||||||
|
e->next = 0;
|
||||||
|
append_expr (block, e);
|
||||||
|
return;
|
||||||
case ex_expr:
|
case ex_expr:
|
||||||
if (e->e.expr.op == OR || e->e.expr.op == AND) {
|
if (e->e.expr.op == OR || e->e.expr.op == AND) {
|
||||||
build_bool_block (block, e->e.expr.e1);
|
build_bool_block (block, e->e.expr.e1);
|
||||||
build_bool_block (block, e->e.expr.e2);
|
build_bool_block (block, e->e.expr.e2);
|
||||||
} else if (e->e.expr.op == 'i') {
|
|
||||||
e->next = 0;
|
|
||||||
append_expr (block, e);
|
|
||||||
} else if (e->e.expr.op == 'n') {
|
|
||||||
e->next = 0;
|
|
||||||
append_expr (block, e);
|
|
||||||
} else {
|
} else {
|
||||||
e->next = 0;
|
e->next = 0;
|
||||||
append_expr (block, e);
|
append_expr (block, e);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == 'g') {
|
|
||||||
e->next = 0;
|
|
||||||
append_expr (block, e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ex_block:
|
case ex_block:
|
||||||
if (!e->e.block.result) {
|
if (!e->e.block.result) {
|
||||||
|
@ -1614,19 +1610,20 @@ build_bool_block (expr_t *block, expr_t *e)
|
||||||
static int
|
static int
|
||||||
is_goto_expr (expr_t *e)
|
is_goto_expr (expr_t *e)
|
||||||
{
|
{
|
||||||
return e && e->type == ex_uexpr && e->e.expr.op == 'g';
|
return e && e->type == ex_branch && e->e.branch.type == pr_branch_jump
|
||||||
|
&& !e->e.branch.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_if_expr (expr_t *e)
|
is_if_expr (expr_t *e)
|
||||||
{
|
{
|
||||||
return e && e->type == ex_expr && e->e.expr.op == 'i';
|
return e && e->type == ex_branch && e->e.branch.type == pr_branch_ne;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_ifnot_expr (expr_t *e)
|
is_ifnot_expr (expr_t *e)
|
||||||
{
|
{
|
||||||
return e && e->type == ex_expr && e->e.expr.op == 'n';
|
return e && e->type == ex_branch && e->e.branch.type == pr_branch_eq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static sblock_t *
|
static sblock_t *
|
||||||
|
@ -1641,33 +1638,33 @@ statement_bool (sblock_t *sblock, expr_t *e)
|
||||||
s = &block->e.block.head;
|
s = &block->e.block.head;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
if (is_if_expr (*s) && is_goto_expr ((*s)->next)) {
|
if (is_if_expr (*s) && is_goto_expr ((*s)->next)) {
|
||||||
l = (*s)->e.expr.e2;
|
l = (*s)->e.branch.target;
|
||||||
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
||||||
if (e == l) {
|
if (e == l) {
|
||||||
l->e.label.used--;
|
l->e.label.used--;
|
||||||
e = *s;
|
e = *s;
|
||||||
e->e.expr.op = 'n';
|
e->e.branch.type = pr_branch_eq;
|
||||||
e->e.expr.e2 = e->next->e.expr.e1;
|
e->e.branch.target = e->next->e.branch.target;
|
||||||
e->next = e->next->next;
|
e->next = e->next->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = &(*s)->next;
|
s = &(*s)->next;
|
||||||
} else if (is_ifnot_expr (*s) && is_goto_expr ((*s)->next)) {
|
} else if (is_ifnot_expr (*s) && is_goto_expr ((*s)->next)) {
|
||||||
l = (*s)->e.expr.e2;
|
l = (*s)->e.branch.target;
|
||||||
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
||||||
if (e == l) {
|
if (e == l) {
|
||||||
l->e.label.used--;
|
l->e.label.used--;
|
||||||
e = *s;
|
e = *s;
|
||||||
e->e.expr.op = 'i';
|
e->e.branch.type = pr_branch_ne;
|
||||||
e->e.expr.e2 = e->next->e.expr.e1;
|
e->e.branch.target = e->next->e.branch.target;
|
||||||
e->next = e->next->next;
|
e->next = e->next->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = &(*s)->next;
|
s = &(*s)->next;
|
||||||
} else if (is_goto_expr (*s)) {
|
} else if (is_goto_expr (*s)) {
|
||||||
l = (*s)->e.expr.e1;
|
l = (*s)->e.branch.target;
|
||||||
for (e = (*s)->next; e && e->type == ex_label; e = e->next) {
|
for (e = (*s)->next; e && e->type == ex_label; e = e->next) {
|
||||||
if (e == l) {
|
if (e == l) {
|
||||||
l->e.label.used--;
|
l->e.label.used--;
|
||||||
|
@ -1722,18 +1719,6 @@ static sblock_t *
|
||||||
statement_expr (sblock_t *sblock, expr_t *e)
|
statement_expr (sblock_t *sblock, expr_t *e)
|
||||||
{
|
{
|
||||||
switch (e->e.expr.op) {
|
switch (e->e.expr.op) {
|
||||||
case 'c':
|
|
||||||
sblock = expr_call (sblock, e, 0);
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
case 'i':
|
|
||||||
case 'n':
|
|
||||||
case IFBE:
|
|
||||||
case IFB:
|
|
||||||
case IFAE:
|
|
||||||
case IFA:
|
|
||||||
sblock = statement_branch (sblock, e);
|
|
||||||
break;
|
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
sblock = expr_move (sblock, e, 0);
|
sblock = expr_move (sblock, e, 0);
|
||||||
|
@ -1776,9 +1761,6 @@ statement_uexpr (sblock_t *sblock, expr_t *e)
|
||||||
sblock->next = new_sblock ();
|
sblock->next = new_sblock ();
|
||||||
sblock = sblock->next;
|
sblock = sblock->next;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
|
||||||
sblock = statement_branch (sblock, e);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
debug (e, "e ue %d", e->e.expr.op);
|
debug (e, "e ue %d", e->e.expr.op);
|
||||||
if (options.warnings.executable)
|
if (options.warnings.executable)
|
||||||
|
@ -1847,6 +1829,7 @@ statement_slist (sblock_t *sblock, expr_t *e)
|
||||||
[ex_value] = statement_nonexec,
|
[ex_value] = statement_nonexec,
|
||||||
[ex_memset] = statement_memset,
|
[ex_memset] = statement_memset,
|
||||||
[ex_assign] = statement_assign,
|
[ex_assign] = statement_assign,
|
||||||
|
[ex_branch] = statement_branch,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (/**/; e; e = e->next) {
|
for (/**/; e; e = e->next) {
|
||||||
|
@ -2115,24 +2098,19 @@ search_for_super_dealloc (sblock_t *sblock)
|
||||||
if (!statement_is_call (st)) {
|
if (!statement_is_call (st)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// effectively checks target
|
||||||
if (st->opa->op_type != op_def
|
if (st->opa->op_type != op_def
|
||||||
|| strcmp (st->opa->def->name, "obj_msgSend_super") != 0) {
|
|| strcmp (st->opa->def->name, "obj_msgSend_super") != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// FIXME this is messy (calls should have their own expression
|
|
||||||
// type)
|
|
||||||
// have effectively checked e1 above
|
|
||||||
if (st->expr->type != ex_expr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// function arguments are in reverse order, and the selector
|
// function arguments are in reverse order, and the selector
|
||||||
// is the second argument (or second last in the list)
|
// is the second argument (or second last in the list)
|
||||||
expr_t *arg;
|
expr_t *arg;
|
||||||
for (arg = st->expr->e.expr.e2;
|
for (arg = st->expr->e.branch.args;
|
||||||
arg && arg->next && arg->next->next; arg = arg->next) {
|
arg && arg->next && arg->next->next; arg = arg->next) {
|
||||||
}
|
}
|
||||||
if (arg && arg->next && is_selector (arg)) {
|
if (arg && arg->next && is_selector (arg)) {
|
||||||
selector_t *sel = get_selector (st->expr->e.expr.e2);
|
selector_t *sel = get_selector (st->expr->e.branch.args);
|
||||||
if (sel && strcmp (sel->name, "dealloc") == 0) {
|
if (sel && strcmp (sel->name, "dealloc") == 0) {
|
||||||
op = pseudo_operand (super_dealloc, st->expr);
|
op = pseudo_operand (super_dealloc, st->expr);
|
||||||
op->next = st->use;
|
op->next = st->use;
|
||||||
|
|
|
@ -311,12 +311,12 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
|
||||||
append_expr (sw, test);
|
append_expr (sw, test);
|
||||||
|
|
||||||
if (tree->low == tree->high) {
|
if (tree->low == tree->high) {
|
||||||
branch = branch_expr ('n', new_alias_expr (&type_integer, temp),
|
branch = branch_expr (EQ, new_alias_expr (&type_integer, temp),
|
||||||
tree->labels[0]);
|
tree->labels[0]);
|
||||||
append_expr (sw, branch);
|
append_expr (sw, branch);
|
||||||
|
|
||||||
if (tree->left) {
|
if (tree->left) {
|
||||||
branch = branch_expr (IFA, new_alias_expr (&type_integer, temp),
|
branch = branch_expr (GT, new_alias_expr (&type_integer, temp),
|
||||||
high_label);
|
high_label);
|
||||||
append_expr (sw, branch);
|
append_expr (sw, branch);
|
||||||
|
|
||||||
|
@ -352,14 +352,14 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
|
||||||
table_expr = new_symbol_expr (table_sym);
|
table_expr = new_symbol_expr (table_sym);
|
||||||
|
|
||||||
if (tree->left) {
|
if (tree->left) {
|
||||||
branch = branch_expr (IFB, temp, low_label);
|
branch = branch_expr (LT, temp, low_label);
|
||||||
append_expr (sw, branch);
|
append_expr (sw, branch);
|
||||||
}
|
}
|
||||||
test = binary_expr (GT, cast_expr (&type_uinteger, temp),
|
test = binary_expr (GT, cast_expr (&type_uinteger, temp),
|
||||||
cast_expr (&type_uinteger, range));
|
cast_expr (&type_uinteger, range));
|
||||||
branch = branch_expr ('i', test, high_label);
|
branch = branch_expr (NE, test, high_label);
|
||||||
append_expr (sw, branch);
|
append_expr (sw, branch);
|
||||||
branch = new_binary_expr ('g', table_expr, temp);
|
branch = jump_table_expr (table_expr, temp);
|
||||||
append_expr (sw, branch);
|
append_expr (sw, branch);
|
||||||
debug (sw, "switch using jump table");
|
debug (sw, "switch using jump table");
|
||||||
if (tree->left) {
|
if (tree->left) {
|
||||||
|
@ -433,7 +433,7 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
|
||||||
|| num_labels < 8) {
|
|| num_labels < 8) {
|
||||||
for (l = labels; *l; l++) {
|
for (l = labels; *l; l++) {
|
||||||
expr_t *cmp = binary_expr (EQ, sw_val, (*l)->value);
|
expr_t *cmp = binary_expr (EQ, sw_val, (*l)->value);
|
||||||
expr_t *test = branch_expr ('i', test_expr (cmp),
|
expr_t *test = branch_expr (NE, test_expr (cmp),
|
||||||
(*l)->label);
|
(*l)->label);
|
||||||
|
|
||||||
append_expr (sw, test);
|
append_expr (sw, test);
|
||||||
|
|
Loading…
Reference in a new issue