diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1995605a6803771ef1f3f5d634fa6af2f3165227..b18b1e4ec0f093a3d1b753658caa7e723057a2e0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2005-06-12  James A. Morrison  <phython@gcc.gnu.org>
+
+	PR tree-optimization/14796
+	* fold-const (fold_binary): Transform (X << C) >> C into X & (-1>>C)
+	for unsigned types.
+
 2005-06-12  Kazu Hirata  <kazu@codesourcery.com>
 
 	* cgraphunit.c, tree-ssa-loop-ivopts.c,
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 1994410d4be8b7d3338d194f0ce94bda60c4e12e..af3f01c38df23b5a2b93a5dbd711cf43384d2ad2 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -8768,8 +8768,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 			      build_int_cst (type, low));
 	}
 
-      /* Transform (x >> c) << c into x & (-1<<c)  */
-      if (code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR
+      /* Transform (x >> c) << c into x & (-1<<c), or transform (x << c) >> c
+         into x & ((unsigned)-1 >> c) for unsigned types.  */
+      if (((code == LSHIFT_EXPR && TREE_CODE (arg0) == RSHIFT_EXPR)
+           || (TYPE_UNSIGNED (type)
+	       && code == RSHIFT_EXPR && TREE_CODE (arg0) == LSHIFT_EXPR))
 	  && host_integerp (arg1, false)
 	  && TREE_INT_CST_LOW (arg1) < TYPE_PRECISION (type)
 	  && host_integerp (TREE_OPERAND (arg0, 1), false)
@@ -8777,8 +8780,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 	{
 	  HOST_WIDE_INT low0 = TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1));
 	  HOST_WIDE_INT low1 = TREE_INT_CST_LOW (arg1);
-	  unsigned HOST_WIDE_INT low;
-	  HOST_WIDE_INT high;
 	  tree lshift;
 	  tree arg00;
 
@@ -8786,15 +8787,13 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 	    {
 	      arg00 = fold_convert (type, TREE_OPERAND (arg0, 0));
 
-	      lshift_double (-1, -1, low0 < low1 ? low0 : low1,
-			     TYPE_PRECISION (type), &low, &high, 1);
-	      lshift = build_int_cst_wide (type, low, high);
+	      lshift = build_int_cst (type, -1);
+	      lshift = int_const_binop (code, lshift, arg1, 0);
 
 	      return fold_build2 (BIT_AND_EXPR, type, arg00, lshift);
 	    }
 	}
 
-
       /* Rewrite an LROTATE_EXPR by a constant into an
 	 RROTATE_EXPR by a new constant.  */
       if (code == LROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9ae809b5d0ee8f48d5e8df09c50bce48abbe833a..0baaf8a6e86688ffe649e437012165d9ede8bb6f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2005-06-12  James A. Morrison  <phython@gcc.gnu.org>
+
+	* ggcc.dg/pr14796-1.c: Add tests for (X << C) >> C.
+
 2005-06-12  Roger Sayle  <roger@eyesopen.com>
 
 	PR c++/21930
diff --git a/gcc/testsuite/gcc.dg/pr14796-1.c b/gcc/testsuite/gcc.dg/pr14796-1.c
index c927e2b54036f18dafd5eacb1b08dfa779245237..7ddc4fe3467c07262d43225e9644d2978887038b 100644
--- a/gcc/testsuite/gcc.dg/pr14796-1.c
+++ b/gcc/testsuite/gcc.dg/pr14796-1.c
@@ -9,6 +9,16 @@ int g (int b) {
 	return (b >> 5) << 5;
 }
 
+unsigned long long h (unsigned long long c) {
+	return (c << 60) >> 60;
+}
+
+int l (int d) {
+	return (d << 6) >> 6;
+}
+
 /* { dg-final { scan-tree-dump "a << 9" "gimple" } } */
 /* { dg-final { scan-tree-dump "b & -32" "gimple" } } */
+/* { dg-final { scan-tree-dump "c & 15" "gimple" } } */
+/* { dg-final { scan-tree-dump "d << 6" "gimple" } } */
 /* { dg-final { cleanup-tree-dump "gimple" } } */