This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

fix middle-end/19609


It has been brought to my attention that when I transliterated this
function from rtl, that I mis-read the original formulae, and thus
made a number of invalid simplifications from that.  Bother.

Tested with flag_complex_divide_method = 1 on ia64-linux.  This is
sufficient to see the bug, because without the following patch, but
with flag_complex_divide_method changed, there are a number of 
Fortran testsuite failures.


r~


        PR middle-end/19609
        * tree-complex.c (expand_complex_div_wide): Use the correct formulae.

Index: tree-complex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-complex.c,v
retrieving revision 2.17
diff -u -p -d -r2.17 tree-complex.c
--- tree-complex.c	24 Jan 2005 11:59:40 -0000	2.17
+++ tree-complex.c	25 Jan 2005 18:16:53 -0000
@@ -169,7 +169,8 @@ expand_complex_div_wide (block_stmt_iter
 			 tree ar, tree ai, tree br, tree bi,
 			 enum tree_code code)
 {
-  tree rr, ri, ratio, div, t1, t2, min, max, cond;
+  tree rr, ri, ratio, div, t1, t2, tr, ti, cond;
+  basic_block bb_cond, bb_true, bb_false, bb_join;
 
   /* Examine |br| < |bi|, and branch.  */
   t1 = gimplify_build1 (bsi, ABS_EXPR, inner_type, br);
@@ -177,30 +178,15 @@ expand_complex_div_wide (block_stmt_iter
   cond = fold (build (LT_EXPR, boolean_type_node, t1, t2));
   STRIP_NOPS (cond);
 
-  if (TREE_CONSTANT (cond))
-    {
-      if (integer_zerop (cond))
-	min = bi, max = br;
-      else
-	min = br, max = bi;
-    }
-  else
+  bb_cond = bb_true = bb_false = bb_join = NULL;
+  rr = ri = tr = ti = NULL;
+  if (!TREE_CONSTANT (cond))
     {
-      basic_block bb_cond, bb_true, bb_false, bb_join;
-      tree l1, l2, l3;
       edge e;
 
-      l1 = create_artificial_label ();
-      t1 = build (GOTO_EXPR, void_type_node, l1);
-      l2 = create_artificial_label ();
-      t2 = build (GOTO_EXPR, void_type_node, l2);
-      cond = build (COND_EXPR, void_type_node, cond, t1, t2);
+      cond = build (COND_EXPR, void_type_node, cond, NULL, NULL);
       bsi_insert_before (bsi, cond, BSI_SAME_STMT);
 
-      min = make_rename_temp (inner_type, NULL);
-      max = make_rename_temp (inner_type, NULL);
-      l3 = create_artificial_label ();
-
       /* Split the original block, and create the TRUE and FALSE blocks.  */
       e = split_block (bsi->bb, cond);
       bb_cond = e->src;
@@ -208,6 +194,11 @@ expand_complex_div_wide (block_stmt_iter
       bb_true = create_empty_bb (bb_cond);
       bb_false = create_empty_bb (bb_true);
 
+      t1 = build (GOTO_EXPR, void_type_node, tree_block_label (bb_true));
+      t2 = build (GOTO_EXPR, void_type_node, tree_block_label (bb_false));
+      COND_EXPR_THEN (cond) = t1;
+      COND_EXPR_ELSE (cond) = t2;
+
       /* Wire the blocks together.  */
       e->flags = EDGE_TRUE_VALUE;
       redirect_edge_succ (e, bb_true);
@@ -223,46 +214,92 @@ expand_complex_div_wide (block_stmt_iter
           set_immediate_dominator (CDI_DOMINATORS, bb_false, bb_cond);
         }
 
-      /* Compute min and max for TRUE block.  */
-      *bsi = bsi_start (bb_true);
-      t1 = build (LABEL_EXPR, void_type_node, l1);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
-      t1 = build (MODIFY_EXPR, inner_type, min, br);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
-      t1 = build (MODIFY_EXPR, inner_type, max, bi);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
+      rr = make_rename_temp (inner_type, NULL);
+      ri = make_rename_temp (inner_type, NULL);
+    }
 
-      /* Compute min and max for FALSE block.  */
-      *bsi = bsi_start (bb_false);
-      t1 = build (LABEL_EXPR, void_type_node, l2);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
-      t1 = build (MODIFY_EXPR, inner_type, min, bi);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
-      t1 = build (MODIFY_EXPR, inner_type, max, br);
-      bsi_insert_after (bsi, t1, BSI_NEW_STMT);
+  /* In the TRUE branch, we compute
+      ratio = br/bi;
+      div = (br * ratio) + bi;
+      tr = (ar * ratio) + ai;
+      ti = (ai * ratio) - ar;
+      tr = tr / div;
+      ti = ti / div;  */
+  if (bb_true || integer_nonzerop (cond))
+    {
+      if (bb_true)
+	{
+	  *bsi = bsi_last (bb_true);
+	  bsi_insert_after (bsi, build_empty_stmt (), BSI_NEW_STMT);
+	}
 
-      /* Insert the join label into the tail of the original block.  */
-      *bsi = bsi_start (bb_join);
-      t1 = build (LABEL_EXPR, void_type_node, l3);
-      bsi_insert_before (bsi, t1, BSI_SAME_STMT);
+      ratio = gimplify_build2 (bsi, code, inner_type, br, bi);
+
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, br, ratio);
+      div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, bi);
+
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, ratio);
+      tr = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, ai);
+
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, ratio);
+      ti = gimplify_build2 (bsi, MINUS_EXPR, inner_type, t1, ar);
+
+      tr = gimplify_build2 (bsi, code, inner_type, tr, div);
+      ti = gimplify_build2 (bsi, code, inner_type, ti, div);
+
+     if (bb_true)
+       {
+	 t1 = build (MODIFY_EXPR, inner_type, rr, tr);
+	 bsi_insert_before (bsi, t1, BSI_SAME_STMT);
+	 t1 = build (MODIFY_EXPR, inner_type, ri, ti);
+	 bsi_insert_before (bsi, t1, BSI_SAME_STMT);
+	 bsi_remove (bsi);
+       }
     }
-  
-  /* Now we have MIN(|br|, |bi|) and MAX(|br|, |bi|).  We now use the
-     ratio min/max to scale both the dividend and divisor.  */
-  ratio = gimplify_build2 (bsi, code, inner_type, min, max);
 
-  /* Calculate the divisor: min*ratio + max.  */
-  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, min, ratio);
-  div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, max);
+  /* In the FALSE branch, we compute
+      ratio = d/c;
+      divisor = (d * ratio) + c;
+      tr = (b * ratio) + a;
+      ti = b - (a * ratio);
+      tr = tr / div;
+      ti = ti / div;  */
+  if (bb_false || integer_zerop (cond))
+    {
+      if (bb_false)
+	{
+	  *bsi = bsi_last (bb_false);
+	  bsi_insert_after (bsi, build_empty_stmt (), BSI_NEW_STMT);
+	}
 
-  /* Result is now ((ar + ai*ratio)/div) + i((ai - ar*ratio)/div).  */
-  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, ratio);
-  t2 = gimplify_build2 (bsi, PLUS_EXPR, inner_type, ar, t1);
-  rr = gimplify_build2 (bsi, code, inner_type, t2, div);
+      ratio = gimplify_build2 (bsi, code, inner_type, bi, br);
 
-  t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, ratio);
-  t2 = gimplify_build2 (bsi, MINUS_EXPR, inner_type, ai, t1);
-  ri = gimplify_build2 (bsi, code, inner_type, t2, div);
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, bi, ratio);
+      div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, br);
+
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, ratio);
+      tr = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, ar);
+
+      t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, ratio);
+      ti = gimplify_build2 (bsi, MINUS_EXPR, inner_type, ai, t1);
+
+      tr = gimplify_build2 (bsi, code, inner_type, tr, div);
+      ti = gimplify_build2 (bsi, code, inner_type, ti, div);
+
+     if (bb_false)
+       {
+	 t1 = build (MODIFY_EXPR, inner_type, rr, tr);
+	 bsi_insert_before (bsi, t1, BSI_SAME_STMT);
+	 t1 = build (MODIFY_EXPR, inner_type, ri, ti);
+	 bsi_insert_before (bsi, t1, BSI_SAME_STMT);
+	 bsi_remove (bsi);
+       }
+    }
+
+  if (bb_join)
+    *bsi = bsi_start (bb_join);
+  else
+    rr = tr, ri = ti;
 
   update_complex_assignment (bsi, rr, ri);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]