On Wed, Aug 12, 2026 at 2:25 AM Daniel Barboza
<[email protected]> wrote:
>
> Given a bit_ior in the format A | B, if we know for certain that
> A != B then we can infer that A | B will always be nonzero.
>
> Bootstrapped and regression tested in x86_64, aarch64 and riscv64.
Ok.
>
> PR tree-optimization/126743
>
> gcc/ChangeLog:
>
> * range-op-mixed.h: declare.
> * range-op.cc (operator_bitwise_or::op1_op2_relation_effect):
> add op1 NE op2 relation range for op1 | op2 as nonzero.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/pr126743.c: New test.
> ---
> gcc/range-op-mixed.h | 6 ++++++
> gcc/range-op.cc | 25 ++++++++++++++++++++++++
> gcc/testsuite/gcc.dg/tree-ssa/pr126743.c | 23 ++++++++++++++++++++++
> 3 files changed, 54 insertions(+)
> create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
>
> diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
> index a870a0c1211..0e97fb11688 100644
> --- a/gcc/range-op-mixed.h
> +++ b/gcc/range-op-mixed.h
> @@ -849,6 +849,7 @@ public:
> using range_operator::fold_range;
> using range_operator::op1_range;
> using range_operator::op2_range;
> + using range_operator::op1_op2_relation_effect;
> using range_operator::update_bitmask;
>
> bool fold_range (prange &r, tree type,
> @@ -861,6 +862,11 @@ public:
> bool op2_range (irange &r, tree type,
> const irange &lhs, const irange &op1,
> relation_trio rel = TRIO_VARYING) const override;
> + bool op1_op2_relation_effect (irange &lhs_range,
> + tree type,
> + const irange &op1_range,
> + const irange &op2_range,
> + relation_kind rel) const final override;
> void update_bitmask (irange &r, const irange &lh,
> const irange &rh) const override;
> // Check compatibility of all operands.
> diff --git a/gcc/range-op.cc b/gcc/range-op.cc
> index 07413ef7054..b878a6052c6 100644
> --- a/gcc/range-op.cc
> +++ b/gcc/range-op.cc
> @@ -4060,6 +4060,31 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
> value_range_with_overflow (r, type, new_lb, new_ub);
> }
>
> +bool
> +operator_bitwise_or::op1_op2_relation_effect (irange &lhs_range,
> + tree type,
> + const irange &,
> + const irange &,
> + relation_kind rel) const
> +{
> + if (rel == VREL_VARYING)
> + return false;
> +
> + int_range<2> rel_range;
> +
> + switch (rel)
> + {
> + case VREL_NE:
> + rel_range.set_nonzero (type);
> + break;
> + default:
> + return false;
> + }
> +
> + lhs_range.intersect (rel_range);
> + return true;
> +}
> +
> bool
> operator_bitwise_or::op1_range (irange &r, tree type,
> const irange &lhs,
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
> b/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
> new file mode 100644
> index 00000000000..a99e6efbff9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr126743.c
> @@ -0,0 +1,23 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-evrp" } */
> +
> +unsigned int
> +or_eq_zero (int a, int b)
> +{
> + if (a == b)
> + __builtin_unreachable ();
> + // return 0;
> + return (a | b) == 0;
> +}
> +
> +unsigned int
> +or_ne_zero (int a, int b)
> +{
> + if (a == b)
> + __builtin_unreachable ();
> + // return 1;
> + return (a | b) != 0;
> +}
> +
> +/* { dg-final { scan-tree-dump-times "return 0;" 1 "evrp" } } */
> +/* { dg-final { scan-tree-dump-times "return 1;" 1 "evrp" } } */
> --
> 2.43.0
>