]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Handle VIEW_CONVERT_EXPR for non-floats.
authorAndrew MacLeod <amacleod@redhat.com>
Sat, 25 Oct 2025 15:59:55 +0000 (11:59 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Wed, 29 Oct 2025 14:21:54 +0000 (10:21 -0400)
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.

gcc/gimple-range-op.cc
gcc/range-op-mixed.h
gcc/range-op.cc
gcc/testsuite/gcc.dg/pr91191.c [new file with mode: 0644]

index c9bc5c0c6b902d1fb2ec87d7c5881a683f6c92c6..3a22606180bb89904aa194262df5eb309fad1bdc 100644 (file)
@@ -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.
index 567b0cdd31bb83948e6956a52dfcd66dc100c34a..db31c2bc8c9547fa7f599ab9e7ea27ac6a97f1e2 100644 (file)
@@ -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:
index 6b6bf78cb2f18fb765acd8b37ee3061bd165f229..cf5b8fe960f8a78638174e2f45aa1ad9c4160bfc 100644 (file)
@@ -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 (file)
index 0000000..7bf727e
--- /dev/null
@@ -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" } } */