From 2293974419a6541fb6425249f1340e96a3fb0766 Mon Sep 17 00:00:00 2001 From: Bernd Schmidt Date: Wed, 29 Sep 2010 20:06:55 +0000 Subject: [PATCH] re PR target/40457 (use stm and ldm to access consecutive memory words) PR target/40457 * postreload.c (move2add_use_add2_insn): Use full_costs for comparison. (move2add_use_add3_insn): Likewise. (reload_cse_move2add): Likewise. * rtlanal.c (get_full_rtx_cost): New function. * rtl.h (struct full_rtx_costs): New. (init_costs_to_max, init_costs_to_zero, costs_lt_p, costs_add_n_insns): New inline functions. (get_full_rtx_cost): Declare. testsuite/ PR target/40457 * gcc.target/arm/pr40457-3.c: New test. From-SVN: r164732 --- gcc/ChangeLog | 13 +++ gcc/postreload.c | 116 ++++++++++++++--------- gcc/rtl.h | 48 ++++++++++ gcc/rtlanal.c | 11 +++ gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.target/arm/pr40457-3.c | 10 ++ 6 files changed, 157 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/pr40457-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a0da8d874d0..0c3f9ce9ff7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2010-09-29 Bernd Schmidt + + PR target/40457 + * postreload.c (move2add_use_add2_insn): Use full_costs for + comparison. + (move2add_use_add3_insn): Likewise. + (reload_cse_move2add): Likewise. + * rtlanal.c (get_full_rtx_cost): New function. + * rtl.h (struct full_rtx_costs): New. + (init_costs_to_max, init_costs_to_zero, costs_lt_p, + costs_add_n_insns): New inline functions. + (get_full_rtx_cost): Declare. + 2010-09-29 Kai Tietz * config/i386/mingw32.h (TARGET_64BIT): replaced by diff --git a/gcc/postreload.c b/gcc/postreload.c index 0a70b2031a5..1fc9bfc50f6 100644 --- a/gcc/postreload.c +++ b/gcc/postreload.c @@ -1645,39 +1645,45 @@ move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn) if (INTVAL (off) == reg_offset [regno]) changed = validate_change (insn, &SET_SRC (pat), reg, 0); } - else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed) - && have_add2_insn (reg, new_src)) + else { + struct full_rtx_costs oldcst, newcst; rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src); - changed = validate_change (insn, &SET_SRC (pat), tem, 0); - } - else if (sym == NULL_RTX && GET_MODE (reg) != BImode) - { - enum machine_mode narrow_mode; - for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); - narrow_mode != VOIDmode - && narrow_mode != GET_MODE (reg); - narrow_mode = GET_MODE_WIDER_MODE (narrow_mode)) + + get_full_rtx_cost (pat, SET, &oldcst); + SET_SRC (pat) = tem; + get_full_rtx_cost (pat, SET, &newcst); + SET_SRC (pat) = src; + + if (costs_lt_p (&newcst, &oldcst, speed) + && have_add2_insn (reg, new_src)) + changed = validate_change (insn, &SET_SRC (pat), tem, 0); + else if (sym == NULL_RTX && GET_MODE (reg) != BImode) { - if (have_insn_for (STRICT_LOW_PART, narrow_mode) - && ((reg_offset[regno] - & ~GET_MODE_MASK (narrow_mode)) - == (INTVAL (off) - & ~GET_MODE_MASK (narrow_mode)))) + enum machine_mode narrow_mode; + for (narrow_mode = GET_CLASS_NARROWEST_MODE (MODE_INT); + narrow_mode != VOIDmode + && narrow_mode != GET_MODE (reg); + narrow_mode = GET_MODE_WIDER_MODE (narrow_mode)) { - rtx narrow_reg = gen_rtx_REG (narrow_mode, - REGNO (reg)); - rtx narrow_src = gen_int_mode (INTVAL (off), - narrow_mode); - rtx new_set = - gen_rtx_SET (VOIDmode, - gen_rtx_STRICT_LOW_PART (VOIDmode, - narrow_reg), - narrow_src); - changed = validate_change (insn, &PATTERN (insn), - new_set, 0); - if (changed) - break; + if (have_insn_for (STRICT_LOW_PART, narrow_mode) + && ((reg_offset[regno] & ~GET_MODE_MASK (narrow_mode)) + == (INTVAL (off) & ~GET_MODE_MASK (narrow_mode)))) + { + rtx narrow_reg = gen_rtx_REG (narrow_mode, + REGNO (reg)); + rtx narrow_src = gen_int_mode (INTVAL (off), + narrow_mode); + rtx new_set + = gen_rtx_SET (VOIDmode, + gen_rtx_STRICT_LOW_PART (VOIDmode, + narrow_reg), + narrow_src); + changed = validate_change (insn, &PATTERN (insn), + new_set, 0); + if (changed) + break; + } } } } @@ -1705,11 +1711,18 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) rtx pat = PATTERN (insn); rtx src = SET_SRC (pat); int regno = REGNO (reg); - int min_cost = INT_MAX; int min_regno = 0; bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)); int i; bool changed = false; + struct full_rtx_costs oldcst, newcst, mincst; + rtx plus_expr; + + init_costs_to_max (&mincst); + get_full_rtx_cost (pat, SET, &oldcst); + + plus_expr = gen_rtx_PLUS (GET_MODE (reg), reg, const0_rtx); + SET_SRC (pat) = plus_expr; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (reg_set_luid[i] > move2add_last_label_luid @@ -1728,22 +1741,25 @@ move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn) no-op moves. */ if (new_src == const0_rtx) { - min_cost = 0; + init_costs_to_zero (&mincst); min_regno = i; break; } else { - int cost = rtx_cost (new_src, PLUS, speed); - if (cost < min_cost) + XEXP (plus_expr, 1) = new_src; + get_full_rtx_cost (pat, SET, &newcst); + + if (costs_lt_p (&newcst, &mincst, speed)) { - min_cost = cost; + mincst = newcst; min_regno = i; } } } + SET_SRC (pat) = src; - if (min_cost < rtx_cost (src, SET, speed)) + if (costs_lt_p (&mincst, &oldcst, speed)) { rtx tem; @@ -1879,18 +1895,26 @@ reload_cse_move2add (rtx first) /* See above why we create (set (reg) (reg)) here. */ success = validate_change (next, &SET_SRC (set), reg, 0); - else if ((rtx_cost (new_src, PLUS, speed) - < COSTS_N_INSNS (1) + rtx_cost (src3, SET, speed)) - && have_add2_insn (reg, new_src)) + else { - rtx newpat = gen_rtx_SET (VOIDmode, - reg, - gen_rtx_PLUS (GET_MODE (reg), - reg, - new_src)); - success - = validate_change (next, &PATTERN (next), - newpat, 0); + rtx old_src = SET_SRC (set); + struct full_rtx_costs oldcst, newcst; + rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src); + + get_full_rtx_cost (set, SET, &oldcst); + SET_SRC (set) = tem; + get_full_rtx_cost (tem, SET, &newcst); + SET_SRC (set) = old_src; + costs_add_n_insns (&oldcst, 1); + + if (costs_lt_p (&newcst, &oldcst, speed) + && have_add2_insn (reg, new_src)) + { + rtx newpat = gen_rtx_SET (VOIDmode, reg, tem); + success + = validate_change (next, &PATTERN (next), + newpat, 0); + } } if (success) delete_insn (insn); diff --git a/gcc/rtl.h b/gcc/rtl.h index 3aba4735642..1f13f2a84eb 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1123,9 +1123,57 @@ rhs_regno (const_rtx x) not to use an rtx with this cost under any circumstances. */ #define MAX_COST INT_MAX +/* A structure to hold all available cost information about an rtl + expression. */ +struct full_rtx_costs +{ + int speed; + int size; +}; + +/* Initialize a full_rtx_costs structure C to the maximum cost. */ +static inline void +init_costs_to_max (struct full_rtx_costs *c) +{ + c->speed = MAX_COST; + c->size = MAX_COST; +} + +/* Initialize a full_rtx_costs structure C to zero cost. */ +static inline void +init_costs_to_zero (struct full_rtx_costs *c) +{ + c->speed = 0; + c->size = 0; +} + +/* Compare two full_rtx_costs structures A and B, returning true + if A < B when optimizing for speed. */ +static inline bool +costs_lt_p (struct full_rtx_costs *a, struct full_rtx_costs *b, + bool speed) +{ + if (speed) + return (a->speed < b->speed + || (a->speed == b->speed && a->size < b->size)); + else + return (a->size < b->size + || (a->size == b->size && a->speed < b->speed)); +} + +/* Increase both members of the full_rtx_costs structure C by the + cost of N insns. */ +static inline void +costs_add_n_insns (struct full_rtx_costs *c, int n) +{ + c->speed += COSTS_N_INSNS (n); + c->size += COSTS_N_INSNS (n); +} + extern void init_rtlanal (void); extern int rtx_cost (rtx, enum rtx_code, bool); extern int address_cost (rtx, enum machine_mode, addr_space_t, bool); +extern void get_full_rtx_cost (rtx, enum rtx_code, struct full_rtx_costs *); extern unsigned int subreg_lsb (const_rtx); extern unsigned int subreg_lsb_1 (enum machine_mode, enum machine_mode, unsigned int); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index d34dc806009..930828ac2eb 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3589,6 +3589,17 @@ rtx_cost (rtx x, enum rtx_code outer_code ATTRIBUTE_UNUSED, bool speed) return total; } + +/* Fill in the structure C with information about both speed and size rtx + costs for X, with outer code OUTER. */ + +void +get_full_rtx_cost (rtx x, enum rtx_code outer, struct full_rtx_costs *c) +{ + c->speed = rtx_cost (x, outer, true); + c->size = rtx_cost (x, outer, false); +} + /* Return cost of address expression X. Expect that X is properly formed address reference. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 76ae3a1eff3..2a5b94f6903 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-09-29 Bernd Schmidt + + PR target/40457 + * gcc.target/arm/pr40457-3.c: New test. + 2010-09-29 Nathan Sidwell * lib/target-supports-dg.exp (dg-require-ifunc): Remove extraneous diff --git a/gcc/testsuite/gcc.target/arm/pr40457-3.c b/gcc/testsuite/gcc.target/arm/pr40457-3.c new file mode 100644 index 00000000000..9bd5a17befe --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/pr40457-3.c @@ -0,0 +1,10 @@ +/* { dg-options "-Os" } */ +/* { dg-do compile } */ + +void foo(int* p) +{ + p[0] = 1; + p[1] = 0; +} + +/* { dg-final { scan-assembler "stm" } } */ -- 2.30.2