Commit e41d82f5 by Richard Henderson Committed by Richard Henderson

re PR tree-optimization/20610 (Real by complex multiplications perform unnecessary operations)

        PR tree-opt/20610
        * tree.h (DECL_COMPLEX_GIMPLE_REG_P): New.
        (struct tree_decl): Add gimple_reg_flag.
        * integrate.c (copy_decl_for_inlining): Copy it.
        * gimplify.c (internal_get_tmp_var): Set it.
        (gimplify_bind_expr): Likewise.
        (gimplify_function_tree): Likewise.
        (gimplify_modify_expr_complex_part): New.
        (gimplify_modify_expr): Use it.
        * tree-gimple.c (is_gimple_reg_type): Allow complex.
        (is_gimple_reg): Allow complex with DECL_COMPLEX_GIMPLE_REG_P set.

        * tree-complex.c (complex_lattice_t): New.
        (complex_lattice_values, complex_variable_components): New.
        (some_nonzerop, find_lattice_value, is_complex_reg,
        init_parameter_lattice_values, init_dont_simulate_again,
        complex_visit_stmt, complex_visit_phi, create_components,
        update_complex_components, update_parameter_components,
        update_phi_components, update_all_vops, expand_complex_move): New.
        (extract_component): Handle INDIRECT_REF, COMPONENT_REF, ARRAY_REF,
        SSA_NAME.
        (update_complex_assignment): Use update_complex_components;
        handle updates of return_expr properly.
        (expand_complex_addition): Use complex lattice values.
        (expand_complex_multiplication): Likewise.
        (expand_complex_division): Likewise.
        (expand_complex_libcall): Use update_complex_components.
        (expand_complex_comparison): Use update_stmt.
        (expand_complex_operations_1): Use expand_complex_move, retrieve
        lattice values.
        (tree_lower_complex): Compute lattice values.
        (tree_lower_complex_O0): Duplicate from tree_lower_complex.
        (pass_lower_complex_O0): Rename from pass_lower_complex.
        (pass_lower_complex, gate_no_optimization): New.
        * tree-optimize.c (init_tree_optimization_passes): Update for
        complex pass changes.
        * tree-pass.h (pass_lower_complex_O0): Declare.

From-SVN: r100793
parent 31920d83
2005-06-09 Richard Henderson <rth@redhat.com>
PR tree-opt/20610
* tree.h (DECL_COMPLEX_GIMPLE_REG_P): New.
(struct tree_decl): Add gimple_reg_flag.
* integrate.c (copy_decl_for_inlining): Copy it.
* gimplify.c (internal_get_tmp_var): Set it.
(gimplify_bind_expr): Likewise.
(gimplify_function_tree): Likewise.
(gimplify_modify_expr_complex_part): New.
(gimplify_modify_expr): Use it.
* tree-gimple.c (is_gimple_reg_type): Allow complex.
(is_gimple_reg): Allow complex with DECL_COMPLEX_GIMPLE_REG_P set.
* tree-complex.c (complex_lattice_t): New.
(complex_lattice_values, complex_variable_components): New.
(some_nonzerop, find_lattice_value, is_complex_reg,
init_parameter_lattice_values, init_dont_simulate_again,
complex_visit_stmt, complex_visit_phi, create_components,
update_complex_components, update_parameter_components,
update_phi_components, update_all_vops, expand_complex_move): New.
(extract_component): Handle INDIRECT_REF, COMPONENT_REF, ARRAY_REF,
SSA_NAME.
(update_complex_assignment): Use update_complex_components;
handle updates of return_expr properly.
(expand_complex_addition): Use complex lattice values.
(expand_complex_multiplication): Likewise.
(expand_complex_division): Likewise.
(expand_complex_libcall): Use update_complex_components.
(expand_complex_comparison): Use update_stmt.
(expand_complex_operations_1): Use expand_complex_move, retrieve
lattice values.
(tree_lower_complex): Compute lattice values.
(tree_lower_complex_O0): Duplicate from tree_lower_complex.
(pass_lower_complex_O0): Rename from pass_lower_complex.
(pass_lower_complex, gate_no_optimization): New.
* tree-optimize.c (init_tree_optimization_passes): Update for
complex pass changes.
* tree-pass.h (pass_lower_complex_O0): Declare.
2005-06-08 Dale Johannesen <dalej@apple.com> 2005-06-08 Dale Johannesen <dalej@apple.com>
* config/darwin.c (darwin_binds_local_p): New. * config/darwin.c (darwin_binds_local_p): New.
......
...@@ -470,6 +470,9 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal) ...@@ -470,6 +470,9 @@ internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
t = lookup_tmp_var (val, is_formal); t = lookup_tmp_var (val, is_formal);
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val); mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val);
if (EXPR_HAS_LOCATION (val)) if (EXPR_HAS_LOCATION (val))
...@@ -856,7 +859,18 @@ gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p) ...@@ -856,7 +859,18 @@ gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
/* Mark variables seen in this bind expr. */ /* Mark variables seen in this bind expr. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t)) for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
DECL_SEEN_IN_BIND_EXPR_P (t) = 1; {
DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
as we find them. */
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
&& !TREE_THIS_VOLATILE (t)
&& (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t))
&& !needs_to_live_in_memory (t))
DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
}
gimple_push_bind_expr (bind_expr); gimple_push_bind_expr (bind_expr);
gimplify_ctxp->save_stack = false; gimplify_ctxp->save_stack = false;
...@@ -3009,6 +3023,45 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p, ...@@ -3009,6 +3023,45 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
return ret; return ret;
} }
/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is
a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
DECL_COMPLEX_GIMPLE_REG_P set. */
static enum gimplify_status
gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
{
enum tree_code code, ocode;
tree lhs, rhs, new_rhs, other, realpart, imagpart;
lhs = TREE_OPERAND (*expr_p, 0);
rhs = TREE_OPERAND (*expr_p, 1);
code = TREE_CODE (lhs);
lhs = TREE_OPERAND (lhs, 0);
ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR;
other = build1 (ocode, TREE_TYPE (rhs), lhs);
other = get_formal_tmp_var (other, pre_p);
realpart = code == REALPART_EXPR ? rhs : other;
imagpart = code == REALPART_EXPR ? other : rhs;
if (TREE_CONSTANT (realpart) && TREE_CONSTANT (imagpart))
new_rhs = build_complex (TREE_TYPE (lhs), realpart, imagpart);
else
new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart);
TREE_OPERAND (*expr_p, 0) = lhs;
TREE_OPERAND (*expr_p, 1) = new_rhs;
if (want_value)
{
append_to_statement_list (*expr_p, pre_p);
*expr_p = rhs;
}
return GS_ALL_DONE;
}
/* Gimplify the MODIFY_EXPR node pointed by EXPR_P. /* Gimplify the MODIFY_EXPR node pointed by EXPR_P.
modify_expr modify_expr
...@@ -3084,6 +3137,14 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value) ...@@ -3084,6 +3137,14 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
} }
} }
/* Transform partial stores to non-addressable complex variables into
total stores. This allows us to use real instead of virtual operands
for these variables, which improves optimization. */
if ((TREE_CODE (*to_p) == REALPART_EXPR
|| TREE_CODE (*to_p) == IMAGPART_EXPR)
&& is_gimple_reg (TREE_OPERAND (*to_p, 0)))
return gimplify_modify_expr_complex_part (expr_p, pre_p, want_value);
if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p)) if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
{ {
/* If we've somehow already got an SSA_NAME on the LHS, then /* If we've somehow already got an SSA_NAME on the LHS, then
...@@ -4668,7 +4729,7 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms) ...@@ -4668,7 +4729,7 @@ gimplify_body (tree *body_p, tree fndecl, bool do_parms)
void void
gimplify_function_tree (tree fndecl) gimplify_function_tree (tree fndecl)
{ {
tree oldfn; tree oldfn, parm, ret;
oldfn = current_function_decl; oldfn = current_function_decl;
current_function_decl = fndecl; current_function_decl = fndecl;
...@@ -4676,6 +4737,22 @@ gimplify_function_tree (tree fndecl) ...@@ -4676,6 +4737,22 @@ gimplify_function_tree (tree fndecl)
if (cfun == NULL) if (cfun == NULL)
allocate_struct_function (fndecl); allocate_struct_function (fndecl);
for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
{
/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
as we find them. */
if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
&& !TREE_THIS_VOLATILE (parm)
&& !needs_to_live_in_memory (parm))
DECL_COMPLEX_GIMPLE_REG_P (parm) = 1;
}
ret = DECL_RESULT (fndecl);
if (TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
&& !needs_to_live_in_memory (ret))
DECL_COMPLEX_GIMPLE_REG_P (ret) = 1;
gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true); gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true);
/* If we're instrumenting function entry/exit, then prepend the call to /* If we're instrumenting function entry/exit, then prepend the call to
......
...@@ -107,6 +107,7 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn) ...@@ -107,6 +107,7 @@ copy_decl_for_inlining (tree decl, tree from_fn, tree to_fn)
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
TREE_READONLY (copy) = TREE_READONLY (decl); TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
DECL_COMPLEX_GIMPLE_REG_P (copy) = DECL_COMPLEX_GIMPLE_REG_P (decl);
} }
else else
{ {
......
...@@ -260,12 +260,10 @@ is_gimple_id (tree t) ...@@ -260,12 +260,10 @@ is_gimple_id (tree t)
bool bool
is_gimple_reg_type (tree type) is_gimple_reg_type (tree type)
{ {
return (!AGGREGATE_TYPE_P (type) return !AGGREGATE_TYPE_P (type);
&& TREE_CODE (type) != COMPLEX_TYPE);
} }
/* Return true if T is a non-aggregate register variable. */
/* Return true if T is a scalar register variable. */
bool bool
is_gimple_reg (tree t) is_gimple_reg (tree t)
...@@ -275,6 +273,7 @@ is_gimple_reg (tree t) ...@@ -275,6 +273,7 @@ is_gimple_reg (tree t)
if (!is_gimple_variable (t)) if (!is_gimple_variable (t))
return false; return false;
if (!is_gimple_reg_type (TREE_TYPE (t))) if (!is_gimple_reg_type (TREE_TYPE (t)))
return false; return false;
...@@ -301,6 +300,11 @@ is_gimple_reg (tree t) ...@@ -301,6 +300,11 @@ is_gimple_reg (tree t)
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
return false; return false;
/* Complex values must have been put into ssa form. That is, no
assignments to the individual components. */
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
return DECL_COMPLEX_GIMPLE_REG_P (t);
return true; return true;
} }
......
...@@ -375,7 +375,7 @@ init_tree_optimization_passes (void) ...@@ -375,7 +375,7 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_lower_cf); NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_lower_eh); NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg); NEXT_PASS (pass_build_cfg);
NEXT_PASS (pass_lower_complex); NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_lower_vector); NEXT_PASS (pass_lower_vector);
NEXT_PASS (pass_warn_function_return); NEXT_PASS (pass_warn_function_return);
NEXT_PASS (pass_tree_profile); NEXT_PASS (pass_tree_profile);
...@@ -417,6 +417,7 @@ init_tree_optimization_passes (void) ...@@ -417,6 +417,7 @@ init_tree_optimization_passes (void)
NEXT_PASS (pass_profile); NEXT_PASS (pass_profile);
NEXT_PASS (pass_ch); NEXT_PASS (pass_ch);
NEXT_PASS (pass_stdarg); NEXT_PASS (pass_stdarg);
NEXT_PASS (pass_lower_complex);
NEXT_PASS (pass_sra); NEXT_PASS (pass_sra);
/* FIXME: SRA may generate arbitrary gimple code, exposing new /* FIXME: SRA may generate arbitrary gimple code, exposing new
aliased and call-clobbered variables. As mentioned below, aliased and call-clobbered variables. As mentioned below,
......
...@@ -192,6 +192,7 @@ extern struct tree_opt_pass pass_may_alias; ...@@ -192,6 +192,7 @@ extern struct tree_opt_pass pass_may_alias;
extern struct tree_opt_pass pass_split_crit_edges; extern struct tree_opt_pass pass_split_crit_edges;
extern struct tree_opt_pass pass_pre; extern struct tree_opt_pass pass_pre;
extern struct tree_opt_pass pass_profile; extern struct tree_opt_pass pass_profile;
extern struct tree_opt_pass pass_lower_complex_O0;
extern struct tree_opt_pass pass_lower_complex; extern struct tree_opt_pass pass_lower_complex;
extern struct tree_opt_pass pass_lower_vector; extern struct tree_opt_pass pass_lower_vector;
extern struct tree_opt_pass pass_lower_vector_ssa; extern struct tree_opt_pass pass_lower_vector_ssa;
......
...@@ -2353,6 +2353,14 @@ extern void decl_value_expr_insert (tree, tree); ...@@ -2353,6 +2353,14 @@ extern void decl_value_expr_insert (tree, tree);
#define DECL_GIMPLE_FORMAL_TEMP_P(DECL) \ #define DECL_GIMPLE_FORMAL_TEMP_P(DECL) \
DECL_CHECK (DECL)->decl.gimple_formal_temp DECL_CHECK (DECL)->decl.gimple_formal_temp
/* For function local variables of COMPLEX type, indicates that the
variable is not aliased, and that all modifications to the variable
have been adjusted so that they are killing assignments. Thus the
variable may now be treated as a GIMPLE register, and use real
instead of virtual ops in SSA form. */
#define DECL_COMPLEX_GIMPLE_REG_P(DECL) \
DECL_CHECK (DECL)->decl.gimple_reg_flag
/* Enumerate visibility settings. */ /* Enumerate visibility settings. */
#ifndef SYMBOL_VISIBILITY_DEFINED #ifndef SYMBOL_VISIBILITY_DEFINED
#define SYMBOL_VISIBILITY_DEFINED #define SYMBOL_VISIBILITY_DEFINED
...@@ -2424,8 +2432,9 @@ struct tree_decl GTY(()) ...@@ -2424,8 +2432,9 @@ struct tree_decl GTY(())
unsigned returns_twice_flag : 1; unsigned returns_twice_flag : 1;
unsigned seen_in_bind_expr : 1; unsigned seen_in_bind_expr : 1;
unsigned novops_flag : 1; unsigned novops_flag : 1;
unsigned has_value_expr:1; unsigned has_value_expr : 1;
/* 8 unused bits. */ unsigned gimple_reg_flag : 1;
/* 7 unused bits. */
union tree_decl_u1 { union tree_decl_u1 {
/* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is /* In a FUNCTION_DECL for which DECL_BUILT_IN holds, this is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment