diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 6859518..19cee6b 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "hash-table.h"
 #include "tm.h"
+#include "rtl.h"
+#include "tm_p.h"
 #include "tree.h"
 #include "basic-block.h"
 #include "gimple-pretty-print.h"
@@ -2253,13 +2255,7 @@ optimize_range_tests (enum tree_code opcode,
 	  lowxor = fold_binary (BIT_XOR_EXPR, type, lowi, lowj);
 	  if (lowxor == NULL_TREE || TREE_CODE (lowxor) != INTEGER_CST)
 	    continue;
-	  gcc_checking_assert (!integer_zerop (lowxor));
-	  tem = fold_binary (MINUS_EXPR, type, lowxor,
-			     build_int_cst (type, 1));
-	  if (tem == NULL_TREE)
-	    continue;
-	  tem = fold_binary (BIT_AND_EXPR, type, lowxor, tem);
-	  if (tem == NULL_TREE || !integer_zerop (tem))
+	  if (tree_log2 (lowxor) < 0)
 	    continue;
 	  highxor = fold_binary (BIT_XOR_EXPR, type, highi, highj);
 	  if (!tree_int_cst_equal (lowxor, highxor))
@@ -2279,6 +2275,71 @@ optimize_range_tests (enum tree_code opcode,
 	}
     }
 
+  /* Optimize X == CST1 || X == CST2
+     if popcount (CST2 - CST1) == 1 into
+     ((X - CST1) & ~(CST2 - CST1)) == 0.  */
+  if (BRANCH_COST (optimize_function_for_speed_p (cfun), false) >= 2)
+    for (i = first; i < length; i++)
+      {
+	tree lowi, highi, lowj, highj, type, tem1, tem2, mask;
+
+	if (ranges[i].exp == NULL_TREE || ranges[i].in_p)
+	  continue;
+	type = TREE_TYPE (ranges[i].exp);
+	if (!INTEGRAL_TYPE_P (type))
+	  continue;
+	lowi = ranges[i].low;
+	if (lowi == NULL_TREE)
+	  continue;
+	highi = ranges[i].high;
+	if (highi == NULL_TREE)
+	  continue;
+	for (j = i + 1; j < length && j < i + 64; j++)
+	  {
+	    lowj = ranges[j].low;
+	    if (lowj == NULL_TREE)
+	      continue;
+	    highj = ranges[j].high;
+	    if (highj == NULL_TREE)
+	      continue;
+	    if (ranges[j].exp == NULL_TREE || ranges[j].in_p
+		|| (ranges[i].exp != ranges[j].exp))
+	      continue;
+	    /* Check lowj > highi.  */
+	    tem1 = fold_binary (GT_EXPR, boolean_type_node,
+			       lowj, highi);
+	    if (tem1 == NULL_TREE || !integer_onep (tem1))
+	      continue;
+	    /* Check highi - lowi == highj - lowj.  */
+	    tem1 = fold_binary (MINUS_EXPR, type, highi, lowi);
+	    if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
+	      continue;
+	    tem2 = fold_binary (MINUS_EXPR, type, highj, lowj);
+	    if (tem2 == NULL_TREE || TREE_CODE (tem2) != INTEGER_CST)
+	      continue;
+	    if (!tree_int_cst_equal (tem1, tem2))
+	      continue;
+	    /* Check popcount (lowj - lowi) == 1.  */
+	    tem1 = fold_binary (MINUS_EXPR, type, lowj, lowi);
+	    if (tem1 == NULL_TREE || TREE_CODE (tem1) != INTEGER_CST)
+	      continue;
+	    if (tree_log2 (tem1) < 0)
+	      continue;
+	    mask = fold_build1 (BIT_NOT_EXPR, type, tem1);
+	    tem1 = fold_binary (MINUS_EXPR, type, ranges[i].exp, lowi);
+	    tem1 = fold_build2 (BIT_AND_EXPR, type, tem1, mask);
+	    lowi = build_int_cst (type, 0);
+	    if (update_range_test (ranges + i, ranges + j, 1, opcode, ops, tem1,
+				   ranges[i].in_p, lowi, tem2,
+				   ranges[i].strict_overflow_p
+				   || ranges[j].strict_overflow_p))
+	      {
+		any_changes = true;
+		break;
+	      }
+	  }
+      }
+
   if (any_changes && opcode != ERROR_MARK)
     {
       j = 0;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-32.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-32.c
new file mode 100644
index 0000000..d050dd4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-32.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+
+int test (int a, int b, int c)
+{
+  if ( a == 10 || a == 12 || a == 26)
+    return b;
+  else
+    return c;
+}
+
+int main ()
+{
+  if (test (10, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (12, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (26, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (30, 20, 30) != 30)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
+/* { dg-final { cleanup-tree-dump "reassoc1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-33.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-33.c
new file mode 100644
index 0000000..6701b29
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-33.c
@@ -0,0 +1,38 @@
+/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int test (int a, int b, int c)
+{
+  if (a == 43 || a == 75 || a == 44 || a == 78 || a == 77 || a == 46 || a == 76 || a == 45)
+    return b;
+  else
+    return c;
+}
+
+int main ()
+{
+  if (test (43, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (44, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (45, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (46, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (75, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (76, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (77, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (78, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (30, 20, 30) != 30)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests" 3 "reassoc1"} }*/
+/* { dg-final { cleanup-tree-dump "reassoc1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-34.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-34.c
new file mode 100644
index 0000000..156e182
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-34.c
@@ -0,0 +1,24 @@
+/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int test (int a, int b, int c)
+{
+  if (a == 10 || a == 12)
+    return b;
+  else
+    return c;
+}
+int main ()
+{
+  if (test (10, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (12, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (26, 20, 30) != 30)
+    __builtin_abort ();
+  return 0;
+}
+/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
+/* { dg-final { cleanup-tree-dump "reassoc1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-35.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-35.c
new file mode 100644
index 0000000..b586021
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-35.c
@@ -0,0 +1,38 @@
+/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int test (unsigned int a, int b, int c)
+{
+  if ((a - 43) <= 3 || (a - 75) <= 3)
+    return b;
+  else
+    return c;
+}
+int main ()
+{
+  if (test (43, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (44, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (45, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (46, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (75, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (76, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (77, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (78, 20, 30) != 20)
+    __builtin_abort ();
+  if (test (30, 20, 30) != 30)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
+/* { dg-final { cleanup-tree-dump "reassoc1" } } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-36.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-36.c
new file mode 100644
index 0000000..930dbe2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-36.c
@@ -0,0 +1,25 @@
+/* { dg-do run { target { ! "m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* picochip*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-*"} } } */
+
+/* { dg-options "-O2 -fno-inline -fdump-tree-reassoc1-details" } */
+/* { dg-additional-options "-mbranch-cost=2" { target avr-*-* } } */
+
+int test (int a, int b, int c)
+{
+  if (a != 10 && a != 12)
+    return b;
+  else
+    return c;
+}
+int main ()
+{
+  if (test (10, 20, 30) != 30)
+    __builtin_abort ();
+  if (test (12, 20, 30) != 30)
+    __builtin_abort ();
+  if (test (26, 20, 30) != 20)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests" 1 "reassoc1"} }*/
+/* { dg-final { cleanup-tree-dump "reassoc1" } } */
