diff options
author | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-01-25 18:19:09 +0000 |
---|---|---|
committer | rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-01-25 18:19:09 +0000 |
commit | 51009286ecb72b0a6c084211e9e5bc7e802d441f (patch) | |
tree | 0adf1f694dd9d4b5548652af20e1700291398272 /gcc/tree-complex.c | |
parent | 9253fc43df189f70c8f37b38c34d877a30d70ffa (diff) | |
download | gcc-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.c | 155 |
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); } |