[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:
Bill Currie 2022-01-09 14:02:16 +09:00
parent 09002c17e6
commit 563de20208
11 changed files with 263 additions and 198 deletions

View file

@ -224,6 +224,15 @@ typedef struct {
struct expr_s *src; ///< source of assignment
} 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)
typedef struct expr_s {
@ -253,6 +262,7 @@ typedef struct expr_s {
ex_alias_t alias; ///< alias expr params
ex_address_t address; ///< alias 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
} e;
} expr_t;
@ -718,6 +728,8 @@ expr_t *function_expr (expr_t *e1, expr_t *e2);
struct function_s;
expr_t *branch_expr (int op, expr_t *test, 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 *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2);
expr_t *incop_expr (int op, expr_t *e, int postop);

View file

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

View file

@ -575,10 +575,6 @@ do_op_field (int op, expr_t *e, expr_t *e1, expr_t *e2)
static expr_t *
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 (options.code.progsversion > PROG_ID_VERSION)
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)
{
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 == '+')) {
// pointer arithmetic
@ -623,8 +619,7 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2)
else
e->e.expr.type = &type_float;
}
if (op != '.' && op != 'M'
&& extract_type (e1) != extract_type (e2))
if (op != '.' && extract_type (e1) != extract_type (e2))
return type_mismatch (e1, e2, op);
if (op == '.' && is_uinteger(get_type (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 *
do_op_struct (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
type_t *type;
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;
return error (e1, "invalid operator for struct");
}
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 *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)) {
// 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
@ -1694,7 +1680,7 @@ fold_constants (expr_t *e)
return e;
}
op = e->e.expr.op;
if (op == 'g' || op == 'r')
if (op == 'r')
return e;
t1 = extract_type (e1);
if (t1 >= ev_type_count || !do_unary_op[t1]) {
@ -1710,9 +1696,6 @@ fold_constants (expr_t *e)
}
op = e->e.expr.op;
if (op == 'i' || op == 'n' || op == 'c') {
return e;
}
t1 = extract_type (e1);
t2 = extract_type (e2);

View file

@ -89,18 +89,8 @@ get_op_string (int op)
case SHL: return "<<";
case SHR: 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 'c': return "<call>";
case 'C': return "<cast>";
case 'M': return "<move>";
case 'm': return "<move>";
default:
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
print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
int indent = level * 2 + 2;
if (e->e.expr.op == 'c') {
print_call (dstr, e, level, id, next);
return;
} else if (e->e.expr.op == 'i' || e->e.expr.op == 'n'
|| e->e.expr.op == IFB || e->e.expr.op ==IFBE
|| e->e.expr.op == IFA || e->e.expr.op ==IFAE) {
_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);
}
_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,
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);
}
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
print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
{
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)
dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e,
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_address] = print_address,
[ex_assign] = print_assign,
[ex_branch] = print_branch,
};
int indent = level * 2 + 2;

View file

@ -215,8 +215,10 @@ get_type (expr_t *e)
const type_t *type = 0;
convert_name (e);
switch (e->type) {
case ex_branch:
case ex_labelref:
return &type_void;
type = e->e.branch.ret_type;
break;
case ex_memset:
return e->e.memset.type;
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.src = copy_expr (e->e.assign.src);
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:
break;
}
@ -1591,14 +1600,10 @@ has_function_call (expr_t *e)
return 1;
return 0;
case ex_expr:
if (e->e.expr.op == 'c')
return 1;
return (has_function_call (e->e.expr.e1)
|| has_function_call (e->e.expr.e2));
case ex_uexpr:
if (e->e.expr.op != 'g')
return has_function_call (e->e.expr.e1);
return 0;
return has_function_call (e->e.expr.e1);
case ex_alias:
return has_function_call (e->e.alias.expr);
case ex_address:
@ -1606,6 +1611,14 @@ has_function_call (expr_t *e)
case ex_assign:
return (has_function_call (e->e.assign.dst)
|| 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_state:
case ex_label:
@ -1724,6 +1737,8 @@ unary_expr (int op, expr_t *e)
n->e.expr.type = get_type (e);
return n;
}
case ex_branch:
return error (e, "invalid type for unary -");
case ex_expr:
case ex_bool:
case ex_temp:
@ -1826,6 +1841,7 @@ unary_expr (int op, expr_t *e)
n->e.expr.type = &type_float;
return n;
}
case ex_branch:
case ex_nil:
return error (e, "invalid type for unary !");
case ex_count:
@ -1887,6 +1903,8 @@ unary_expr (int op, expr_t *e)
if (!e->e.block.result)
return error (e, "invalid type for unary ~");
goto bitnot_expr;
case ex_branch:
return error (e, "invalid type for unary ~");
case ex_expr:
case ex_bool:
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]);
append_expr (call, e);
}
e = expr_file_line (new_binary_expr ('c', fexpr, args), fexpr);
e->e.expr.type = ftype->t.func.type;
e = expr_file_line (call_expr (fexpr, args, ftype->t.func.type), fexpr);
append_expr (call, e);
if (!is_void(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 *
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");
if (label)
}
if (label) {
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 *
goto_expr (expr_t *label)
{
if (label && label->type != ex_label)
if (label && label->type != ex_label) {
internal_error (label, "not a label");
if (label)
}
if (label) {
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 *

View file

@ -124,6 +124,7 @@ is_lvalue (const expr_t *expr)
return 1;
}
break;
case ex_branch:
case ex_memset:
case ex_compound:
case ex_state:

View file

@ -165,12 +165,9 @@ backpatch (ex_list_t *list, expr_t *label)
for (i = 0; i < list->size; i++) {
e = list->e[i];
if (e->type == ex_uexpr && e->e.expr.op == 'g')
e->e.expr.e1 = label;
else if (e->type == ex_expr && (e->e.expr.op == 'i'
|| e->e.expr.op == 'n'))
e->e.expr.e2 = label;
else {
if (e->type == ex_branch && e->e.branch.type < pr_branch_call) {
e->e.branch.target = label;
} else {
internal_error (e, 0);
}
label->e.label.used++;
@ -299,7 +296,7 @@ convert_bool (expr_t *e, int block)
e = new_bool_expr (0, make_list (b), b);
} else {
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));
e = new_bool_expr (make_list (b->e.block.head),
make_list (b->e.block.head->next), b);

View file

@ -132,7 +132,7 @@ int yylex (void);
%left '^'
%left '&'
%left EQ NE
%left LE GE LT GT
%left LT GT GE LE
// end of tokens common between qc and qp
%left SHL SHR
@ -146,7 +146,7 @@ int yylex (void);
%token <expr> VALUE STRING
%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 <op> STRUCT
%token <type> TYPE

View file

@ -113,7 +113,7 @@ int yylex (void);
%left '^'
%left '&'
%left EQ NE
%left LE GE LT GT
%left LT GT GE LE
// end of tokens common between qc and qp
%left <op> RELOP

View file

@ -588,12 +588,6 @@ convert_op (int op)
case SHL: return "<<";
case SHR: 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:
return 0;
}
@ -709,33 +703,6 @@ static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e,
operand_t **op);
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 *
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;
}
static sblock_t *
expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
{
expr_t *func = call->e.expr.e1;
expr_t *args = call->e.expr.e2;
expr_t *func = call->e.branch.target;
expr_t *args = call->e.branch.args;
expr_t *a;
expr_t *param;
operand_t *arguments[2] = {0, 0};
@ -1113,6 +1079,46 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
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 *
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;
switch (e->e.expr.op) {
case 'c':
sblock = expr_call (sblock, e, op);
break;
case 'm':
case 'M':
sblock = expr_move (sblock, e, op);
@ -1573,27 +1576,20 @@ build_bool_block (expr_t *block, expr_t *e)
e->next = 0;
append_expr (block, e);
return;
case ex_branch:
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);
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 {
e->next = 0;
append_expr (block, e);
}
return;
case ex_uexpr:
if (e->e.expr.op == 'g') {
e->next = 0;
append_expr (block, e);
return;
}
break;
case ex_block:
if (!e->e.block.result) {
@ -1614,19 +1610,20 @@ build_bool_block (expr_t *block, expr_t *e)
static int
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
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
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 *
@ -1641,33 +1638,33 @@ statement_bool (sblock_t *sblock, expr_t *e)
s = &block->e.block.head;
while (*s) {
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) {
if (e == l) {
l->e.label.used--;
e = *s;
e->e.expr.op = 'n';
e->e.expr.e2 = e->next->e.expr.e1;
e->e.branch.type = pr_branch_eq;
e->e.branch.target = e->next->e.branch.target;
e->next = e->next->next;
break;
}
}
s = &(*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) {
if (e == l) {
l->e.label.used--;
e = *s;
e->e.expr.op = 'i';
e->e.expr.e2 = e->next->e.expr.e1;
e->e.branch.type = pr_branch_ne;
e->e.branch.target = e->next->e.branch.target;
e->next = e->next->next;
break;
}
}
s = &(*s)->next;
} 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) {
if (e == l) {
l->e.label.used--;
@ -1722,18 +1719,6 @@ static sblock_t *
statement_expr (sblock_t *sblock, expr_t *e)
{
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':
sblock = expr_move (sblock, e, 0);
@ -1776,9 +1761,6 @@ statement_uexpr (sblock_t *sblock, expr_t *e)
sblock->next = new_sblock ();
sblock = sblock->next;
break;
case 'g':
sblock = statement_branch (sblock, e);
break;
default:
debug (e, "e ue %d", e->e.expr.op);
if (options.warnings.executable)
@ -1847,6 +1829,7 @@ statement_slist (sblock_t *sblock, expr_t *e)
[ex_value] = statement_nonexec,
[ex_memset] = statement_memset,
[ex_assign] = statement_assign,
[ex_branch] = statement_branch,
};
for (/**/; e; e = e->next) {
@ -2115,24 +2098,19 @@ search_for_super_dealloc (sblock_t *sblock)
if (!statement_is_call (st)) {
continue;
}
// effectively checks target
if (st->opa->op_type != op_def
|| strcmp (st->opa->def->name, "obj_msgSend_super") != 0) {
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
// is the second argument (or second last in the list)
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) {
}
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) {
op = pseudo_operand (super_dealloc, st->expr);
op->next = st->use;

View file

@ -311,12 +311,12 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val,
append_expr (sw, test);
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]);
append_expr (sw, branch);
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);
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);
if (tree->left) {
branch = branch_expr (IFB, temp, low_label);
branch = branch_expr (LT, temp, low_label);
append_expr (sw, branch);
}
test = binary_expr (GT, cast_expr (&type_uinteger, temp),
cast_expr (&type_uinteger, range));
branch = branch_expr ('i', test, high_label);
branch = branch_expr (NE, test, high_label);
append_expr (sw, branch);
branch = new_binary_expr ('g', table_expr, temp);
branch = jump_table_expr (table_expr, temp);
append_expr (sw, branch);
debug (sw, "switch using jump table");
if (tree->left) {
@ -433,7 +433,7 @@ switch_expr (switch_block_t *switch_block, expr_t *break_label,
|| num_labels < 8) {
for (l = labels; *l; l++) {
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);
append_expr (sw, test);