@@ -1209,6 +1209,31 @@ static int map_opcode(int opcode, struct symbol *ctype)
return opcode;
}
+static inline pseudo_t add_convert_to_bool(struct entrypoint *ep, pseudo_t src, struct symbol *type)
+{
+ pseudo_t zero;
+ int op;
+
+ if (is_bool_type(type))
+ return src;
+ if (is_float_type(type)) {
+ zero = add_setfval(ep, type, 0.0);
+ op = map_opcode(OP_SET_NE, type);
+ } else {
+ zero = value_pseudo(0);
+ op = OP_SET_NE;
+ }
+ return add_binary_op(ep, &bool_ctype, op, src, zero);
+}
+
+static pseudo_t linearize_expression_to_bool(struct entrypoint *ep, struct expression *expr)
+{
+ pseudo_t dst;
+ dst = linearize_expression(ep, expr);
+ dst = add_convert_to_bool(ep, dst, expr->ctype);
+ return dst;
+}
+
static pseudo_t linearize_assignment(struct entrypoint *ep, struct expression *expr)
{
struct access_data ad = { NULL, };
@@ -1351,6 +1376,19 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi
return retval;
}
+static pseudo_t linearize_binop_bool(struct entrypoint *ep, struct expression *expr)
+{
+ pseudo_t src1, src2, dst;
+ int op = (expr->op == SPECIAL_LOGICAL_OR) ? OP_OR_BOOL : OP_AND_BOOL;
+
+ src1 = linearize_expression_to_bool(ep, expr->left);
+ src2 = linearize_expression_to_bool(ep, expr->right);
+ dst = add_binary_op(ep, &bool_ctype, op, src1, src2);
+ if (expr->ctype != &bool_ctype)
+ dst = cast_pseudo(ep, dst, &bool_ctype, expr->ctype);
+ return dst;
+}
+
static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr)
{
pseudo_t src1, src2, dst;
@@ -1361,8 +1399,6 @@ static pseudo_t linearize_binop(struct entrypoint *ep, struct expression *expr)
['|'] = OP_OR, ['^'] = OP_XOR,
[SPECIAL_LEFTSHIFT] = OP_SHL,
[SPECIAL_RIGHTSHIFT] = OP_LSR,
- [SPECIAL_LOGICAL_AND] = OP_AND_BOOL,
- [SPECIAL_LOGICAL_OR] = OP_OR_BOOL,
};
int op;
@@ -1647,6 +1683,8 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr)
return linearize_call_expression(ep, expr);
case EXPR_BINOP:
+ if (expr->op == SPECIAL_LOGICAL_AND || expr->op == SPECIAL_LOGICAL_OR)
+ return linearize_binop_bool(ep, expr);
return linearize_binop(ep, expr);
case EXPR_LOGICAL:
@@ -5,6 +5,10 @@ bool bfexp(float a) { return (bool)a; }
bool bfnot(float a) { return !a; }
int ifnot(float a) { return !a; }
+bool bfior(float a, float b) { return a || b; }
+int ifior(float a, float b) { return a || b; }
+bool bfand(float a, float b) { return a && b; }
+int ifand(float a, float b) { return a && b; }
/*
* check-name: bool context fp
@@ -43,5 +47,49 @@ ifnot:
ret.32 %r16
+bfior:
+.L8:
+ <entry-point>
+ setfval.32 %r19 <- 0.000000
+ fcmpune.1 %r20 <- %arg1, %r19
+ fcmpune.1 %r23 <- %arg2, %r19
+ or-bool.1 %r24 <- %r23, %r20
+ setne.1 %r26 <- %r24, $0
+ ret.1 %r26
+
+
+ifior:
+.L10:
+ <entry-point>
+ setfval.32 %r29 <- 0.000000
+ fcmpune.1 %r30 <- %arg1, %r29
+ fcmpune.1 %r33 <- %arg2, %r29
+ or-bool.1 %r34 <- %r33, %r30
+ cast.32 %r35 <- (1) %r34
+ ret.32 %r35
+
+
+bfand:
+.L12:
+ <entry-point>
+ setfval.32 %r38 <- 0.000000
+ fcmpune.1 %r39 <- %arg1, %r38
+ fcmpune.1 %r42 <- %arg2, %r38
+ and-bool.1 %r43 <- %r42, %r39
+ setne.1 %r45 <- %r43, $0
+ ret.1 %r45
+
+
+ifand:
+.L14:
+ <entry-point>
+ setfval.32 %r48 <- 0.000000
+ fcmpune.1 %r49 <- %arg1, %r48
+ fcmpune.1 %r52 <- %arg2, %r48
+ and-bool.1 %r53 <- %r52, %r49
+ cast.32 %r54 <- (1) %r53
+ ret.32 %r54
+
+
* check-output-end
*/
new file mode 100644
@@ -0,0 +1,12 @@
+#define bool _Bool
+
+bool bool_ior(int a, int b) { return a || b; }
+bool bool_and(int a, int b) { return a && b; }
+
+/*
+ * check-name: bool-context
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-pattern-4-times: setne\\..* %arg[12]
+ */
@@ -32,13 +32,17 @@ and_0:
and_1:
.L2:
<entry-point>
- ret.32 %arg1
+ setne.1 %r8 <- %arg1, $0
+ cast.32 %r11 <- (1) %r8
+ ret.32 %r11
or_0:
.L4:
<entry-point>
- ret.32 %arg1
+ setne.1 %r14 <- %arg1, $0
+ cast.32 %r17 <- (1) %r14
+ ret.32 %r17
or_1:
Current simplification of 'x && 1 --> x' and its dual 'x || 0 --> x' are wrong because the '||' and '&&' operators demand that their operands are first compared against zero which then always give a boolean valued result. For example: '3 && 1' is not equal to '3' but to '1'. The correct simplification is thus 'x && 1 --> x != 0' and 'x || 0 --> x != 0'. Fix this by always first doing the comparison against zero before generating the OP_AND_BOOL and OP_OR_BOOL instructions. Note: of course, we could decide that the semantic of OP_AND_BOOL and OP_OR_BOOL is that these ops take care themselves of making a boolean context (which I think was why these ops were created) but then these simplifications cannot be done (or when they are done, we need to add the comparison against zero). Fixes: b85ec4bb7f5b1c522d7c71782dbd9cf1c4c49b2f Fixes: a0886db12307d2633b04ec44342099a2955794a5 Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com> --- linearize.c | 42 +++++++++++++++++++++++++++++++-- validation/optim/bool-context-fp.c | 48 ++++++++++++++++++++++++++++++++++++++ validation/optim/bool-context.c | 12 ++++++++++ validation/optim/bool-simplify.c | 8 +++++-- 4 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 validation/optim/bool-context.c