aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-07-31 15:00:06 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-08-06 08:50:40 +0200
commit3334fa789234c05da18b9e0e284bc04e5ef6b39b (patch)
tree830a09a4ce171452bab3fc9da5778c86048021eb
parent875235a6801d1c5a9ccc9c265fe45a8f6a0f87c0 (diff)
downloadsparse-dev-3334fa789234c05da18b9e0e284bc04e5ef6b39b.tar.gz
fix linearize_conditional() for logical ops
The function linearize_conditional(), normaly used for conditionals (c ? a : b) is also used to linearize the logical ops || and &&. For conditionals, the type evaluation ensure that both LHS & RHS have consistent types. However, this is not the case when used for logical ops. This creates 2 separated but related problems: * the operands are not compared with 0 as required by the standard (6.5.13, 6.5.14). * both operands can have different, incompatible types and thus it's possible to have a phi-node with sources of different, incompatible types, which doesn't make sense. Fix this by: * add a flag to linearize_conditional() telling if it's used for a conditional or for a logical op. * when used for logical ops: * first compare the operands againts zero * convert the boolean result to the expression's type. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--linearize.c17
-rw-r--r--validation/linear/logical.c1
2 files changed, 13 insertions, 5 deletions
diff --git a/linearize.c b/linearize.c
index 2b950210..2b1b2658 100644
--- a/linearize.c
+++ b/linearize.c
@@ -1615,7 +1615,8 @@ static pseudo_t linearize_short_conditional(struct entrypoint *ep, struct expres
static pseudo_t linearize_conditional(struct entrypoint *ep, struct expression *expr,
struct expression *cond,
struct expression *expr_true,
- struct expression *expr_false)
+ struct expression *expr_false,
+ int logical)
{
pseudo_t src1, src2;
pseudo_t phi1, phi2;
@@ -1631,11 +1632,19 @@ static pseudo_t linearize_conditional(struct entrypoint *ep, struct expression *
set_activeblock(ep, bb_true);
src1 = linearize_expression(ep, expr_true);
+ if (logical) {
+ src1 = add_convert_to_bool(ep, src1, expr_true->ctype);
+ src1 = cast_pseudo(ep, src1, &bool_ctype, expr->ctype);
+ }
phi1 = alloc_phi(ep->active, src1, expr->ctype);
add_goto(ep, merge);
set_activeblock(ep, bb_false);
src2 = linearize_expression(ep, expr_false);
+ if (logical) {
+ src2 = add_convert_to_bool(ep, src2, expr_false->ctype);
+ src2 = cast_pseudo(ep, src2, &bool_ctype, expr->ctype);
+ }
phi2 = alloc_phi(ep->active, src2, expr->ctype);
set_activeblock(ep, merge);
@@ -1649,8 +1658,8 @@ static pseudo_t linearize_logical(struct entrypoint *ep, struct expression *expr
shortcut = alloc_const_expression(expr->pos, expr->op == SPECIAL_LOGICAL_OR);
shortcut->ctype = expr->ctype;
if (expr->op == SPECIAL_LOGICAL_OR)
- return linearize_conditional(ep, expr, expr->left, shortcut, expr->right);
- return linearize_conditional(ep, expr, expr->left, expr->right, shortcut);
+ return linearize_conditional(ep, expr, expr->left, shortcut, expr->right, 1);
+ return linearize_conditional(ep, expr, expr->left, expr->right, shortcut, 1);
}
static pseudo_t linearize_compare(struct entrypoint *ep, struct expression *expr)
@@ -1829,7 +1838,7 @@ static pseudo_t linearize_expression(struct entrypoint *ep, struct expression *e
return linearize_short_conditional(ep, expr, expr->conditional, expr->cond_false);
return linearize_conditional(ep, expr, expr->conditional,
- expr->cond_true, expr->cond_false);
+ expr->cond_true, expr->cond_false, 0);
case EXPR_COMMA:
linearize_expression(ep, expr->left);
diff --git a/validation/linear/logical.c b/validation/linear/logical.c
index 645adc56..972f8709 100644
--- a/validation/linear/logical.c
+++ b/validation/linear/logical.c
@@ -19,7 +19,6 @@ int ad(int i, struct S *b) { return i && b->d; }
/*
* check-name: logical
* check-command: test-linearize -m64 -fdump-ir -Wno-decl $file
- * check-known-to-fail
*
* check-output-start
os: