summaryrefslogtreecommitdiff
path: root/gcc/tree-complex.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2005-01-25 18:19:09 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>2005-01-25 18:19:09 +0000
commit51009286ecb72b0a6c084211e9e5bc7e802d441f (patch)
tree0adf1f694dd9d4b5548652af20e1700291398272 /gcc/tree-complex.c
parent9253fc43df189f70c8f37b38c34d877a30d70ffa (diff)
downloadgcc-51009286ecb72b0a6c084211e9e5bc7e802d441f.tar.gz
PR middle-end/19609
* tree-complex.c (expand_complex_div_wide): Use the correct formulae. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94222 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-complex.c')
-rw-r--r--gcc/tree-complex.c155
1 files changed, 96 insertions, 59 deletions
diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c
index 6fc6c767e26..3373326aad9 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -169,7 +169,8 @@ expand_complex_div_wide (block_stmt_iterator *bsi, tree inner_type,
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_iterator *bsi, tree inner_type,
cond = fold (build (LT_EXPR, boolean_type_node, t1, t2));
STRIP_NOPS (cond);
- if (TREE_CONSTANT (cond))
+ bb_cond = bb_true = bb_false = bb_join = NULL;
+ rr = ri = tr = ti = NULL;
+ if (!TREE_CONSTANT (cond))
{
- if (integer_zerop (cond))
- min = bi, max = br;
- else
- min = br, max = bi;
- }
- else
- {
- 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_iterator *bsi, tree inner_type,
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_iterator *bsi, tree inner_type,
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);
-
- /* 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);
-
- /* 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);
+ rr = make_rename_temp (inner_type, NULL);
+ ri = make_rename_temp (inner_type, NULL);
}
-
- /* 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);
-
- /* 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);
-
- 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);
+
+ /* 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);
+ }
+
+ 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);
+ }
+ }
+
+ /* 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);
+ }
+
+ ratio = gimplify_build2 (bsi, code, inner_type, bi, br);
+
+ 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);
}