Projects
openEuler:24.03:SP1:Everything
gcc
_service:tar_scm:0311-PATCH-Add-if-split-optimi...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0311-PATCH-Add-if-split-optimization-pass.patch of Package gcc
From 899db9bca3c2ef3cd346814be761eed8b85f5e1e Mon Sep 17 00:00:00 2001 From: liyancheng <412998149@qq.com> Date: Wed, 27 Nov 2024 19:26:13 +0800 Subject: [PATCH] [PATCH] Add if-split optimization pass This pass splits conditions like if (cond1 or cond2) to the sequense of separate conditions. This happens only if there is a function call under condition Which depends on the condition variable. --- gcc/Makefile.in | 1 + gcc/common.opt | 4 + gcc/gimple-if-split.cc | 567 ++++++++++++++++++++ gcc/opts.cc | 2 +- gcc/passes.def | 1 + gcc/testsuite/gcc.dg/tree-ssa/if-split-1.c | 24 + gcc/testsuite/gcc.dg/tree-ssa/if-split-10.c | 45 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-2.c | 36 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-3.c | 36 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-4.c | 42 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-5.c | 42 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-6.c | 45 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-7.c | 45 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-8.c | 42 ++ gcc/testsuite/gcc.dg/tree-ssa/if-split-9.c | 44 ++ gcc/timevar.def | 1 + gcc/tree-cfg.h | 2 + gcc/tree-pass.h | 1 + gcc/tree-ssa-ifcombine.cc | 6 +- 19 files changed, 981 insertions(+), 5 deletions(-) create mode 100644 gcc/gimple-if-split.cc create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-1.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-10.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-2.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-3.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-5.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-6.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-7.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-8.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/if-split-9.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index bb6197a8e..683b28896 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1393,6 +1393,7 @@ OBJS = \ gimple-builder.o \ gimple-expr.o \ gimple-if-to-switch.o \ + gimple-if-split.o \ gimple-iterator.o \ gimple-fold.o \ gimple-harden-conditionals.o \ diff --git a/gcc/common.opt b/gcc/common.opt index a45fbfe1b..a52fa9814 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1981,6 +1981,10 @@ finstrument-functions-exclude-file-list= Common RejectNegative Joined -finstrument-functions-exclude-file-list=filename,... Do not instrument functions listed in files. +fif-split +Common Var(flag_if_split) Init(0) Optimization +Perform splitting if complex conditions on separate ones with clonning their bodies (gimple version). + fipa-cp Common Var(flag_ipa_cp) Optimization Perform interprocedural constant propagation. diff --git a/gcc/gimple-if-split.cc b/gcc/gimple-if-split.cc new file mode 100644 index 000000000..3446204ea --- /dev/null +++ b/gcc/gimple-if-split.cc @@ -0,0 +1,567 @@ +/* If-split. + Copyright (C) 2024 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#define INCLUDE_FUNCTIONAL +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "tree-ssa.h" +#include "tree-pass.h" +#include "diagnostic-core.h" +#include "function.h" +#include "basic-block.h" +#include "gimple.h" +#include "gimple-pretty-print.h" +#include "gimple-iterator.h" +#include "cfg.h" +#include "cfghooks.h" +#include "ssa.h" +#include "fold-const.h" +#include "tree-into-ssa.h" +#include "tree-cfg.h" +#include "bitmap.h" +#include "cfganal.h" + +/* Perform splitting if-then-else patterns, whose complex OR condition in +cond-bb contains comparison of some variable with constant and then-bb got +function call, whose arg list contains this var (or this variable is a +scalar of an aggregate which is an arg of this call). We split condition on +two separate ones and duplicate then-bb for each one, thus help ipa const +prop to propagate corresponding constant in function calls. +Example: + Before: + if (n == const || some_cond) + func (n); + After: + if (n == const) + func (n); + else if (some_cond) + func (n); */ + +//------------------------------------------------------------------------- +// Auxiliary functions +//------------------------------------------------------------------------- +/* Check if arg list of call got n. */ +bool +got_in_args_p (gimple* call, tree n) +{ + unsigned num_args = gimple_call_num_args (call); + + for (int i = 0; i < num_args; i++) + { + if (n == gimple_call_arg (call, i)) + return true; + } + + return false; +} + +#define SCALAR_NESTING 2 +/* Check if call is "necessary" for n. Call is called "necessary" + * for n, if n is one of call args, or n is scalar of some aggregate, + * which is one of this call args. Nesting param determines how many + * levels of aggregate-scalar nesting we want to check. For example, + * if nesting == 2, we allow only 2 levels of nesting, like + * outer_aggr->inner_aggr->scalar. */ +static bool +necessary_call_p (gimple *call, tree n, unsigned nesting) +{ + if (!call) + return false; + + if (got_in_args_p (call, n)) + return true; + + /* Else we need to check if n could be a scalar of some aggregate which + * is one of call args. */ + tree scalar = n; + tree aggregate = NULL_TREE; + + for (int i = 0; i < nesting; i++) + { + if (!scalar || TREE_CODE (scalar) != SSA_NAME) + return false; + + gimple *scalar_def = SSA_NAME_DEF_STMT (scalar); + + if (!is_gimple_assign (scalar_def) + || gimple_assign_rhs_code (scalar_def) != COMPONENT_REF) + return false; + + tree scalar_def_rhs = gimple_assign_rhs1 (scalar_def); + tree aggregate = TREE_OPERAND (scalar_def_rhs, 0); + + if (TREE_CODE (aggregate) == MEM_REF) + aggregate = TREE_OPERAND (aggregate, 0); + + if (aggregate && got_in_args_p (call, aggregate)) + return true; + + scalar = aggregate; + } + + return false; +} + +/* Check if bb got a "necessary" call statement. */ +static bool +bb_got_necessary_call_p (basic_block bb, tree n, unsigned nesting) +{ + gimple *stmt = NULL; + + for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); + gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + + if (is_gimple_call (stmt) && necessary_call_p (stmt, n, nesting)) + return true; + } + + return false; +} + +//------------------------------------------------------------------------- +// Complex conditions +//------------------------------------------------------------------------- +/* Auxiliary struct which contains var and its constant of comaprison + * of expr: n == cst. */ +struct var_const +{ + tree n = NULL_TREE; + tree cst = NULL_TREE; +}; + +/* Check if var_def stmt got this pattern: + * var = (n == const); + * If it does, we need to set var_cst struct. */ +static bool +comp_with_const_p (gimple *var_def, var_const *var_cst) +{ + if (gimple_expr_code (var_def) != EQ_EXPR) + return false; + + tree var_def_rhs2 = gimple_assign_rhs2 (var_def); + + if (TREE_CODE (var_def_rhs2) != INTEGER_CST) + return false; + + var_cst->n = gimple_assign_rhs1 (var_def); + var_cst->cst = var_def_rhs2; + + return true; +} + +/* Auxiliary struct which contains defenition of each part of + * complex condition, like: + * a = ... <- a_def + * b = ... <- b_def + * c = a | b <- complex_cond. */ +struct cond_parts_defs +{ + gimple *a_def = NULL; + gimple *b_def = NULL; +}; + +/* Check if cond got this pattern: + * a = ...; <- a_def + * b = ...; <- b_def + * c = a | b; + * if (c != 0) + * and a_def or b_def is comparison with constant. If it does, + * we need to set a with a_def and b with b_def. */ +static bool +necessary_complex_cond_p (const gimple *cond, basic_block then_bb, + cond_parts_defs *defs) +{ + tree lhs = gimple_cond_lhs (cond); + tree rhs = gimple_cond_rhs (cond); + + /* As we look for: if (c != 0). */ + if (gimple_cond_code (cond) != NE_EXPR || TREE_CODE (lhs) != SSA_NAME + || !integer_zerop (rhs)) + return false; + + gimple *c_def = SSA_NAME_DEF_STMT (lhs); + + /* As we look for: c = a | b. */ + if (!c_def || !is_gimple_assign (c_def) || gimple_num_ops (c_def) != 3 + || gimple_expr_code (c_def) != BIT_IOR_EXPR) + return false; + + tree a_var = gimple_assign_rhs1 (c_def); + tree b_var = gimple_assign_rhs2 (c_def); + gimple *a_def = SSA_NAME_DEF_STMT (a_var); + gimple *b_def = SSA_NAME_DEF_STMT (b_var); + + if (!a_def || !is_gimple_assign (a_def) || !b_def + || !is_gimple_assign (b_def)) + return false; + + var_const var_cst; + + if (!(comp_with_const_p (a_def, &var_cst) + && bb_got_necessary_call_p (then_bb, var_cst.n, SCALAR_NESTING)) + && !(comp_with_const_p (b_def, &var_cst) + && bb_got_necessary_call_p (then_bb, var_cst.n, SCALAR_NESTING))) + return false; + + defs->a_def = a_def; + defs->b_def = b_def; + + return true; +} + +/* Check if our complex condition seems to be "necessary" + * and if it does split it on two separate ones. Like: + * a = (n == const); <- a_def + * b = smth; <- b_def + * c = a | b + * if (c != 0) + * call func (n, ...) + * Transform this to: + * if (n == const) + * goto then + * else if (b != 0) + * goto then + * then: + * call func (n, ...). + * A complex condition is called "necessary", if it is OR of two + * conditions, one of them is comparison with constant and then_bb + * of this cond got "necessary" function_call. To know, what + * "necessary" function call means look at necessary_call_p (). */ +static void +process_complex_cond (basic_block cond_bb, basic_block then_bb, + basic_block else_bb) +{ + gimple *cond = last_stmt (cond_bb); + cond_parts_defs defs; + + if (!can_duplicate_block_p (then_bb) + || !necessary_complex_cond_p (cond, then_bb, &defs)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "Recognized necessary complex condition: ", cond_bb->index); + print_gimple_stmt (dump_file, cond, 0, TDF_NONE); + } + + var_const var_cst; + + /* Setting cond. */ + if (comp_with_const_p (defs.a_def, &var_cst)) + /* Setting cond as: if (n == const). */ + gimple_cond_set_condition (as_a<gcond *> (cond), EQ_EXPR, var_cst.n, + var_cst.cst); + else + { + /* Setting cond as: if (a != 0). */ + tree cond_lhs = gimple_assign_lhs (defs.a_def); + gimple_cond_set_condition (as_a<gcond *> (cond), NE_EXPR, cond_lhs, + build_zero_cst (TREE_TYPE (cond_lhs))); + } + update_stmt (cond); + + /* Creating inner_cond_bb. */ + edge then_e = find_edge (cond_bb, then_bb); + edge else_e = find_edge (cond_bb, else_bb); + basic_block inner_cond_bb = split_edge (else_e); + + /* Setting inner_cond. */ + gcond *inner_cond = NULL; + if (comp_with_const_p (defs.b_def, &var_cst)) + { + /* Setting inner cond as: if (b == const). */ + inner_cond = gimple_build_cond (EQ_EXPR, var_cst.n, var_cst.cst, + NULL_TREE, NULL_TREE); + } + else + { + /* Setting inner cond as: if (b != 0). */ + tree inner_cond_lhs = gimple_assign_lhs (defs.b_def); + inner_cond = gimple_build_cond ( + NE_EXPR, inner_cond_lhs, build_zero_cst (TREE_TYPE (inner_cond_lhs)), + NULL_TREE, NULL_TREE); + } + gimple_stmt_iterator gsi = gsi_last_bb (inner_cond_bb); + gsi_insert_after (&gsi, inner_cond, GSI_NEW_STMT); + + /* Configuring edges. */ + edge inner_cond_then_e = make_edge (inner_cond_bb, then_bb, EDGE_TRUE_VALUE); + edge inner_cond_else_e = find_edge (inner_cond_bb, else_bb); + inner_cond_else_e->flags = EDGE_FALSE_VALUE; + + /* Setting phinode args in then_bb coming from inner_cond_bb the same as + * ones coming from cond_bb. */ + for (gphi_iterator psi = gsi_start_phis (then_bb); !gsi_end_p (psi); + gsi_next (&psi)) + { + gphi *phi = psi.phi (); + add_phi_arg (phi, PHI_ARG_DEF_FROM_EDGE (phi, then_e), inner_cond_then_e, + UNKNOWN_LOCATION); + } + + /* Updating dominators. */ + set_immediate_dominator (CDI_DOMINATORS, inner_cond_bb, cond_bb); + basic_block cond_bb_postdominator + = get_immediate_dominator (CDI_POST_DOMINATORS, cond_bb); + set_immediate_dominator (CDI_POST_DOMINATORS, inner_cond_bb, + cond_bb_postdominator); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Successfully transformed:\n (o_cond) ", + cond_bb->index); + print_gimple_stmt (dump_file, cond, 0, TDF_NONE); + fprintf (dump_file, " (i_cond) ", inner_cond_bb->index); + print_gimple_stmt (dump_file, inner_cond, 0, TDF_NONE); + } +} + +//------------------------------------------------------------------------- +// Condition pairs +//------------------------------------------------------------------------- +/* Transforming cfg if we recognized patern in process_condition_pair (). */ +static basic_block +make_two_separate_calls (basic_block outer_cond_bb, basic_block inner_cond_bb, + basic_block then_bb) +{ + if (!can_duplicate_block_p (then_bb) || EDGE_COUNT (then_bb->succs) != 1) + return NULL; + + edge outer_then_e = find_edge (outer_cond_bb, then_bb); + + /* Making duplication of then_bb. */ + basic_block then_bb_dom = get_immediate_dominator (CDI_DOMINATORS, then_bb); + basic_block merge_bb = split_edge (single_succ_edge (then_bb)); + basic_block then_bb1 = duplicate_block (then_bb, outer_then_e, outer_cond_bb); + edge outer_then1_e = find_edge (outer_cond_bb, then_bb1); + + /* Setting phinode args in then_bb1 coming from outer_cond_bb by previously + * collected args_from_outer_cond_bb. */ + flush_pending_stmts (outer_then1_e); + + /* Updating dominators. */ + if (then_bb_dom == outer_cond_bb) + set_immediate_dominator (CDI_DOMINATORS, then_bb, inner_cond_bb); + + set_immediate_dominator (CDI_DOMINATORS, merge_bb, then_bb_dom); + set_immediate_dominator (CDI_DOMINATORS, then_bb1, outer_cond_bb); + + set_immediate_dominator (CDI_POST_DOMINATORS, then_bb, merge_bb); + set_immediate_dominator (CDI_POST_DOMINATORS, then_bb1, merge_bb); + set_immediate_dominator (CDI_POST_DOMINATORS, merge_bb, + single_succ (merge_bb)); + + return then_bb1; +} + +/* Here we check if cond of bb got this pattern: + * if (n == const) + * And if it does we need to set n. */ +static bool +got_necessary_cond_p (basic_block bb, tree *n) +{ + gimple *stmt = last_stmt (bb); + if (!stmt || gimple_code (stmt) != GIMPLE_COND) + return false; + + gcond *cond = as_a<gcond *> (stmt); + + if (gimple_cond_code (cond) != EQ_EXPR + || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME + || TREE_CODE (gimple_cond_rhs (cond)) != INTEGER_CST) + return false; + + *n = gimple_cond_lhs (cond); + + return true; +} + +/* Recognize pattern: + * if (n == const) + * goto then + * else if (some_cond) + * goto then + * then: + * call func (n, ...) + * Transform this to: + * if (n == const) + * call func (n, ...) + * else if (some_cond) + * call func (n, ...). */ +static void +process_cond_pair (basic_block outer_cond_bb, basic_block inner_cond_bb, + basic_block then_bb) +{ + tree n = NULL_TREE; + + if (inner_cond_bb == then_bb + || !recognize_if_then_else (outer_cond_bb, &then_bb, &inner_cond_bb) + || !same_phi_args_p (outer_cond_bb, inner_cond_bb, then_bb) + || (!got_necessary_cond_p (outer_cond_bb, &n) + && !got_necessary_cond_p (inner_cond_bb, &n)) + || !bb_got_necessary_call_p (then_bb, n, SCALAR_NESTING)) + return; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Recognized necessary condition pair: (o_cond) "); + print_gimple_stmt (dump_file, last_stmt (outer_cond_bb), 0, TDF_NONE); + fprintf (dump_file, " (i_cond) "); + print_gimple_stmt (dump_file, last_stmt (inner_cond_bb), 0, TDF_NONE); + } + + basic_block then_bb1 + = make_two_separate_calls (outer_cond_bb, inner_cond_bb, then_bb); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + if (then_bb1) + fprintf (dump_file, + "Successfully transformed: bb<%d> is a copy of bb<%d> \n", + then_bb1->index, then_bb->index); + else + fprintf (dump_file, "No transformation: bb<%d> cannot be duplicated \n", + then_bb->index); + } +} + +//------------------------------------------------------------------------- +// Main logic +//------------------------------------------------------------------------- +/* If cond_bb suits if-then-else pattern and got single pred, execute func + * over it and its then, else basic blocks. */ +template <typename F> +static void +process_bb (basic_block cond_bb, F func) +{ + basic_block then_bb = NULL, else_bb = NULL; + + if (!recognize_if_then_else (cond_bb, &then_bb, &else_bb)) + return; + + func (cond_bb, then_bb, else_bb); +} + +/* For each block, if it has condition, execute function over it. We walk + * the blocks in order that guarantees that a block with a single predecessor + * is processed after the predecessor. */ +template <typename F> +static void +execute_function_over_conditional_bbs (F func) +{ + basic_block *bbs = single_pred_before_succ_order (); + for (int i = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS - 1; i >= 0; i--) + { + gimple *stmt = last_stmt (bbs[i]); + + if (stmt && gimple_code (stmt) == GIMPLE_COND) + { + process_bb (bbs[i], func); + } + } + update_ssa (TODO_update_ssa); + free (bbs); +} + +static void +process_if_split_cfun () +{ + /* First pass. Split complex conditions, so process_condition_pair_bb () + * will be able to recognize more necessary patterns. */ + execute_function_over_conditional_bbs (process_complex_cond); + + /* Second pass. Search each basic block for condition pair we may be + * able to optimize. */ + execute_function_over_conditional_bbs ( + [] (basic_block cond_bb, basic_block then_bb, basic_block else_bb) + { + if (!single_pred_p (cond_bb)) + return; + process_cond_pair (single_pred (cond_bb), cond_bb, then_bb); + }); +} + +namespace +{ + +const pass_data pass_data_if_split = { + GIMPLE_PASS, /* type. */ + "if-split", /* name. */ + OPTGROUP_NONE, /* optinfo_flags. */ + TV_TREE_IF_SPLIT, /* tv_id. */ + 0, /* properties_required. */ + 0, /* properties_provided. */ + 0, /* properties_destroyed. */ + 0, /* todo_flags_start. */ + 0 /* todo_flags_finish. */ +}; + +class pass_if_split : public gimple_opt_pass +{ +public: + pass_if_split (gcc::context *ctxt) + : gimple_opt_pass (pass_data_if_split, ctxt) + { + } + + /* opt_pass methods: */ + virtual bool + gate (function *) + { + /* Don't bother doing anything if the program has errors. */ + return (optimize >= 3 && flag_if_split && !seen_error ()); + } + + virtual unsigned int execute (function *); + +}; // class pass_if_split + +unsigned int +pass_if_split::execute (function *fun) +{ + calculate_dominance_info (CDI_DOMINATORS); + calculate_dominance_info (CDI_POST_DOMINATORS); + initialize_original_copy_tables (); + + process_if_split_cfun (); + + checking_verify_ssa (true, true); + checking_verify_flow_info (); + checking_verify_dominators (CDI_DOMINATORS); + checking_verify_dominators (CDI_POST_DOMINATORS); + + free_original_copy_tables (); + free_dominance_info (CDI_POST_DOMINATORS); + free_dominance_info (CDI_DOMINATORS); + + return 0; +} + +} // anon namespace + +gimple_opt_pass * +make_pass_if_split (gcc::context *ctxt) +{ + return new pass_if_split (ctxt); +} \ No newline at end of file diff --git a/gcc/opts.cc b/gcc/opts.cc index 84dd8925a..4f3eb4bd4 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -3145,7 +3145,7 @@ common_handle_option (struct gcc_options *opts, SET_OPTION_IF_UNSET (opts, opts_set, flag_cfgo_profile_generate, value); } - /* No break here - do -fcfgo-profile-generate processing. */ + /* No break here - do -fprofile-generate processing. */ /* FALLTHRU */ case OPT_fprofile_generate_: opts->x_profile_data_prefix = xstrdup (arg); diff --git a/gcc/passes.def b/gcc/passes.def index 862ef0d8f..fbe828439 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -100,6 +100,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_if_to_switch); NEXT_PASS (pass_convert_switch); NEXT_PASS (pass_cleanup_eh); + NEXT_PASS (pass_if_split); NEXT_PASS (pass_profile); NEXT_PASS (pass_local_pure_const); NEXT_PASS (pass_modref); diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-1.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-1.c new file mode 100644 index 000000000..5909dac41 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-1.c @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + int b = argc; + int res = 0; + + if (b == 5 || b == 52) + res = foo (b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-10.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-10.c new file mode 100644 index 000000000..20a45116b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-10.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int foo2 (); + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + int foo2_res = foo2(); + + if (data.y.b == 5 || data.y.b == 52 || foo2_res == 25) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 2 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-2.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-2.c new file mode 100644 index 000000000..1370f9474 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-2.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct X +{ + int a; +} X; + + +void __attribute__ ((noinline)) set_a (X* x, int val) +{ + x->a = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + X data; + set_a (&data, argc); + int res = 0; + + if (data.a == 5 || data.a == 52) + res = foo (data.a); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-3.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-3.c new file mode 100644 index 000000000..93a6eb6dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-3.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct X +{ + int a; +} X; + + +void __attribute__ ((noinline)) set_a (X* x, int val) +{ + x->a = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + X data; + set_a (&data, argc); + int res = 0; + + if (data.a == 5 || data.a == 52 || data.a == 25) + res = foo (data.a); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 2 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-4.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-4.c new file mode 100644 index 000000000..36f2a15b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-4.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + + if (data.y.b == 5 || data.y.b == 52) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-5.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-5.c new file mode 100644 index 000000000..fbc3b0c19 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-5.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + + if (data.y.b == 5 || data.y.b == 52 || data.y.b == 25) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 2 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-6.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-6.c new file mode 100644 index 000000000..185127c79 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-6.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int foo2 (); + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + int foo2_res = foo2(); + + if (data.y.b == 5 || foo2_res == 52) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-7.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-7.c new file mode 100644 index 000000000..23f1a8f04 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-7.c @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int foo2 (); + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + + if (data.y.b == 5 || foo2() == 52) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary complex condition:" 0 "if-split" } } */ +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 0 "if-split" } } */ +/* { dg-final { scan-tree-dump-times "Successfully transformed:" 0 "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-8.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-8.c new file mode 100644 index 000000000..028b6dc40 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-8.c @@ -0,0 +1,42 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + + if (data.y.b == 5 || data.a == 52) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/tree-ssa/if-split-9.c b/gcc/testsuite/gcc.dg/tree-ssa/if-split-9.c new file mode 100644 index 000000000..3ff7e2efc --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/if-split-9.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ +/* { dg-options "-O3 -fif-split -fdump-tree-if-split-details" } */ + +typedef struct Y +{ + int b; +} Y; + +typedef struct X +{ + Y y; + int a; +} X; + + +void __attribute__ ((noinline)) set_b (Y* y, int val) +{ + y->b = val; +} + +static __attribute__ ((noinline)) int foo (int b) +{ + int res = 1; + for (int i = 0; i < b; i++) { + res*=3; + } + return res; +} + +int foo2 (); + +int main(int argc, char** argv){ + X data; + set_b (&data.y, argc); + int res = 0; + + if (data.y.b == 5 || data.y.b == 52 || foo2() == 25) + res = foo (data.y.b); + + return res; +} + +/* { dg-final { scan-tree-dump-times "Recognized necessary condition pair:" 1 "if-split" } } */ +/* { dg-final { scan-tree-dump "Successfully transformed:" "if-split" } } */ \ No newline at end of file diff --git a/gcc/timevar.def b/gcc/timevar.def index 6fdb2c767..b0d3d1188 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -306,6 +306,7 @@ DEFTIMEVAR (TV_VAR_TRACKING_DATAFLOW , "var-tracking dataflow") DEFTIMEVAR (TV_VAR_TRACKING_EMIT , "var-tracking emit") DEFTIMEVAR (TV_TREE_IFCOMBINE , "tree if-combine") DEFTIMEVAR (TV_TREE_IF_TO_SWITCH , "if to switch conversion") +DEFTIMEVAR (TV_TREE_IF_SPLIT , "gimple if splitting") DEFTIMEVAR (TV_TREE_UNINIT , "uninit var analysis") DEFTIMEVAR (TV_PLUGIN_INIT , "plugin initialization") DEFTIMEVAR (TV_PLUGIN_RUN , "plugin execution") diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index cb67cdf87..bfe44c073 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -112,6 +112,8 @@ extern basic_block gimple_switch_default_bb (function *, gswitch *); extern edge gimple_switch_edge (function *, gswitch *, unsigned); extern edge gimple_switch_default_edge (function *, gswitch *); extern bool cond_only_block_p (basic_block); +extern bool recognize_if_then_else (basic_block, basic_block *, basic_block *); +extern bool same_phi_args_p (basic_block, basic_block, basic_block); /* Return true if the LHS of a call should be removed. */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index f9c2eed8b..fb17b189c 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -383,6 +383,7 @@ extern gimple_opt_pass *make_pass_graphite (gcc::context *ctxt); extern gimple_opt_pass *make_pass_graphite_transforms (gcc::context *ctxt); extern gimple_opt_pass *make_pass_if_conversion (gcc::context *ctxt); extern gimple_opt_pass *make_pass_if_to_switch (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_if_split (gcc::context *ctxt); extern gimple_opt_pass *make_pass_loop_distribution (gcc::context *ctxt); extern gimple_opt_pass *make_pass_vectorize (gcc::context *ctxt); extern gimple_opt_pass *make_pass_simduid_cleanup (gcc::context *ctxt); diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index 264a8bcae..3b50fc114 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -76,8 +76,7 @@ along with GCC; see the file COPYING3. If not see match the then and else basic-blocks to make the pattern match. Returns true if the pattern matched, false otherwise. */ -static bool -recognize_if_then_else (basic_block cond_bb, +bool recognize_if_then_else (basic_block cond_bb, basic_block *then_bb, basic_block *else_bb) { edge t, e; @@ -168,8 +167,7 @@ forwarder_block_to (basic_block bb, basic_block to_bb) BB2 to DEST are the same. This makes the CFG merge point free from side-effects. Return true in this case, else false. */ -static bool -same_phi_args_p (basic_block bb1, basic_block bb2, basic_block dest) +bool same_phi_args_p (basic_block bb1, basic_block bb2, basic_block dest) { edge e1 = find_edge (bb1, dest); edge e2 = find_edge (bb2, dest); -- 2.25.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2