diff --git a/gcc/match.pd b/gcc/match.pd
index 53ced346bbd2f96ad437c6fd2232b593d0a3d2d2..4700380fb1fd794abb22d5e6a638b97144546890 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -4868,6 +4868,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    (with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
     (cmp (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
 
+/* Simplify (a >= 0 && b >= 0) to ( (a | b) >= 0 ) for integer types.
+   If one type is wider then the narrower type is sign-extended
+*/
+
+(for and (truth_and truth_andif)
+ (simplify
+  (and (ge @0 integer_zerop) (ge @1 integer_zerop))
+  (if (   INTEGRAL_TYPE_P (TREE_TYPE (@0))
+       && INTEGRAL_TYPE_P (TREE_TYPE (@1)))
+    (with { tree t = TYPE_PRECISION (TREE_TYPE (@0)) > TYPE_PRECISION (TREE_TYPE (@1)) ?
+                        TREE_TYPE (@0) : TREE_TYPE (@1); }
+    (ge (bit_ior (convert:t @0) (convert:t @1)) { build_zero_cst (t); })))))
+
 /* Simplification of math builtins.  These rules must all be optimizations
    as well as IL simplifications.  If there is a possibility that the new
    form could be a pessimization, the rule should go in the canonicalization
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr95731-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr95731-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..6af00e94d580737d0a4e5e4ae853a88fe30e58cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr95731-1.c
@@ -0,0 +1,10 @@
+/* { dg-do compile} */
+/* { dg-options "-fdump-tree-gimple" } */
+
+/* { dg-final { scan-tree-dump-times "_1 = a \\| b" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times " _2 = _1 >= 0" 1 "gimple" } } */
+
+int f(int a, int b)
+{
+  return a >= 0 && b >= 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr95731-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr95731-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..5fe819aadad09bc69b53e7aa0e3cc7d80f699d87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr95731-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile} */
+/* { dg-options "-fdump-tree-gimple" } */
+
+/* { dg-final { scan-tree-dump-times "_1 = \\(long int\\) a" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "_2 = b \\| _1" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "_3 = _2 >= 0" 1 "gimple" } } */
+
+#include <stdint.h>
+
+int f(int16_t a, int64_t b)
+{
+  return a >= 0 && b >= 0;
+}
