https://gcc.gnu.org/g:8b0e43d7ec87f53d5bbd0a2d4d876d0aa1327a33

commit r16-4708-g8b0e43d7ec87f53d5bbd0a2d4d876d0aa1327a33
Author: Andrew MacLeod <[email protected]>
Date:   Sat Oct 25 11:59:55 2025 -0400

    Handle VIEW_CONVERT_EXPR for non-floats.
    
    Handle VIEW_CONVERT_EXPR for ranges as if it were a cast.
    
            PR tree-optimization/91191
            gcc/
            * gimple-range-op.cc (gimple_range_op_handler): Descend one
            operand lower for a VIEW_CONVERT_EXPR.
            * range-op-mixed.h (class operator_view): New.
            * range-op.cc (range_op_table): Add VIEW_CONVERT_EXPR case.
            (operator_view::fold_range): New.
            (operator_view::op1_range): New.
            (operator_view::update_bitmask): New.
    
            gcc/testsuite/
            * gcc.dg/pr91191.c: New.

Diff:
---
 gcc/gimple-range-op.cc         |  4 +++
 gcc/range-op-mixed.h           | 41 +++++++++++++++++++++++
 gcc/range-op.cc                | 76 ++++++++++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr91191.c | 20 +++++++++++
 4 files changed, 141 insertions(+)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index c9bc5c0c6b90..3a22606180bb 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -150,6 +150,10 @@ gimple_range_op_handler::gimple_range_op_handler (gimple 
*s)
              if (TREE_CODE (ssa) == SSA_NAME)
                m_op1 = ssa;
            }
+         // VIEW_CONVERT_EXPR needs to descend one level deeper to pick
+         // up the symbolic operand.
+         if (TREE_CODE (m_op1) == VIEW_CONVERT_EXPR)
+           m_op1 = TREE_OPERAND (m_op1, 0);
          if (gimple_num_ops (m_stmt) >= 3)
            m_op2 = gimple_assign_rhs2 (m_stmt);
          // Check that operands are supported types.  One check is enough.
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 567b0cdd31bb..db31c2bc8c95 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -527,6 +527,47 @@ private:
                           const irange &outer) const;
 };
 
+
+class operator_view : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::update_bitmask;
+  bool fold_range (irange &r, tree type,
+                  const irange &op1, const irange &op2,
+                  relation_trio rel = TRIO_VARYING) const override;
+  bool fold_range (prange &r, tree type,
+                  const prange &op1, const prange &op2,
+                  relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+                  const prange &op1, const irange &op2,
+                  relation_trio rel = TRIO_VARYING) const final override;
+  bool fold_range (prange &r, tree type,
+                  const irange &op1, const prange &op2,
+                  relation_trio rel = TRIO_VARYING) const final override;
+
+  bool op1_range (irange &r, tree type,
+                 const irange &lhs, const irange &op2,
+                 relation_trio rel = TRIO_VARYING) const override;
+  bool op1_range (prange &r, tree type,
+                 const prange &lhs, const prange &op2,
+                 relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (irange &r, tree type,
+                 const prange &lhs, const irange &op2,
+                 relation_trio rel = TRIO_VARYING) const final override;
+  bool op1_range (prange &r, tree type,
+                 const irange &lhs, const prange &op2,
+                 relation_trio rel = TRIO_VARYING) const final override;
+
+  void update_bitmask (irange &r, const irange &lh,
+                      const irange &) const final override;
+private:
+// VIEW_CONVERT_EXPR works much like a cast between integral values, so use
+// the cast operator.  Non-integrals are not handled as yet.
+  operator_cast m_cast;
+};
+
 class operator_plus : public range_operator
 {
 public:
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 6b6bf78cb2f1..cf5b8fe960f8 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -60,6 +60,7 @@ operator_ge op_ge;
 operator_identity op_ident;
 operator_cst op_cst;
 operator_cast op_cast;
+operator_view op_view;
 operator_plus op_plus;
 operator_abs op_abs;
 operator_minus op_minus;
@@ -97,6 +98,7 @@ range_op_table::range_op_table ()
   set (INTEGER_CST, op_cst);
   set (NOP_EXPR, op_cast);
   set (CONVERT_EXPR, op_cast);
+  set (VIEW_CONVERT_EXPR, op_view);
   set (FLOAT_EXPR, op_cast);
   set (FIX_TRUNC_EXPR, op_cast);
   set (PLUS_EXPR, op_plus);
@@ -3247,6 +3249,80 @@ operator_cast::op1_range (irange &r, tree type,
   return true;
 }
 
+// VIEW_CONVERT_EXPR works like a cast between integral values.
+// If the number of bits are not the same, behaviour is undefined,
+// so cast behaviour still works.
+
+bool
+operator_view::fold_range (irange &r, tree type,
+                          const irange &op1, const irange &op2,
+                          relation_trio rel) const
+{
+  return m_cast.fold_range (r, type, op1, op2, rel);
+}
+
+bool
+operator_view::fold_range (prange &r, tree type,
+                          const prange &op1, const prange &op2,
+                          relation_trio rel) const
+{
+  return m_cast.fold_range (r, type, op1, op2, rel);
+}
+bool
+operator_view::fold_range (irange &r, tree type,
+                          const prange &op1, const irange &op2,
+                          relation_trio rel) const
+{
+  return m_cast.fold_range (r, type, op1, op2, rel);
+}
+
+bool
+operator_view::fold_range (prange &r, tree type,
+                          const irange &op1, const prange &op2,
+                          relation_trio rel) const
+{
+  return m_cast.fold_range (r, type, op1, op2, rel);
+}
+
+bool
+operator_view::op1_range (irange &r, tree type,
+                         const irange &lhs, const irange &op2,
+                         relation_trio rel) const
+{
+  return m_cast.op1_range (r, type, lhs, op2, rel);
+}
+
+bool
+operator_view::op1_range (prange &r, tree type,
+                         const prange &lhs, const prange &op2,
+                         relation_trio rel) const
+{
+  return m_cast.op1_range (r, type, lhs, op2, rel);
+}
+
+bool
+operator_view::op1_range (irange &r, tree type,
+                         const prange &lhs, const irange &op2,
+                         relation_trio rel) const
+{
+  return m_cast.op1_range (r, type, lhs, op2, rel);
+}
+
+bool
+operator_view::op1_range (prange &r, tree type,
+                         const irange &lhs, const prange &op2,
+                         relation_trio rel) const
+{
+  return m_cast.op1_range (r, type, lhs, op2, rel);
+}
+
+void
+operator_view::update_bitmask (irange &r, const irange &lh,
+                              const irange &rh) const
+{
+  m_cast.update_bitmask (r, lh, rh);
+}
+
 
 class operator_logical_and : public range_operator
 {
diff --git a/gcc/testsuite/gcc.dg/pr91191.c b/gcc/testsuite/gcc.dg/pr91191.c
new file mode 100644
index 000000000000..7bf727e5b4f6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr91191.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+unsigned char reg(_Bool b) {
+    union U {
+        unsigned char f0;
+        _Bool f1;
+    };
+    union U u;
+    u.f1 = b;
+    if (u.f0 > 1) {
+        // This cannot happen
+        // if b is only allowed
+        // to be 0 or 1:
+        return 42;
+    }
+    return 13;
+}
+
+/* { dg-final { scan-tree-dump "return 13"  "evrp" } } */

Reply via email to