aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2004-08-01 15:56:03 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-07 21:02:30 -0700
commit8e039e099e7aba63590969ceba7a20f208c2bbba (patch)
treea0e47eca623a27bdc2bbb410cb80779659cfe724 /compile-i386.c
parent[be] minor fixes (diff)
downloadsparse-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.c130
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;
}