type = TREE_TYPE (TREE_OPERAND (stmt, 1));
TREE_OPERAND (stmt, 1) = build (COMPLEX_EXPR, type, r, i);
- modify_stmt (stmt);
+ mark_stmt_modified (stmt);
}
/* Expand complex addition to scalars:
update_complex_assignment (bsi, rr, ri);
}
+/* Expand a complex multiplication or division to a libcall to the c99
+ compliant routines. */
+
+static void
+expand_complex_libcall (block_stmt_iterator *bsi, tree ar, tree ai,
+ tree br, tree bi, enum tree_code code)
+{
+ enum machine_mode mode;
+ enum built_in_function bcode;
+ tree args, fn, stmt, type;
+
+ args = tree_cons (NULL, bi, NULL);
+ args = tree_cons (NULL, br, args);
+ args = tree_cons (NULL, ai, args);
+ args = tree_cons (NULL, ar, args);
+
+ stmt = bsi_stmt (*bsi);
+ type = TREE_TYPE (TREE_OPERAND (stmt, 1));
+
+ mode = TYPE_MODE (type);
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
+ if (code == MULT_EXPR)
+ bcode = BUILT_IN_COMPLEX_MUL_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+ else if (code == RDIV_EXPR)
+ bcode = BUILT_IN_COMPLEX_DIV_MIN + mode - MIN_MODE_COMPLEX_FLOAT;
+ else
+ gcc_unreachable ();
+ fn = built_in_decls[bcode];
+
+ TREE_OPERAND (stmt, 1)
+ = build3 (CALL_EXPR, type, build_fold_addr_expr (fn), args, NULL);
+ update_stmt (stmt);
+}
+
/* Expand complex multiplication to scalars:
a * b = (ar*br - ai*bi) + i(ar*bi + br*ai)
*/
{
tree t1, t2, t3, t4, rr, ri;
+ if (flag_complex_method == 2 && SCALAR_FLOAT_TYPE_P (inner_type))
+ {
+ expand_complex_libcall (bsi, ar, ai, br, bi, MULT_EXPR);
+ return;
+ }
+
t1 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, br);
t2 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ai, bi);
t3 = gimplify_build2 (bsi, MULT_EXPR, inner_type, ar, bi);
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);
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;
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);
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);
+ /* 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);
- /* 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, bi, ratio);
+ div = gimplify_build2 (bsi, PLUS_EXPR, inner_type, t1, 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, 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);
}
tree ar, tree ai, tree br, tree bi,
enum tree_code code)
{
- switch (flag_complex_divide_method)
+ switch (flag_complex_method)
{
case 0:
/* straightforward implementation of complex divide acceptable. */
expand_complex_div_straight (bsi, inner_type, ar, ai, br, bi, code);
break;
+
+ case 2:
+ if (SCALAR_FLOAT_TYPE_P (inner_type))
+ {
+ expand_complex_libcall (bsi, ar, ai, br, bi, code);
+ return;
+ }
+ /* FALLTHRU */
+
case 1:
/* wide ranges of inputs must work for complex divide. */
expand_complex_div_wide (bsi, inner_type, ar, ai, br, bi, code);
break;
+
default:
- /* C99-like requirements for complex divide (not yet implemented). */
gcc_unreachable ();
}
}
gcc_unreachable ();
}
- modify_stmt (stmt);
+ mark_stmt_modified (stmt);
}
/* Process one statement. If we identify a complex operation, expand it. */
default:
gcc_unreachable ();
}
+ update_stmt_if_modified (stmt);
}
\f
/* Build a constant of type TYPE, made of VALUE's bits replicated
*p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
TREE_OPERAND (rhs, 0),
TREE_OPERAND (rhs, 1), code);
- modify_stmt (bsi_stmt (*bsi));
+ mark_stmt_modified (bsi_stmt (*bsi));
return;
case NEGATE_EXPR:
*p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
TREE_OPERAND (rhs, 0),
NULL_TREE, code);
- modify_stmt (bsi_stmt (*bsi));
+ mark_stmt_modified (bsi_stmt (*bsi));
return;
case BIT_AND_EXPR:
*p_rhs = expand_vector_parallel (bsi, do_binop, type,
TREE_OPERAND (rhs, 0),
TREE_OPERAND (rhs, 1), code);
- modify_stmt (bsi_stmt (*bsi));
+ mark_stmt_modified (bsi_stmt (*bsi));
return;
case BIT_NOT_EXPR:
*p_rhs = expand_vector_parallel (bsi, do_unop, type,
TREE_OPERAND (rhs, 0),
NULL_TREE, code);
- modify_stmt (bsi_stmt (*bsi));
+ mark_stmt_modified (bsi_stmt (*bsi));
return;
default:
TREE_OPERAND (rhs, 0),
TREE_OPERAND (rhs, 1), code);
- modify_stmt (bsi_stmt (*bsi));
+ mark_stmt_modified (bsi_stmt (*bsi));
}
\f
static void