+ type = TREE_TYPE (GIMPLE_STMT_OPERAND (mod, 1));
+ GIMPLE_STMT_OPERAND (mod, 1) = build2 (COMPLEX_EXPR, type, r, i);
+ update_stmt (stmt);
+}
+
+/* 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)
+{
+ tree phi;
+
+ for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ if (is_complex_reg (PHI_RESULT (phi)))
+ {
+ tree lr, li, pr = NULL, pi = NULL;
+ unsigned int i, n;
+
+ lr = get_component_ssa_name (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 (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 = PHI_NUM_ARGS (phi); i < n; ++i)
+ {
+ tree comp, arg = 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);
+ }
+ }
+ }
+}
+
+/* Mark each virtual op in STMT for ssa update. */
+
+static void
+update_all_vops (tree stmt)
+{
+ ssa_op_iter iter;
+ tree sym;
+
+ FOR_EACH_SSA_TREE_OPERAND (sym, stmt, iter, SSA_OP_ALL_VIRTUALS)
+ {
+ if (TREE_CODE (sym) == SSA_NAME)
+ sym = SSA_NAME_VAR (sym);
+ mark_sym_for_renaming (sym);
+ }
+}
+
+/* Expand a complex move to scalars. */
+
+static void
+expand_complex_move (block_stmt_iterator *bsi, tree stmt, tree type,
+ tree lhs, tree rhs)
+{
+ tree inner_type = TREE_TYPE (type);
+ tree r, i;
+
+ if (TREE_CODE (lhs) == SSA_NAME)
+ {
+ if (is_ctrl_altering_stmt (bsi_stmt (*bsi)))
+ {
+ 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, bsi->bb->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 (TREE_CODE (rhs) == CALL_EXPR || TREE_SIDE_EFFECTS (rhs)
+ || TREE_CODE (rhs) == PAREN_EXPR)
+ {
+ r = build1 (REALPART_EXPR, inner_type, lhs);
+ i = build1 (IMAGPART_EXPR, inner_type, lhs);
+ update_complex_components (bsi, stmt, r, i);
+ }
+ else
+ {
+ update_all_vops (bsi_stmt (*bsi));
+ r = extract_component (bsi, rhs, 0, true);
+ i = extract_component (bsi, rhs, 1, true);
+ update_complex_assignment (bsi, r, i);
+ }
+ }
+ else if (TREE_CODE (rhs) == SSA_NAME && !TREE_SIDE_EFFECTS (lhs))
+ {
+ tree x;
+
+ r = extract_component (bsi, rhs, 0, false);
+ i = extract_component (bsi, rhs, 1, false);
+
+ x = build1 (REALPART_EXPR, inner_type, unshare_expr (lhs));
+ x = build_gimple_modify_stmt (x, r);
+ bsi_insert_before (bsi, x, BSI_SAME_STMT);
+
+ if (stmt == bsi_stmt (*bsi))
+ {
+ x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
+ GIMPLE_STMT_OPERAND (stmt, 0) = x;
+ GIMPLE_STMT_OPERAND (stmt, 1) = i;
+ }
+ else
+ {
+ x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs));
+ x = build_gimple_modify_stmt (x, i);
+ bsi_insert_before (bsi, x, BSI_SAME_STMT);
+
+ stmt = bsi_stmt (*bsi);
+ gcc_assert (TREE_CODE (stmt) == RETURN_EXPR);
+ GIMPLE_STMT_OPERAND (stmt, 0) = lhs;
+ }
+
+ update_all_vops (stmt);
+ update_stmt (stmt);
+ }