return sval;
}
+/* Subroutine of region_model_manager::maybe_fold_unaryop
+ when the arg is a binop_svalue.
+ Invert comparisons e.g. "!(x == y)" => "x != y".
+ Otherwise, return nullptr. */
+
+const svalue *
+region_model_manager::
+maybe_invert_comparison_in_unaryop (tree result_type,
+ const binop_svalue *binop)
+{
+ if (TREE_CODE_CLASS (binop->get_op ()) == tcc_comparison)
+ {
+ enum tree_code inv_op
+ = invert_tree_comparison (binop->get_op (),
+ HONOR_NANS (binop->get_type ()));
+ if (inv_op != ERROR_MARK)
+ return get_or_create_cast
+ (result_type,
+ get_or_create_binop (binop->get_type (), inv_op,
+ binop->get_arg0 (),
+ binop->get_arg1 ()));
+ }
+ return nullptr;
+}
+
/* Subroutine of region_model_manager::get_or_create_unaryop.
Attempt to fold the inputs and return a simpler svalue *.
Otherwise, return nullptr. */
{
/* Invert comparisons e.g. "!(x == y)" => "x != y". */
if (const binop_svalue *binop = arg->dyn_cast_binop_svalue ())
- if (TREE_CODE_CLASS (binop->get_op ()) == tcc_comparison)
- {
- enum tree_code inv_op
- = invert_tree_comparison (binop->get_op (),
- HONOR_NANS (binop->get_type ()));
- if (inv_op != ERROR_MARK)
- return get_or_create_binop (binop->get_type (), inv_op,
- binop->get_arg0 (),
- binop->get_arg1 ());
- }
+ if (const svalue *folded
+ = maybe_invert_comparison_in_unaryop (type, binop))
+ return folded;
}
break;
case NEGATE_EXPR:
return unaryop->get_arg ();
}
break;
+ case BIT_NOT_EXPR:
+ {
+ /* Invert comparisons for e.g. "~(x == y)" => "x != y". */
+ if (type
+ && TREE_CODE (type) == BOOLEAN_TYPE
+ && arg->get_type ()
+ && TREE_CODE (arg->get_type ()) == BOOLEAN_TYPE)
+ if (const binop_svalue *binop = arg->dyn_cast_binop_svalue ())
+ if (const svalue *folded
+ = maybe_invert_comparison_in_unaryop (type, binop))
+ return folded;
+ }
+ break;
}
/* Constants. */
bool too_complex_p (const complexity &c) const;
bool reject_if_too_complex (svalue *sval);
+ const svalue *
+ maybe_invert_comparison_in_unaryop (tree type,
+ const binop_svalue *binop);
const svalue *maybe_fold_unaryop (tree type, enum tree_code op,
const svalue *arg);
const svalue *maybe_fold_sub_svalue (tree type,
--- /dev/null
+typedef _Bool BOOL;
+#define NULL ((void *)0)
+
+int test_eq_null_inverted ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (!p_is_null) __builtin_free(p);
+ return 0;
+}
+
+int test_eq_null_compared_against_false ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (p_is_null == false) __builtin_free(p);
+ return 0;
+}
+
+int test_ne_null ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_notnull = (p != NULL);
+ if (p_is_notnull) __builtin_free(p);
+ return 0;
+}
+
+int test_eq_null ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (p_is_null) {} else __builtin_free(p);
+ return 0;
+}
--- /dev/null
+/* { dg-additional-options "-std=c99" } */
+
+typedef enum { false = 0, true } BOOL;
+#define NULL ((void *)0)
+
+int test_eq_null_inverted ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (!p_is_null) __builtin_free(p);
+ return 0;
+}
+
+int test_eq_null_compared_against_false ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (p_is_null == false) __builtin_free(p);
+ return 0;
+}
+
+int test_ne_null ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_notnull = (p != NULL);
+ if (p_is_notnull) __builtin_free(p);
+ return 0;
+}
+
+int test_eq_null ()
+{
+ char *p = __builtin_malloc(1);
+ const BOOL p_is_null = (p == NULL);
+ if (p_is_null) {} else __builtin_free(p);
+ return 0;
+}