+ Emit any new code before gsi. */
+
+static tree
+extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p,
+ bool gimple_p)
+{
+ switch (TREE_CODE (t))
+ {
+ case COMPLEX_CST:
+ return imagpart_p ? TREE_IMAGPART (t) : TREE_REALPART (t);
+
+ case COMPLEX_EXPR:
+ gcc_unreachable ();
+
+ case VAR_DECL:
+ case RESULT_DECL:
+ case PARM_DECL:
+ case INDIRECT_REF:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case VIEW_CONVERT_EXPR:
+ {
+ tree inner_type = TREE_TYPE (TREE_TYPE (t));
+
+ t = build1 ((imagpart_p ? IMAGPART_EXPR : REALPART_EXPR),
+ inner_type, unshare_expr (t));
+
+ if (gimple_p)
+ t = force_gimple_operand_gsi (gsi, t, true, NULL, true,
+ GSI_SAME_STMT);
+
+ return t;
+ }
+
+ case SSA_NAME:
+ return get_component_ssa_name (t, imagpart_p);
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Update the complex components of the ssa name on the lhs of STMT. */
+
+static void
+update_complex_components (gimple_stmt_iterator *gsi, gimple stmt, tree r,
+ tree i)
+{
+ tree lhs;
+ gimple_seq list;
+
+ lhs = gimple_get_lhs (stmt);
+
+ list = set_component_ssa_name (lhs, false, r);
+ if (list)
+ gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+
+ list = set_component_ssa_name (lhs, true, i);
+ if (list)
+ gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING);
+}
+
+static void
+update_complex_components_on_edge (edge e, tree lhs, tree r, tree i)
+{
+ gimple_seq list;
+
+ list = set_component_ssa_name (lhs, false, r);
+ if (list)
+ gsi_insert_seq_on_edge (e, list);
+
+ list = set_component_ssa_name (lhs, true, i);
+ if (list)
+ gsi_insert_seq_on_edge (e, list);
+}
+
+
+/* Update an assignment to a complex variable in place. */
+
+static void
+update_complex_assignment (gimple_stmt_iterator *gsi, tree r, tree i)
+{
+ gimple_stmt_iterator orig_si = *gsi;
+
+ if (gimple_in_ssa_p (cfun))
+ update_complex_components (gsi, gsi_stmt (*gsi), r, i);
+
+ gimple_assign_set_rhs_with_ops (&orig_si, COMPLEX_EXPR, r, i);
+ update_stmt (gsi_stmt (orig_si));
+}
+
+
+/* Generate code at the entry point of the function to initialize the
+ component variables for a complex parameter. */
+
+static void
+update_parameter_components (void)
+{
+ edge entry_edge = single_succ_edge (ENTRY_BLOCK_PTR);
+ tree parm;
+
+ for (parm = DECL_ARGUMENTS (cfun->decl); parm ; parm = TREE_CHAIN (parm))
+ {
+ tree type = TREE_TYPE (parm);
+ tree ssa_name, r, i;
+
+ if (TREE_CODE (type) != COMPLEX_TYPE || !is_gimple_reg (parm))
+ continue;
+
+ type = TREE_TYPE (type);
+ ssa_name = gimple_default_def (cfun, parm);
+ if (!ssa_name)
+ continue;
+
+ r = build1 (REALPART_EXPR, type, ssa_name);
+ i = build1 (IMAGPART_EXPR, type, ssa_name);
+ update_complex_components_on_edge (entry_edge, ssa_name, r, i);
+ }
+}
+
+/* Generate code to set the component variables of a complex variable
+ to match the PHI statements in block BB. */
+
+static void
+update_phi_components (basic_block bb)
+{
+ gimple_stmt_iterator gsi;
+
+ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple phi = gsi_stmt (gsi);
+
+ if (is_complex_reg (gimple_phi_result (phi)))
+ {
+ tree lr, li;
+ gimple pr = NULL, pi = NULL;
+ unsigned int i, n;
+
+ lr = get_component_ssa_name (gimple_phi_result (phi), false);
+ if (TREE_CODE (lr) == SSA_NAME)
+ {
+ pr = create_phi_node (lr, bb);
+ SSA_NAME_DEF_STMT (lr) = pr;
+ }
+
+ li = get_component_ssa_name (gimple_phi_result (phi), true);
+ if (TREE_CODE (li) == SSA_NAME)
+ {
+ pi = create_phi_node (li, bb);
+ SSA_NAME_DEF_STMT (li) = pi;
+ }
+
+ for (i = 0, n = gimple_phi_num_args (phi); i < n; ++i)
+ {
+ tree comp, arg = gimple_phi_arg_def (phi, i);
+ if (pr)
+ {
+ comp = extract_component (NULL, arg, false, false);
+ SET_PHI_ARG_DEF (pr, i, comp);
+ }
+ if (pi)
+ {
+ comp = extract_component (NULL, arg, true, false);
+ SET_PHI_ARG_DEF (pi, i, comp);
+ }
+ }
+ }
+ }
+}
+
+/* Expand a complex move to scalars. */
+
+static void
+expand_complex_move (gimple_stmt_iterator *gsi, tree type)
+{
+ tree inner_type = TREE_TYPE (type);
+ tree r, i, lhs, rhs;
+ gimple stmt = gsi_stmt (*gsi);
+
+ if (is_gimple_assign (stmt))
+ {
+ lhs = gimple_assign_lhs (stmt);
+ if (gimple_num_ops (stmt) == 2)
+ rhs = gimple_assign_rhs1 (stmt);
+ else
+ rhs = NULL_TREE;
+ }
+ else if (is_gimple_call (stmt))
+ {
+ lhs = gimple_call_lhs (stmt);
+ rhs = NULL_TREE;
+ }
+ else
+ gcc_unreachable ();
+
+ if (TREE_CODE (lhs) == SSA_NAME)
+ {
+ if (is_ctrl_altering_stmt (stmt))
+ {
+ edge_iterator ei;
+ edge e;
+
+ /* The value is not assigned on the exception edges, so we need not
+ concern ourselves there. We do need to update on the fallthru
+ edge. Find it. */
+ FOR_EACH_EDGE (e, ei, gsi_bb (*gsi)->succs)
+ if (e->flags & EDGE_FALLTHRU)
+ goto found_fallthru;
+ gcc_unreachable ();
+ found_fallthru:
+
+ r = build1 (REALPART_EXPR, inner_type, lhs);
+ i = build1 (IMAGPART_EXPR, inner_type, lhs);
+ update_complex_components_on_edge (e, lhs, r, i);
+ }
+ else if (is_gimple_call (stmt)
+ || gimple_has_side_effects (stmt)
+ || gimple_assign_rhs_code (stmt) == PAREN_EXPR)
+ {
+ r = build1 (REALPART_EXPR, inner_type, lhs);
+ i = build1 (IMAGPART_EXPR, inner_type, lhs);
+ update_complex_components (gsi, stmt, r, i);
+ }
+ else
+ {
+ if (gimple_assign_rhs_code (stmt) != COMPLEX_EXPR)
+ {
+ r = extract_component (gsi, rhs, 0, true);
+ i = extract_component (gsi, rhs, 1, true);
+ }
+ else
+ {
+ r = gimple_assign_rhs1 (stmt);
+ i = gimple_assign_rhs2 (stmt);
+ }
+ update_complex_assignment (gsi, r, i);
+ }
+ }
+ else if (rhs && TREE_CODE (rhs) == SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
+ {
+ tree x;
+ gimple t;
+
+ r = extract_component (gsi, rhs, 0, false);
+ i = extract_component (gsi, rhs, 1, false);
+
+ x = build1 (REALPART_EXPR, inner_type, unshare_expr (lhs));
+ t = gimple_build_assign (x, r);
+ gsi_insert_before (gsi, t, GSI_SAME_STMT);
+
+ if (stmt == gsi_stmt (*gsi))
+ {
+ x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
+ gimple_assign_set_lhs (stmt, x);
+ gimple_assign_set_rhs1 (stmt, i);
+ }
+ else
+ {
+ x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
+ t = gimple_build_assign (x, i);
+ gsi_insert_before (gsi, t, GSI_SAME_STMT);
+
+ stmt = gsi_stmt (*gsi);
+ gcc_assert (gimple_code (stmt) == GIMPLE_RETURN);
+ gimple_return_set_retval (stmt, lhs);
+ }
+
+ update_stmt (stmt);
+ }
+}
+
+/* Expand complex addition to scalars:
+ a + b = (ar + br) + i(ai + bi)
+ a - b = (ar - br) + i(ai + bi)
+*/
+
+static void
+expand_complex_addition (gimple_stmt_iterator *gsi, tree inner_type,
+ tree ar, tree ai, tree br, tree bi,
+ enum tree_code code,
+ complex_lattice_t al, complex_lattice_t bl)
+{
+ tree rr, ri;
+
+ switch (PAIR (al, bl))
+ {
+ case PAIR (ONLY_REAL, ONLY_REAL):
+ rr = gimplify_build2 (gsi, code, inner_type, ar, br);
+ ri = ai;
+ break;
+
+ case PAIR (ONLY_REAL, ONLY_IMAG):
+ rr = ar;
+ if (code == MINUS_EXPR)
+ ri = gimplify_build2 (gsi, MINUS_EXPR, inner_type, ai, bi);
+ else
+ ri = bi;
+ break;
+
+ case PAIR (ONLY_IMAG, ONLY_REAL):
+ if (code == MINUS_EXPR)
+ rr = gimplify_build2 (gsi, MINUS_EXPR, inner_type, ar, br);
+ else
+ rr = br;
+ ri = ai;
+ break;
+
+ case PAIR (ONLY_IMAG, ONLY_IMAG):
+ rr = ar;
+ ri = gimplify_build2 (gsi, code, inner_type, ai, bi);
+ break;
+
+ case PAIR (VARYING, ONLY_REAL):
+ rr = gimplify_build2 (gsi, code, inner_type, ar, br);
+ ri = ai;
+ break;