Allow the cplxlower pass to identify if an operation does not need to be lowered through optabs. In this case, lowering is not performed. The cplxlower pass now has to handle a mix of lowered and non-lowered operations. A quick access to both parts of a complex constant is also implemented.
gcc/lto/ChangeLog: * lto-common.cc (compare_tree_sccs_1): Handle both parts of a complex constant gcc/ChangeLog: * coretypes.h: Add enum for complex parts * gensupport.cc (match_pattern): Add complex types * lto-streamer-out.cc (DFS::DFS_write_tree_body): (hash_tree): Handle both parts of a complex constant * tree-complex.cc (get_component_var): Support handling of both parts of a complex (get_component_ssa_name): Likewise (set_component_ssa_name): Likewise (extract_component): Likewise (update_complex_components): Likewise (update_complex_components_on_edge): Likewise (update_complex_assignment): Likewise (update_phi_components): Likewise (expand_complex_move): Likewise (expand_complex_asm): Update with complex_part_t (complex_component_cst_p): New: check if a complex component is a constant (target_native_complex_operation): New: Check if complex operation is supported natively by the backend, through the optab (expand_complex_operations_1): Condionally lowered ops (tree_lower_complex): Support handling of both parts of a complex * tree-core.h (struct GTY): Add field for both parts of the tree_complex struct * tree-streamer-in.cc (lto_input_ts_complex_tree_pointers): Handle both parts of a complex constant * tree-streamer-out.cc (write_ts_complex_tree_pointers): Likewise * tree.cc (build_complex): likewise * tree.h (class auto_suppress_location_wrappers): (type_has_mode_precision_p): Add special case for complex --- gcc/coretypes.h | 9 + gcc/gensupport.cc | 2 + gcc/lto-streamer-out.cc | 2 + gcc/lto/lto-common.cc | 2 + gcc/tree-complex.cc | 434 +++++++++++++++++++++++++++++---------- gcc/tree-core.h | 1 + gcc/tree-streamer-in.cc | 1 + gcc/tree-streamer-out.cc | 1 + gcc/tree.cc | 8 + gcc/tree.h | 15 +- 10 files changed, 363 insertions(+), 112 deletions(-) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index ca8837cef67..a000c104b53 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -443,6 +443,15 @@ enum optimize_size_level OPTIMIZE_SIZE_MAX }; +/* part of a complex */ + +typedef enum +{ + REAL_P = 0, + IMAG_P = 1, + BOTH_P = 2 +} complex_part_t; + /* Support for user-provided GGC and PCH markers. The first parameter is a pointer to a pointer, the second either NULL if the pointer to pointer points into a GC object or the actual pointer address if diff --git a/gcc/gensupport.cc b/gcc/gensupport.cc index 959d1d9c83c..9aa2ba69fcd 100644 --- a/gcc/gensupport.cc +++ b/gcc/gensupport.cc @@ -3746,9 +3746,11 @@ match_pattern (optab_pattern *p, const char *name, const char *pat) break; if (*p == 0 && (! force_int || mode_class[i] == MODE_INT + || mode_class[i] == MODE_COMPLEX_INT || mode_class[i] == MODE_VECTOR_INT) && (! force_partial_int || mode_class[i] == MODE_INT + || mode_class[i] == MODE_COMPLEX_INT || mode_class[i] == MODE_PARTIAL_INT || mode_class[i] == MODE_VECTOR_INT) && (! force_float diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 5ffa8954022..38c48e44867 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -985,6 +985,7 @@ DFS::DFS_write_tree_body (struct output_block *ob, { DFS_follow_tree_edge (TREE_REALPART (expr)); DFS_follow_tree_edge (TREE_IMAGPART (expr)); + DFS_follow_tree_edge (TREE_COMPLEX_BOTH_PARTS (expr)); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) @@ -1417,6 +1418,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map, { visit (TREE_REALPART (t)); visit (TREE_IMAGPART (t)); + visit (TREE_COMPLEX_BOTH_PARTS (t)); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc index 703e665b698..f647ee62f9e 100644 --- a/gcc/lto/lto-common.cc +++ b/gcc/lto/lto-common.cc @@ -1408,6 +1408,8 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map) { compare_tree_edges (TREE_REALPART (t1), TREE_REALPART (t2)); compare_tree_edges (TREE_IMAGPART (t1), TREE_IMAGPART (t2)); + compare_tree_edges (TREE_COMPLEX_BOTH_PARTS (t1), + TREE_COMPLEX_BOTH_PARTS (t2)); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) diff --git a/gcc/tree-complex.cc b/gcc/tree-complex.cc index 688fe13989c..63753e4acf4 100644 --- a/gcc/tree-complex.cc +++ b/gcc/tree-complex.cc @@ -42,6 +42,10 @@ along with GCC; see the file COPYING3. If not see #include "cfganal.h" #include "gimple-fold.h" #include "diagnostic-core.h" +#include "target.h" +#include "memmodel.h" +#include "optabs-tree.h" +#include "internal-fn.h" /* For each complex ssa name, a lattice value. We're interested in finding @@ -74,7 +78,7 @@ static vec<complex_lattice_t> complex_lattice_values; the hashtable. */ static int_tree_htab_type *complex_variable_components; -/* For each complex SSA_NAME, a pair of ssa names for the components. */ +/* For each complex SSA_NAME, three ssa names for the components. */ static vec<tree> complex_ssa_name_components; /* Vector of PHI triplets (original complex PHI and corresponding real and @@ -476,17 +480,27 @@ create_one_component_var (tree type, tree orig, const char *prefix, /* Retrieve a value for a complex component of VAR. */ static tree -get_component_var (tree var, bool imag_p) +get_component_var (tree var, complex_part_t part) { - size_t decl_index = DECL_UID (var) * 2 + imag_p; + size_t decl_index = DECL_UID (var) * 3 + part; tree ret = cvc_lookup (decl_index); if (ret == NULL) { - ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var, - imag_p ? "CI" : "CR", - imag_p ? "$imag" : "$real", - imag_p ? IMAGPART_EXPR : REALPART_EXPR); + switch (part) + { + case REAL_P: + ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var, + "CR", "$real", REALPART_EXPR); + break; + case IMAG_P: + ret = create_one_component_var (TREE_TYPE (TREE_TYPE (var)), var, + "CI", "$imag", IMAGPART_EXPR); + break; + case BOTH_P: + ret = var; + break; + } cvc_insert (decl_index, ret); } @@ -496,13 +510,15 @@ get_component_var (tree var, bool imag_p) /* Retrieve a value for a complex component of SSA_NAME. */ static tree -get_component_ssa_name (tree ssa_name, bool imag_p) +get_component_ssa_name (tree ssa_name, complex_part_t part) { complex_lattice_t lattice = find_lattice_value (ssa_name); size_t ssa_name_index; tree ret; - if (lattice == (imag_p ? ONLY_REAL : ONLY_IMAG)) + if (((lattice == ONLY_IMAG) && (part == REAL_P)) + || ((lattice == ONLY_REAL) && (part == IMAG_P))) + { tree inner_type = TREE_TYPE (TREE_TYPE (ssa_name)); if (SCALAR_FLOAT_TYPE_P (inner_type)) @@ -511,14 +527,33 @@ get_component_ssa_name (tree ssa_name, bool imag_p) return build_int_cst (inner_type, 0); } - ssa_name_index = SSA_NAME_VERSION (ssa_name) * 2 + imag_p; + if (part == BOTH_P) + return ssa_name; + + ssa_name_index = SSA_NAME_VERSION (ssa_name) * 3 + part; + + /* increase size of dynamic array if needed */ + if (ssa_name_index >= complex_ssa_name_components.length ()) + { + complex_ssa_name_components.safe_grow_cleared + (2 * complex_ssa_name_components.length (), true); + complex_lattice_values.safe_grow_cleared + (2 * complex_lattice_values.length (), true); + } + ret = complex_ssa_name_components[ssa_name_index]; if (ret == NULL) { if (SSA_NAME_VAR (ssa_name)) - ret = get_component_var (SSA_NAME_VAR (ssa_name), imag_p); + ret = get_component_var (SSA_NAME_VAR (ssa_name), part); else - ret = TREE_TYPE (TREE_TYPE (ssa_name)); + { + if (part == BOTH_P) + ret = TREE_TYPE (ssa_name); + else + ret = TREE_TYPE (TREE_TYPE (ssa_name)); + } + ret = make_ssa_name (ret); /* Copy some properties from the original. In particular, whether it @@ -542,7 +577,7 @@ get_component_ssa_name (tree ssa_name, bool imag_p) gimple_seq of stuff that needs doing. */ static gimple_seq -set_component_ssa_name (tree ssa_name, bool imag_p, tree value) +set_component_ssa_name (tree ssa_name, complex_part_t part, tree value) { complex_lattice_t lattice = find_lattice_value (ssa_name); size_t ssa_name_index; @@ -553,14 +588,24 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value) /* We know the value must be zero, else there's a bug in our lattice analysis. But the value may well be a variable known to contain zero. We should be safe ignoring it. */ - if (lattice == (imag_p ? ONLY_REAL : ONLY_IMAG)) + if (((lattice == ONLY_IMAG) && (part == REAL_P)) + || ((lattice == ONLY_REAL) && (part == IMAG_P))) return NULL; /* If we've already assigned an SSA_NAME to this component, then this means that our walk of the basic blocks found a use before the set. This is fine. Now we should create an initialization for the value we created earlier. */ - ssa_name_index = SSA_NAME_VERSION (ssa_name) * 2 + imag_p; + ssa_name_index = SSA_NAME_VERSION (ssa_name) * 3 + part; + + /* increase size of dynamic array if needed */ + if (ssa_name_index >= complex_ssa_name_components.length ()) + { + size_t old_size = complex_ssa_name_components.length (); + complex_ssa_name_components.safe_grow (2 * old_size, true); + complex_lattice_values.safe_grow (2 * old_size, true); + } + comp = complex_ssa_name_components[ssa_name_index]; if (comp) ; @@ -584,7 +629,7 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value) && (!SSA_NAME_VAR (value) || DECL_IGNORED_P (SSA_NAME_VAR (value))) && !DECL_IGNORED_P (SSA_NAME_VAR (ssa_name))) { - comp = get_component_var (SSA_NAME_VAR (ssa_name), imag_p); + comp = get_component_var (SSA_NAME_VAR (ssa_name), part); replace_ssa_name_symbol (value, comp); } @@ -595,7 +640,7 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value) /* Finally, we need to stabilize the result by installing the value into a new ssa name. */ else - comp = get_component_ssa_name (ssa_name, imag_p); + comp = get_component_ssa_name (ssa_name, part); /* Do all the work to assign VALUE to COMP. */ list = NULL; @@ -612,13 +657,14 @@ set_component_ssa_name (tree ssa_name, bool imag_p, tree value) Emit any new code before gsi. */ static tree -extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, +extract_component (gimple_stmt_iterator * gsi, tree t, complex_part_t part, bool gimple_p, bool phiarg_p = false) { switch (TREE_CODE (t)) { case COMPLEX_CST: - return imagpart_p ? TREE_IMAGPART (t) : TREE_REALPART (t); + return (part == BOTH_P) ? t : (part == IMAG_P) ? + TREE_IMAGPART (t) : TREE_REALPART (t); case COMPLEX_EXPR: gcc_unreachable (); @@ -629,7 +675,7 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, t = unshare_expr (t); TREE_TYPE (t) = inner_type; TREE_OPERAND (t, 1) = TYPE_SIZE (inner_type); - if (imagpart_p) + if (part == IMAG_P) TREE_OPERAND (t, 2) = size_binop (PLUS_EXPR, TREE_OPERAND (t, 2), TYPE_SIZE (inner_type)); if (gimple_p) @@ -646,10 +692,11 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, case VIEW_CONVERT_EXPR: case MEM_REF: { - tree inner_type = TREE_TYPE (TREE_TYPE (t)); - - t = build1 ((imagpart_p ? IMAGPART_EXPR : REALPART_EXPR), - inner_type, unshare_expr (t)); + if (part == BOTH_P) + t = unshare_expr (t); + else + t = build1 (((part == IMAG_P) ? IMAGPART_EXPR : REALPART_EXPR), + (TREE_TYPE (TREE_TYPE (t))), unshare_expr (t)); if (gimple_p) t = force_gimple_operand_gsi (gsi, t, true, NULL, true, @@ -659,10 +706,12 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, } case SSA_NAME: - t = get_component_ssa_name (t, imagpart_p); - if (TREE_CODE (t) == SSA_NAME && SSA_NAME_DEF_STMT (t) == NULL) - gcc_assert (phiarg_p); - return t; + { + t = get_component_ssa_name (t, part); + if (TREE_CODE (t) == SSA_NAME && SSA_NAME_DEF_STMT (t) == NULL) + gcc_assert (phiarg_p); + return t; + } default: gcc_unreachable (); @@ -673,18 +722,29 @@ extract_component (gimple_stmt_iterator *gsi, tree t, bool imagpart_p, static void update_complex_components (gimple_stmt_iterator *gsi, gimple *stmt, tree r, - tree i) + tree i, tree b = NULL) { tree lhs; gimple_seq list; + gcc_assert (b || (r && i)); lhs = gimple_get_lhs (stmt); + if (!b) + b = lhs; + if (!r) + r = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (b)), unshare_expr (b)); + if (!i) + i = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (b)), unshare_expr (b)); + + list = set_component_ssa_name (lhs, REAL_P, r); + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); - list = set_component_ssa_name (lhs, false, r); + list = set_component_ssa_name (lhs, IMAG_P, i); if (list) gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); - list = set_component_ssa_name (lhs, true, i); + list = set_component_ssa_name (lhs, BOTH_P, b); if (list) gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); } @@ -694,11 +754,11 @@ update_complex_components_on_edge (edge e, tree lhs, tree r, tree i) { gimple_seq list; - list = set_component_ssa_name (lhs, false, r); + list = set_component_ssa_name (lhs, REAL_P, r); if (list) gsi_insert_seq_on_edge (e, list); - list = set_component_ssa_name (lhs, true, i); + list = set_component_ssa_name (lhs, IMAG_P, i); if (list) gsi_insert_seq_on_edge (e, list); } @@ -707,19 +767,24 @@ update_complex_components_on_edge (edge e, tree lhs, tree r, tree i) /* Update an assignment to a complex variable in place. */ static void -update_complex_assignment (gimple_stmt_iterator *gsi, tree r, tree i) +update_complex_assignment (gimple_stmt_iterator * gsi, tree r, tree i, + tree b = NULL) { gimple *old_stmt = gsi_stmt (*gsi); - gimple_assign_set_rhs_with_ops (gsi, COMPLEX_EXPR, r, i); + if (b == NULL) + gimple_assign_set_rhs_with_ops (gsi, COMPLEX_EXPR, r, i); + else + /* dummy assignment, but pr45569.C fails if removed */ + gimple_assign_set_rhs_from_tree (gsi, b); + gimple *stmt = gsi_stmt (*gsi); update_stmt (stmt); if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)) bitmap_set_bit (need_eh_cleanup, gimple_bb (stmt)->index); - update_complex_components (gsi, gsi_stmt (*gsi), r, i); + update_complex_components (gsi, gsi_stmt (*gsi), r, i, b); } - /* Generate code at the entry point of the function to initialize the component variables for a complex parameter. */ @@ -768,7 +833,8 @@ update_phi_components (basic_block bb) for (j = 0; j < 2; j++) { - tree l = get_component_ssa_name (gimple_phi_result (phi), j > 0); + tree l = get_component_ssa_name (gimple_phi_result (phi), + (complex_part_t) j); if (TREE_CODE (l) == SSA_NAME) p[j] = create_phi_node (l, bb); } @@ -779,7 +845,9 @@ update_phi_components (basic_block bb) for (j = 0; j < 2; j++) if (p[j]) { - comp = extract_component (NULL, arg, j > 0, false, true); + comp = + extract_component (NULL, arg, (complex_part_t) j, false, + true); if (TREE_CODE (comp) == SSA_NAME && SSA_NAME_DEF_STMT (comp) == NULL) { @@ -809,13 +877,14 @@ update_phi_components (basic_block bb) } } + /* 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; + tree r, i, b, lhs, rhs; gimple *stmt = gsi_stmt (*gsi); if (is_gimple_assign (stmt)) @@ -862,16 +931,13 @@ expand_complex_move (gimple_stmt_iterator *gsi, tree type) else { if (gimple_assign_rhs_code (stmt) != COMPLEX_EXPR) - { - r = extract_component (gsi, rhs, 0, true); - i = extract_component (gsi, rhs, 1, true); - } + update_complex_assignment (gsi, NULL, NULL, + extract_component (gsi, rhs, + BOTH_P, true)); else - { - r = gimple_assign_rhs1 (stmt); - i = gimple_assign_rhs2 (stmt); - } - update_complex_assignment (gsi, r, i); + update_complex_assignment (gsi, + gimple_assign_rhs1 (stmt), + gimple_assign_rhs2 (stmt), NULL); } } else if (rhs @@ -883,24 +949,18 @@ expand_complex_move (gimple_stmt_iterator *gsi, tree type) location_t loc; loc = gimple_location (stmt); - 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); - gimple_set_location (t, loc); - gsi_insert_before (gsi, t, GSI_SAME_STMT); + b = extract_component (gsi, rhs, BOTH_P, false); if (stmt == gsi_stmt (*gsi)) { - x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs)); + x = unshare_expr (lhs); gimple_assign_set_lhs (stmt, x); - gimple_assign_set_rhs1 (stmt, i); + gimple_assign_set_rhs1 (stmt, b); } else { - x = build1 (IMAGPART_EXPR, inner_type, unshare_expr (lhs)); - t = gimple_build_assign (x, i); + x = unshare_expr (lhs); + t = gimple_build_assign (x, b); gimple_set_location (t, loc); gsi_insert_before (gsi, t, GSI_SAME_STMT); @@ -1641,26 +1701,88 @@ expand_complex_asm (gimple_stmt_iterator *gsi) } /* Make sure to not ICE later, see PR105165. */ tree zero = build_zero_cst (TREE_TYPE (TREE_TYPE (op))); - set_component_ssa_name (op, false, zero); - set_component_ssa_name (op, true, zero); + set_component_ssa_name (op, REAL_P, zero); + set_component_ssa_name (op, IMAG_P, zero); + set_component_ssa_name (op, BOTH_P, zero); continue; } tree type = TREE_TYPE (op); tree inner_type = TREE_TYPE (type); tree r = build1 (REALPART_EXPR, inner_type, op); tree i = build1 (IMAGPART_EXPR, inner_type, op); - gimple_seq list = set_component_ssa_name (op, false, r); + tree b = op; + gimple_seq list = set_component_ssa_name (op, REAL_P, r); if (list) gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); - list = set_component_ssa_name (op, true, i); + list = set_component_ssa_name (op, IMAG_P, i); + if (list) + gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); + + list = set_component_ssa_name (op, BOTH_P, b); if (list) gsi_insert_seq_after (gsi, list, GSI_CONTINUE_LINKING); } } } +/* Returns true if a complex component is a constant */ + +static bool +complex_component_cst_p (tree cplx, complex_part_t part) +{ + switch (TREE_CODE (cplx)) + { + case COMPLEX_CST: + return true; + + case SSA_NAME: + { + size_t ssa_name_index = SSA_NAME_VERSION (cplx) * 3 + part; + tree val = complex_ssa_name_components[ssa_name_index]; + return (val) ? CONSTANT_CLASS_P (val) : false; + } + + default: + return false; + } +} + +/* Returns true if the target support a particular complex operation natively */ + +static bool +target_native_complex_operation (enum tree_code code, tree type, + tree inner_type, tree ac, tree bc, + complex_lattice_t al, complex_lattice_t bl) +{ + /* Native complex instructions are currently only used when both operands are varying, + but a finer grain approach may be interesting */ + if ((al != VARYING) || ((bl != VARYING) && (bl != UNINITIALIZED))) + return false; + + /* do not use native operations when a part of the result is constant */ + if ((bl == UNINITIALIZED) + && (complex_component_cst_p (ac, REAL_P) + || complex_component_cst_p (ac, IMAG_P))) + return false; + else if ((bl != UNINITIALIZED) + && + ((complex_component_cst_p (ac, REAL_P) + && complex_component_cst_p (bc, REAL_P)) + || (complex_component_cst_p (ac, IMAG_P) + && complex_component_cst_p (bc, IMAG_P)))) + return false; + + optab op = optab_for_tree_code (code, inner_type, optab_default); + + /* no need to search if operation is not in the optab */ + if (op == unknown_optab) + return false; + + return optab_handler (op, TYPE_MODE (type)) != CODE_FOR_nothing; +} + /* Process one statement. If we identify a complex operation, expand it. */ static void @@ -1729,14 +1851,17 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi) && TREE_CODE (lhs) == SSA_NAME) { rhs = gimple_assign_rhs1 (stmt); + enum tree_code rhs_code = gimple_assign_rhs_code (stmt); rhs = extract_component (gsi, TREE_OPERAND (rhs, 0), - gimple_assign_rhs_code (stmt) - == IMAGPART_EXPR, - false); + (rhs_code == IMAGPART_EXPR) ? IMAG_P + : (rhs_code == REALPART_EXPR) ? REAL_P + : BOTH_P, false); gimple_assign_set_rhs_from_tree (gsi, rhs); stmt = gsi_stmt (*gsi); update_stmt (stmt); } + else if (is_gimple_call (stmt)) + return; } return; } @@ -1755,19 +1880,6 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi) bc = gimple_cond_rhs (stmt); } - ar = extract_component (gsi, ac, false, true); - ai = extract_component (gsi, ac, true, true); - - if (ac == bc) - br = ar, bi = ai; - else if (bc) - { - br = extract_component (gsi, bc, 0, true); - bi = extract_component (gsi, bc, 1, true); - } - else - br = bi = NULL_TREE; - al = find_lattice_value (ac); if (al == UNINITIALIZED) al = VARYING; @@ -1783,44 +1895,142 @@ expand_complex_operations_1 (gimple_stmt_iterator *gsi) bl = VARYING; } - switch (code) + if (target_native_complex_operation + (code, type, inner_type, ac, bc, al, bl)) { - case PLUS_EXPR: - case MINUS_EXPR: - expand_complex_addition (gsi, inner_type, ar, ai, br, bi, code, al, bl); - break; + tree ab, bb, rb; + gimple_seq stmts = NULL; + location_t loc = gimple_location (gsi_stmt (*gsi)); + + ab = extract_component (gsi, ac, BOTH_P, true); + if (ac == bc) + bb = ab; + else if (bc) + { + bb = extract_component (gsi, bc, BOTH_P, true); + } + else + bb = NULL_TREE; - case MULT_EXPR: - expand_complex_multiplication (gsi, type, ar, ai, br, bi, al, bl); - break; + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + rb = gimple_build (&stmts, loc, code, type, ab, bb); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + update_complex_assignment (gsi, NULL, NULL, rb); + break; - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case RDIV_EXPR: - expand_complex_division (gsi, type, ar, ai, br, bi, code, al, bl); - break; + case NEGATE_EXPR: + case CONJ_EXPR: + rb = gimple_build (&stmts, loc, code, type, ab); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + update_complex_assignment (gsi, NULL, NULL, rb); + break; - case NEGATE_EXPR: - expand_complex_negation (gsi, inner_type, ar, ai); - break; + case EQ_EXPR: + case NE_EXPR: + /* FIXME */ + { + gimple *stmt = gsi_stmt (*gsi); + rb = gimple_build (&stmts, loc, code, type, ab, bb); + switch (gimple_code (stmt)) + { + case GIMPLE_RETURN: + { + greturn *return_stmt = as_a < greturn * >(stmt); + gimple_return_set_retval (return_stmt, + fold_convert (type, rb)); + } + break; - case CONJ_EXPR: - expand_complex_conjugate (gsi, inner_type, ar, ai); - break; + case GIMPLE_ASSIGN: + update_complex_assignment (gsi, NULL, NULL, rb); + gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT); + break; - case EQ_EXPR: - case NE_EXPR: - expand_complex_comparison (gsi, ar, ai, br, bi, code); - break; + case GIMPLE_COND: + { + gcond *cond_stmt = as_a < gcond * >(stmt); + gimple_cond_set_code (cond_stmt, EQ_EXPR); + gimple_cond_set_lhs (cond_stmt, rb); + gimple_cond_set_rhs (cond_stmt, boolean_true_node); + } + break; - default: - gcc_unreachable (); + default: + break; + } + break; + } + + + /* not supported yet */ + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + + default: + gcc_unreachable (); + } + return; } -} + ar = extract_component (gsi, ac, REAL_P, true); + ai = extract_component (gsi, ac, IMAG_P, true); + + if (ac == bc) + br = ar, bi = ai; + else if (bc) + { + br = extract_component (gsi, bc, REAL_P, true); + bi = extract_component (gsi, bc, IMAG_P, true); + } + else + br = bi = NULL_TREE; + + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + expand_complex_addition (gsi, inner_type, ar, ai, br, bi, code, al, + bl); + break; + + case MULT_EXPR: + expand_complex_multiplication (gsi, type, ar, ai, br, bi, al, bl); + break; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + expand_complex_division (gsi, type, ar, ai, br, bi, code, al, bl); + break; + + case NEGATE_EXPR: + expand_complex_negation (gsi, inner_type, ar, ai); + break; + + case CONJ_EXPR: + expand_complex_conjugate (gsi, inner_type, ar, ai); + break; + + case EQ_EXPR: + case NE_EXPR: + expand_complex_comparison (gsi, ar, ai, br, bi, code); + break; + + default: + gcc_unreachable (); + } +} + /* Entry point for complex operation lowering during optimization. */ static unsigned int @@ -1845,8 +2055,8 @@ tree_lower_complex (void) complex_variable_components = new int_tree_htab_type (10); - complex_ssa_name_components.create (2 * num_ssa_names); - complex_ssa_name_components.safe_grow_cleared (2 * num_ssa_names, true); + complex_ssa_name_components.create (3 * num_ssa_names); + complex_ssa_name_components.safe_grow_cleared (3 * num_ssa_names, true); update_parameter_components (); @@ -1879,7 +2089,9 @@ tree_lower_complex (void) || is_gimple_min_invariant (op)) continue; tree arg = gimple_phi_arg_def (phis_to_revisit[j], l); - op = extract_component (NULL, arg, k > 0, false, false); + op = + extract_component (NULL, arg, (complex_part_t) k, false, + false); SET_PHI_ARG_DEF (phi, l, op); } } diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 668808a29d0..da6daf99fc1 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1486,6 +1486,7 @@ struct GTY(()) tree_complex { struct tree_typed typed; tree real; tree imag; + tree both; }; struct GTY(()) tree_vector { diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc index 5bead0c3c6a..a1fa2cb9eea 100644 --- a/gcc/tree-streamer-in.cc +++ b/gcc/tree-streamer-in.cc @@ -695,6 +695,7 @@ lto_input_ts_complex_tree_pointers (class lto_input_block *ib, { TREE_REALPART (expr) = stream_read_tree_ref (ib, data_in); TREE_IMAGPART (expr) = stream_read_tree_ref (ib, data_in); + TREE_COMPLEX_BOTH_PARTS (expr) = stream_read_tree_ref (ib, data_in); } diff --git a/gcc/tree-streamer-out.cc b/gcc/tree-streamer-out.cc index ff9694e17dd..be7314ef748 100644 --- a/gcc/tree-streamer-out.cc +++ b/gcc/tree-streamer-out.cc @@ -592,6 +592,7 @@ write_ts_complex_tree_pointers (struct output_block *ob, tree expr) { stream_write_tree_ref (ob, TREE_REALPART (expr)); stream_write_tree_ref (ob, TREE_IMAGPART (expr)); + stream_write_tree_ref (ob, TREE_COMPLEX_BOTH_PARTS (expr)); } diff --git a/gcc/tree.cc b/gcc/tree.cc index 420857b110c..2bc1b0d1e3f 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -2497,6 +2497,14 @@ build_complex (tree type, tree real, tree imag) tree t = make_node (COMPLEX_CST); + /* represent both parts as a constant vector */ + tree vector_type = build_vector_type (TREE_TYPE (real), 2); + tree_vector_builder v (vector_type, 1, 2); + v.quick_push (real); + v.quick_push (imag); + tree both = v.build (); + + TREE_COMPLEX_BOTH_PARTS (t) = both; TREE_REALPART (t) = real; TREE_IMAGPART (t) = imag; TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real)); diff --git a/gcc/tree.h b/gcc/tree.h index fa02e2907a1..28716b53120 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -634,6 +634,12 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* Nonzero if TYPE represents a complex floating-point type. */ +#define COMPLEX_INTEGER_TYPE_P(TYPE) \ + (TREE_CODE (TYPE) == COMPLEX_TYPE \ + && TREE_CODE (TREE_TYPE (TYPE)) == INTEGER_TYPE) + +/* Nonzero if TYPE represents a complex floating-point type. */ + #define COMPLEX_FLOAT_TYPE_P(TYPE) \ (TREE_CODE (TYPE) == COMPLEX_TYPE \ && TREE_CODE (TREE_TYPE (TYPE)) == REAL_TYPE) @@ -1155,6 +1161,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* In a COMPLEX_CST node. */ #define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real) #define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag) +#define TREE_COMPLEX_BOTH_PARTS(NODE) (COMPLEX_CST_CHECK (NODE)->complex.both) /* In a VECTOR_CST node. See generic.texi for details. */ #define VECTOR_CST_NELTS(NODE) (TYPE_VECTOR_SUBPARTS (TREE_TYPE (NODE))) @@ -2214,6 +2221,8 @@ class auto_suppress_location_wrappers (as_a <scalar_int_mode> (TYPE_CHECK (NODE)->type_common.mode)) #define SCALAR_FLOAT_TYPE_MODE(NODE) \ (as_a <scalar_float_mode> (TYPE_CHECK (NODE)->type_common.mode)) +#define COMPLEX_TYPE_MODE(NODE) \ + (as_a <complex_mode> (TYPE_CHECK (NODE)->type_common.mode)) #define SET_TYPE_MODE(NODE, MODE) \ (TYPE_CHECK (NODE)->type_common.mode = (MODE)) @@ -6646,7 +6655,11 @@ extern const builtin_structptr_type builtin_structptr_types[6]; inline bool type_has_mode_precision_p (const_tree t) { - return known_eq (TYPE_PRECISION (t), GET_MODE_PRECISION (TYPE_MODE (t))); + if (TREE_CODE (t) == COMPLEX_TYPE) + return known_eq (2*TYPE_PRECISION (TREE_TYPE(t)), + GET_MODE_PRECISION (TYPE_MODE (t))); + else + return known_eq (TYPE_PRECISION (t), GET_MODE_PRECISION (TYPE_MODE (t))); } /* Helper functions for fndecl_built_in_p. */ -- 2.17.1