diff --git a/gcc/postreload.cc b/gcc/postreload.cc index 05c2e0e2644528c6e4fae83aeebf7cc72e8a87fb..487aa8aad054eb6fe5e7f2e6d65439c1359b2323 100644 --- a/gcc/postreload.cc +++ b/gcc/postreload.cc @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "emit-rtl.h" #include "recog.h" +#include "cfghooks.h" #include "cfgrtl.h" #include "cfgbuild.h" #include "cfgcleanup.h" @@ -221,13 +222,107 @@ reload_cse_regs_1 (void) init_alias_analysis (); FOR_EACH_BB_FN (bb, cfun) - FOR_BB_INSNS (bb, insn) - { - if (INSN_P (insn)) - cfg_changed |= reload_cse_simplify (insn, testreg); + { + /* If BB has a small number of predecessors, see if each of the + has the same implicit set. If so, record that implicit set so + that we can add it to the cselib tables. */ + rtx_insn *implicit_set; - cselib_process_insn (insn); - } + implicit_set = NULL; + if (EDGE_COUNT (bb->preds) <= 3) + { + edge e; + edge_iterator ei; + rtx src = NULL_RTX; + rtx dest = NULL_RTX; + + /* Iterate over each incoming edge and see if they + all have the same implicit set. */ + FOR_EACH_EDGE (e, ei, bb->preds) + { + /* Skip the entry/exit block. */ + if (e->src == ENTRY_BLOCK_PTR_FOR_FN (cfun)) + break; + + /* Verify this block ends with a suitable condjump */ + rtx_insn *condjump = BB_END (e->src); + if (!condjump || ! any_condjump_p (condjump)) + break; + + /* This predecessor ends with a possible equivalence + producing conditional branch. Extract the condition + and try to use it to create an equivalence. */ + rtx pat = pc_set (condjump); + rtx i_t_e = SET_SRC (pat); + gcc_assert (GET_CODE (i_t_e) == IF_THEN_ELSE); + rtx cond = XEXP (i_t_e, 0); + + if ((((e->flags & EDGE_FALLTHRU) != 0) + == (XEXP (i_t_e, 1) == pc_rtx)) + ? GET_CODE (cond) == EQ + : GET_CODE (cond) == NE) + { + /* If this is the first time through record + the source and destination. */ + if (!dest) + { + dest = XEXP (cond, 0); + src = XEXP (cond, 1); + } + /* If this is not the first time through, then + verify the source and destination match. */ + else if (rtx_equal_p (dest, XEXP (cond, 0)) + && rtx_equal_p (src, XEXP (cond, 1))) + ; + else + break; + + /* A few more checks. First make sure we're dealing with + integer modes, second make sure the values aren't clobbered + by the conditional branch itself. Do this for every + conditional jump participating in creation of the + equivalence. */ + if (!REG_P (dest) + || !(REG_P (src) || CONST_INT_P (src)) + || GET_MODE_CLASS (GET_MODE (dest)) != MODE_INT + || reg_set_p (dest, condjump) + || reg_set_p (src, condjump)) + break; + + } + else + break; + } + + /* If all the incoming edges had the same implicit + set, then create a dummy insn for that set. + + It will be entered into the cselib tables before + we process the first real insn in this block. */ + if (dest && ei_end_p (ei)) + implicit_set = make_insn_raw (gen_rtx_SET (dest, src)); + } + + FOR_BB_INSNS (bb, insn) + { + if (INSN_P (insn)) + { + /* If we recorded an implicit set, enter it + into the tables before the first real insn. + + We have to do it this way because a CODE_LABEL + will flush the cselib tables. */ + if (implicit_set) + { + cselib_process_insn (implicit_set); + implicit_set = NULL; + } + cfg_changed |= reload_cse_simplify (insn, testreg); + } + + cselib_process_insn (insn); + } + } /* Clean up. */ end_alias_analysis (); diff --git a/gcc/testsuite/gcc.target/riscv/pr107455-1.c b/gcc/testsuite/gcc.target/riscv/pr107455-1.c new file mode 100644 index 0000000000000000000000000000000000000000..59616b89176008bef6297e4dd57bde60340e88e9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr107455-1.c @@ -0,0 +1,46 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-dp" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-O2" "-O3" "-Og" } } */ + + +typedef struct dllist +{ + int i; + struct dllist *ptr_to_next; + struct dllist *ptr_to_previous; +} dllist; + +int sglib_dllist_len(dllist *list) { + int res; + dllist *_dl_; + int _r1_, _r2_; + if (list== ((void *)0)) { + res = 0; + } else { + dllist *_ce_; + dllist *_ne_; + _r1_ = 0; + _ce_ = list; + while (_ce_!= ((void *)0)) { + _ne_ = _ce_->ptr_to_previous; + _r1_++; + _ce_ = _ne_; + } + _dl_ = list->ptr_to_next; + _r2_ = 0; + _ce_ = _dl_; + while (_ce_!= (void *)0) { + _ne_ = _ce_->ptr_to_next; + _r2_++; + _ce_ = _ne_; + } + res = _r1_ + _r2_; + } + return res; +} + + +/* There was an unnecessary assignment to the return value until + recently. Scan for that in the resulting output. */ +/* { dg-final { scan-assembler-times "li\\ta0,0" 1 } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/pr107455-2.c b/gcc/testsuite/gcc.target/riscv/pr107455-2.c new file mode 100644 index 0000000000000000000000000000000000000000..91106bb5d805f3aa3891794b0618f2623f5c3a21 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr107455-2.c @@ -0,0 +1,40 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -dp" } */ +/* This was extracted from coremark. */ + + +typedef signed short ee_s16; +typedef struct list_data_s +{ + ee_s16 data16; + ee_s16 idx; +} list_data; + +typedef struct list_head_s +{ + struct list_head_s *next; + struct list_data_s *info; +} list_head; + + +list_head * +core_list_find(list_head *list, list_data *info) +{ + if (info->idx >= 0) + { + while (list && (list->info->idx != info->idx)) + list = list->next; + return list; + } + else + { + while (list && ((list->info->data16 & 0xff) != info->data16)) + list = list->next; + return list; + } +} + +/* There was an unnecessary assignment to the return value until + recently. Scan for that in the resulting output. */ +/* { dg-final { scan-assembler-not "li\\ta0,0" } } */ +