Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/gcc/common.opt b/gcc/common.opt
- index 94d1d88..3913bc1 100644
- --- a/gcc/common.opt
- +++ b/gcc/common.opt
- @@ -1300,6 +1300,10 @@ ffunction-sections
- Common Report Var(flag_function_sections)
- Place each function into its own section
- +fremove-temps
- +Common Report Var(flag_rtl_remove_temps) Optimization
- +Undo CSE of test conditions made by rtl pre.
- +
- fgcse
- Common Report Var(flag_gcse) Optimization
- Perform global common subexpression elimination
- diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
- index fa4e083..d36d017 100644
- --- a/gcc/config/arm/arm.c
- +++ b/gcc/config/arm/arm.c
- @@ -73,6 +73,9 @@
- #include "builtins.h"
- #include "tm-constrs.h"
- #include "rtl-iter.h"
- +#include "tree-pass.h"
- +#include "context.h"
- +#include <set>
- /* This file should be included last. */
- #include "target-def.h"
- @@ -3397,6 +3400,22 @@ arm_option_override (void)
- /* Init initial mode for testing. */
- thumb_flipper = TARGET_THUMB;
- +
- + /* Registering the pass must be done at start up. It's
- + convenient to do it here. */
- +
- + rtl_opt_pass *make_pass_rtl_remove_temps (gcc::context *);
- +
- + opt_pass *new_pass = make_pass_rtl_remove_temps (g);
- + struct register_pass_info insert_pass_rtl_remove_temps =
- + {
- + new_pass, /* pass */
- + "combine", /* reference_pass_name */
- + 1, /* ref_pass_instance_number */
- + PASS_POS_INSERT_BEFORE /* po_op */
- + };
- + pass_init_dump_file (new_pass);
- + register_pass (&insert_pass_rtl_remove_temps);
- }
- static void
- @@ -29781,4 +29800,219 @@ arm_sched_fusion_priority (rtx_insn *insn, int max_pri,
- *pri = tmp;
- return;
- }
- +
- +/* Pass: pass_rtl_remove_temps
- +The patch look for rtx containing
- +(set (reg:CC )
- + (compare:CC (reg:SI <num>) (const_int 0)))
- +
- +and then looks for insn that sets reg:SI <num> and creates a copy of
- +that rtx insn.
- +
- +Suppose the definition of reg:SI<num> is follows:
- +(set (reg:SI <num>)
- + (and:SI (reg:SI ) (const_int <val>)))
- +
- +The above insn is replicated:
- +(set (reg:SI <num2>)
- + (and:SI (reg:SI ) (const_int <val>))) { *arm_andsi3_insn }
- +
- +and then it's value used in compare-against-0 insn
- +(set (reg:CC)
- + (compare:CC (reg:SI <num2>) (const_int 0))) { *arm_cmpsi_insn }
- +
- +The rationale for this change is that combine pass combines adjacent
- +arm_andsi3_insn, arm_cmpsi_insn into zeroextractsi_compare0_scratch,
- +which results in tst instruction.
- +The new insn is introduced only if reg:SI<num> is used in multiple
- +compare-against-0 insns (seen_regs is used for this purpose)
- +*/
- +
- +std::set<int> seen_regs;
- +
- +/* Find insn that defines reg. rtx_insn *insn uses the reg */
- +static rtx_insn *
- +get_def_insn (rtx_insn *insn, rtx reg)
- +{
- + df_ref use;
- + struct df_link *ref_chain, *ref_link;
- +
- + use = df_find_use (insn, reg);
- + gcc_assert (use != NULL);
- + ref_chain = DF_REF_CHAIN (use);
- +
- + // ??? Punt if a use has multiple defs
- + if (ref_chain->next)
- + return NULL;
- +
- + if (ref_chain->ref == NULL || DF_REF_INSN_INFO (ref_chain->ref) == NULL)
- + return NULL;
- +
- + return DF_REF_INSN (ref_chain->ref);
- +}
- +
- +/* See if expr is of the form
- + (and:SI (reg:SI <num> ) {(const_int <val>), (reg:SI <num>)}) */
- +
- +static bool
- +def_candidate_p (rtx expr)
- +{
- + if (GET_CODE (expr) != AND)
- + return false;
- +
- + if (GET_MODE (expr) != SImode)
- + return false;
- +
- + rtx op0 = XEXP (expr, 0);
- + rtx op1 = XEXP (expr, 1);
- +
- + if (!REG_P (op0) || GET_MODE (op0) != SImode)
- + return false;
- +
- + if ((REG_P (op1) && GET_MODE (op1) != SImode)
- + || GET_CODE (op1) != CONST_INT)
- + return false;
- +
- + return true;
- +}
- +
- +/* Performs the transform described above */
- +
- +static void
- +do_remove_temp (rtx_insn *insn)
- +{
- + rtx exp = PATTERN (insn);
- +
- + if (GET_CODE (exp) != SET)
- + return;
- + exp = XEXP (exp, 1);
- + if (GET_CODE (exp) != COMPARE)
- + return;
- + if (GET_MODE (exp) != CCmode)
- + return;
- +
- + rtx compare_expr = exp;
- + rtx op0 = XEXP (exp, 0);
- + if (!REG_P (op0))
- + return;
- +
- + if (GET_MODE (op0) != SImode)
- + return;
- +
- + rtx op1 = XEXP (exp, 1);
- + if (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0)
- + return;
- +
- + rtx_insn *def_insn = get_def_insn (insn, op0);
- + if (def_insn == NULL)
- + return;
- +
- + rtx pat = PATTERN (def_insn);
- + if (!def_candidate_p (XEXP (pat, 1)))
- + return;
- +
- + rtx result_reg = XEXP (pat, 0);
- + if (!REG_P (result_reg) || GET_MODE (result_reg) != SImode)
- + return;
- +
- + gcc_assert (REG_P (result_reg));
- + std::pair< std::set<int>::iterator, bool > ret = seen_regs.insert (REGNO (result_reg));
- + if (ret.second == true)
- + return;
- +
- + rtx reg = gen_reg_rtx (SImode);
- + rtx newpat = gen_rtx_SET (reg, copy_rtx (SET_SRC (pat)));
- + rtx_insn *x = emit_insn_before (newpat, insn);
- + XEXP (compare_expr, 0) = reg;
- + df_insn_rescan (insn);
- + recog_memoized (x);
- +}
- +
- +static void
- +rtl_remove_temps_init()
- +{
- + df_set_flags (DF_RD_PRUNE_DEAD_DEFS);
- + df_chain_add_problem (DF_UD_CHAIN);
- + df_analyze ();
- + df_set_flags (DF_DEFER_INSN_RESCAN);
- +}
- +
- +static unsigned int
- +execute_rtl_remove_temps (void)
- +{
- + rtx_insn *insn, *last, *first;
- +
- + for (insn = first = get_insns (), last = get_last_insn (); insn != last; insn = NEXT_INSN (insn))
- + {
- + if (!INSN_P (insn))
- + continue;
- +
- + rtx pat = PATTERN (insn);
- + /* ??? set and use of same register cannot happen in PARALLEL */
- + if (GET_CODE (pat) == PARALLEL)
- + continue;
- + else if (GET_CODE (pat) == SEQUENCE)
- + {
- + push_topmost_sequence ();
- + execute_rtl_remove_temps ();
- + pop_topmost_sequence ();
- + }
- + else
- + do_remove_temp (insn);
- + }
- +
- + return 0;
- +}
- +
- +namespace {
- +
- +const pass_data pass_data_rtl_remove_temps =
- +{
- + RTL_PASS, /* type */
- + "remove-temps", /* name */
- + OPTGROUP_NONE, /* optinfo_flags */
- + TV_NONE,
- + PROP_cfglayout, /* properties_required */
- + 0, /* properties_provided */
- + 0, /* properties_destroyed */
- + 0, /* todo_flags_start */
- + TODO_df_finish, /* todo_flags_finish */
- +};
- +
- +class pass_rtl_remove_temps : public rtl_opt_pass
- +{
- +public:
- + pass_rtl_remove_temps (gcc::context *ctxt)
- + : rtl_opt_pass (pass_data_rtl_remove_temps, ctxt)
- + {}
- +
- + /* opt_pass methods: */
- + virtual bool gate (function *);
- + virtual unsigned int execute (function *);
- +
- +}; // class pass_rtl_remove_temps
- +
- +bool
- +pass_rtl_remove_temps::gate (function *)
- +{
- + return flag_rtl_remove_temps != 0 && optimize > 0;
- +}
- +
- +} // anon namespace
- +
- +unsigned int
- +pass_rtl_remove_temps::execute (function *)
- +{
- + rtl_remove_temps_init ();
- + unsigned ret = execute_rtl_remove_temps ();
- + df_process_deferred_rescans ();
- + return ret;
- +}
- +
- +rtl_opt_pass *
- +make_pass_rtl_remove_temps (gcc::context *ctxt)
- +{
- + return new pass_rtl_remove_temps (ctxt);
- +}
- +
- #include "gt-arm.h"
Advertisement
Add Comment
Please, Sign In to add comment