diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2004-08-01 15:56:03 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:02:30 -0700 |
commit | 8e039e099e7aba63590969ceba7a20f208c2bbba (patch) | |
tree | a0e47eca623a27bdc2bbb410cb80779659cfe724 /compile-i386.c | |
parent | [be] minor fixes (diff) | |
download | sparse-8e039e099e7aba63590969ceba7a20f208c2bbba.tar.gz sparse-8e039e099e7aba63590969ceba7a20f208c2bbba.tar.bz2 sparse-8e039e099e7aba63590969ceba7a20f208c2bbba.zip |
[be] fix amazingly stupid conditional expression handling
By virtue of attempting to be too smart, the conditional expression
handling ("x ? foo : bar") would evaluate both 'foo' and 'bar', and
then use the cmov instruction to determine the result, avoiding a
branch in the process.
Unfortunately this only makes sense for simple things (EXPR_VALUE,
EXPR_SYMBOL) and is quite wrong for everything else.
Changed so that 'if' statements and conditional expressions use
largely the same code.
Diffstat (limited to 'compile-i386.c')
-rw-r--r-- | compile-i386.c | 130 |
1 files changed, 69 insertions, 61 deletions
diff --git a/compile-i386.c b/compile-i386.c index 3efb416..289bfe4 100644 --- a/compile-i386.c +++ b/compile-i386.c @@ -1231,64 +1231,70 @@ static struct storage *emit_binop(struct expression *expr) return new; } -static void emit_if_conditional(struct statement *stmt) +static int emit_conditional_test(struct storage *val) { - struct storage *val, *target_val; - int target; - struct expression *cond = stmt->if_conditional; - -/* This is only valid if nobody can jump into the "dead" statement */ -#if 0 - if (cond->type == EXPR_VALUE) { - struct statement *s = stmt->if_true; - if (!cond->value) - s = stmt->if_false; - x86_statement(s); - break; - } -#endif - val = x86_expression(cond); + struct storage *target_val; + int target_false; - /* load 'if' test result into EAX */ - insn("movl", val, REG_EAX, "begin if conditional"); + /* load result into EAX */ + insn("movl", val, REG_EAX, "begin if/conditional"); - /* compare 'if' test result */ + /* compare result with zero */ insn("test", REG_EAX, REG_EAX, NULL); - /* create end-of-if label / if-failed labelto jump to, - * and jump to it if the expression returned zero. - */ - target = new_label(); + /* create conditional-failed label to jump to */ + target_false = new_label(); target_val = new_storage(STOR_LABEL); - target_val->label = target; + target_val->label = target_false; target_val->flags = STOR_WANTS_FREE; insn("jz", target_val, NULL, NULL); - x86_statement(stmt->if_true); - if (stmt->if_false) { - struct storage *last_val; - int last; + return target_false; +} - /* finished generating code for if-true statement. - * add a jump-to-end jump to avoid falling through - * to the if-false statement code. - */ - last = new_label(); - last_val = new_storage(STOR_LABEL); - last_val->label = last; - last_val->flags = STOR_WANTS_FREE; - insn("jmp", last_val, NULL, NULL); - - /* if we have both if-true and if-false statements, - * the failed-conditional case will fall through to here - */ - emit_label(target, NULL); +static int emit_conditional_end(int target_false) +{ + struct storage *cond_end_st; + int cond_end; + + /* finished generating code for if-true statement. + * add a jump-to-end jump to avoid falling through + * to the if-false statement code. + */ + cond_end = new_label(); + cond_end_st = new_storage(STOR_LABEL); + cond_end_st->label = cond_end; + cond_end_st->flags = STOR_WANTS_FREE; + insn("jmp", cond_end_st, NULL, NULL); + + /* if we have both if-true and if-false statements, + * the failed-conditional case will fall through to here + */ + emit_label(target_false, NULL); + + return cond_end; +} + +static void emit_if_conditional(struct statement *stmt) +{ + struct storage *val; + int cond_end; + + /* emit test portion of conditional */ + val = x86_expression(stmt->if_conditional); + cond_end = emit_conditional_test(val); + + /* emit if-true statement */ + x86_statement(stmt->if_true); - target = last; + /* emit if-false statement, if present */ + if (stmt->if_false) { + cond_end = emit_conditional_end(cond_end); x86_statement(stmt->if_false); } - emit_label(target, "end if"); + /* end of conditional; jump target for if-true branch */ + emit_label(cond_end, "end if"); } static struct storage *emit_inc_dec(struct expression *expr, int postop) @@ -1341,29 +1347,31 @@ static struct storage *emit_return_stmt(struct statement *stmt) static struct storage *emit_conditional_expr(struct expression *expr) { - struct storage *cond = x86_expression(expr->conditional); - struct storage *true = x86_expression(expr->cond_true); - struct storage *false = x86_expression(expr->cond_false); - struct storage *new = stack_alloc(4); + struct storage *cond, *true = NULL, *false = NULL; + struct storage *new = stack_alloc(expr->ctype->bit_size / 8); + int target_false, cond_end; - if (!true) + /* evaluate conditional */ + cond = x86_expression(expr->conditional); + target_false = emit_conditional_test(cond); + + /* handle if-true part of the expression */ + if (!expr->cond_true) true = cond; + else + true = x86_expression(expr->cond_true); - emit_move(cond, REG_EAX, expr->conditional->ctype, - "begin EXPR_CONDITIONAL"); - emit_move(true, REG_ECX, expr->cond_true->ctype, NULL); - emit_move(false, REG_EDX, expr->cond_false->ctype, NULL); + emit_copy(new, true, expr->ctype); - /* test EAX (for zero/non-zero) */ - insn("test", REG_EAX, REG_EAX, NULL); + cond_end = emit_conditional_end(target_false); - /* if false, move EDX to ECX */ - insn("cmovz", REG_EDX, REG_ECX, NULL); + /* handle if-false part of the expression */ + false = x86_expression(expr->cond_false); - /* finally, store the result (ECX) in a new pseudo / stack slot */ - new = stack_alloc(4); - emit_move(REG_ECX, new, expr->ctype, "end EXPR_CONDITIONAL"); - /* FIXME: we lose type knowledge of expression result at this point */ + emit_copy(new, false, expr->ctype); + + /* end of conditional; jump target for if-true branch */ + emit_label(cond_end, "end conditional"); return new; } |