diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2d926260394dc069c7151472e35cf7149cc8452c..5a2a80b8f125882a58844321f74c2c0c121bc943 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2009-07-17  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/40321
+	* tree-ssa-pre.c (add_to_exp_gen): Also add names defined by
+	PHI nodes to the maximal set.
+	(make_values_for_phi): Add PHI arguments to the maximal set.
+	(execute_pre): Dump PHI_GEN and the maximal set.
+
 2009-07-17  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c++/40780
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index fdd4d18d5b3a685920d4e8dd2615e9ca78caaf05..d35fe72d9ff8d844b8c05cb13e965b40c8b6e335 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2009-07-17  Richard Guenther  <rguenther@suse.de>
+
+	PR tree-optimization/40321
+	* gcc.c-torture/compile/pr40321.c: New testcase.
+	* g++.dg/torture/pr40321.C: Likewise.
+
 2009-07-17  Jakub Jelinek  <jakub@redhat.com>
 
 	PR c++/40780
diff --git a/gcc/testsuite/g++.dg/torture/pr40321.C b/gcc/testsuite/g++.dg/torture/pr40321.C
new file mode 100644
index 0000000000000000000000000000000000000000..9177431098ec8e8ff7f36c0bd51aa6df944672bd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr40321.C
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+
+struct VectorD2
+{
+  VectorD2() : x(0), y(0) { }
+  VectorD2(int _x, int _y) : x(_x), y(_y) { }
+  int x, y;
+  int GetLength2() const { return x*x + y*y; };
+  VectorD2 operator+(const VectorD2 vec) const {
+      return VectorD2(x+vec.x,y+vec.y);
+  }
+};
+struct Shape
+{
+  enum Type { ST_RECT, ST_CIRCLE } type;
+  VectorD2 pos;
+  VectorD2 radius;
+  bool CollisionWith(const Shape& s) const;
+};
+bool Shape::CollisionWith(const Shape& s) const
+{
+  if(type == ST_CIRCLE && s.type == ST_RECT)
+    return s.CollisionWith(*this);
+  return (pos + s.pos).GetLength2() < (radius + s.radius).GetLength2();
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr40321.c b/gcc/testsuite/gcc.c-torture/compile/pr40321.c
new file mode 100644
index 0000000000000000000000000000000000000000..a2f83ed8d84af868b94cd4959b277e3cdcb4ccf5
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr40321.c
@@ -0,0 +1,12 @@
+struct X { int flag; int pos; };
+int foo(struct X *a, struct X *b)
+{
+  while (1)
+    {
+      if (a->flag)
+	break;
+      ({ struct X *tmp = a; a = b; b = tmp; });
+    }
+
+  return a->pos + b->pos;
+}
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 11640a8895e0a783fe6165e10272a8191b8eb4d9..96ca5edb0f3fb46255d3de28cd9126e4e37079b0 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -1996,8 +1996,7 @@ vro_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2,
    ONLY SET2 CAN BE NULL.
    This means that we have a leader for each part of the expression
    (if it consists of values), or the expression is an SSA_NAME.
-   For loads/calls, we also see if the vuse is killed in this block.
-*/
+   For loads/calls, we also see if the vuse is killed in this block.  */
 
 static bool
 valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
@@ -3625,11 +3624,7 @@ insert (void)
 }
 
 
-/* Add OP to EXP_GEN (block), and possibly to the maximal set if it is
-   not defined by a phi node.
-   PHI nodes can't go in the maximal sets because they are not in
-   TMP_GEN, so it is possible to get into non-monotonic situations
-   during ANTIC calculation, because it will *add* bits.  */
+/* Add OP to EXP_GEN (block), and possibly to the maximal set.  */
 
 static void
 add_to_exp_gen (basic_block block, tree op)
@@ -3641,9 +3636,7 @@ add_to_exp_gen (basic_block block, tree op)
 	return;
       result = get_or_alloc_expr_for_name (op);
       bitmap_value_insert_into_set (EXP_GEN (block), result);
-      if (TREE_CODE (op) != SSA_NAME
-	  || gimple_code (SSA_NAME_DEF_STMT (op)) != GIMPLE_PHI)
-	bitmap_value_insert_into_set (maximal_set, result);
+      bitmap_value_insert_into_set (maximal_set, result);
     }
 }
 
@@ -3662,6 +3655,20 @@ make_values_for_phi (gimple phi, basic_block block)
       add_to_value (get_expr_value_id (e), e);
       bitmap_insert_into_set (PHI_GEN (block), e);
       bitmap_value_insert_into_set (AVAIL_OUT (block), e);
+      if (!in_fre)
+	{
+	  unsigned i;
+	  for (i = 0; i < gimple_phi_num_args (phi); ++i)
+	    {
+	      tree arg = gimple_phi_arg_def (phi, i);
+	      if (TREE_CODE (arg) == SSA_NAME)
+		{
+		  e = get_or_alloc_expr_for_name (arg);
+		  add_to_value (get_expr_value_id (e), e);
+		  bitmap_value_insert_into_set (maximal_set, e);
+		}
+	    }
+	}
     }
 }
 
@@ -4509,11 +4516,12 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED)
       FOR_ALL_BB (bb)
 	{
 	  print_bitmap_set (dump_file, EXP_GEN (bb), "exp_gen", bb->index);
-	  print_bitmap_set (dump_file, TMP_GEN (bb), "tmp_gen",
-				  bb->index);
-	  print_bitmap_set (dump_file, AVAIL_OUT (bb), "avail_out",
-				  bb->index);
+	  print_bitmap_set (dump_file, PHI_GEN (bb), "phi_gen", bb->index);
+	  print_bitmap_set (dump_file, TMP_GEN (bb), "tmp_gen", bb->index);
+	  print_bitmap_set (dump_file, AVAIL_OUT (bb), "avail_out", bb->index);
 	}
+
+      print_bitmap_set (dump_file, maximal_set, "maximal", 0);
     }
 
   /* Insert can get quite slow on an incredibly large number of basic