diff options
| author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-07-31 15:00:06 +0200 |
|---|---|---|
| committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2018-08-06 08:50:40 +0200 |
| commit | 3334fa789234c05da18b9e0e284bc04e5ef6b39b (patch) | |
| tree | 830a09a4ce171452bab3fc9da5778c86048021eb | |
| parent | 875235a6801d1c5a9ccc9c265fe45a8f6a0f87c0 (diff) | |
| download | sparse-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.c | 17 | ||||
| -rw-r--r-- | validation/linear/logical.c | 1 |
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: |
