The commit 2c0fa3ecf70d199af18785702e9e0548fd3ab793 reuses VALUEs on sp adjustments. We can generalize the idea and reuse VALUEs on other registers. This can help the postreload pass find more opportunities to simplify insns.
The following assembly code is generated from the testcase using the current trunk compiler: .L5: movq %rbp, %rsi movq %rbx, %rdi call l movq %rbx, %rsi addq $4, %rbx testl %eax, %eax je .L6 leaq -4(%rbx), %rax cmpq %rax, %rbp je .L6 movq %rbx, %rdi call as The lea instruction is actually redundant here, as rsi contains the same value as rbx-4 and can be used in the cmp instruction instead of rax. With this patch, the lea instruction can be eliminated in the postreload pass. Bootstrapped and regtested on x86_64-pc-linux-gnu, no regressions. --- gcc/cselib.cc | 29 ++++++++++++++---------- gcc/rtl.h | 1 + gcc/testsuite/gcc.target/i386/cselib-1.c | 22 ++++++++++++++++++ 3 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/cselib-1.c diff --git a/gcc/cselib.cc b/gcc/cselib.cc index e6a36e892bb..43ab266c4de 100644 --- a/gcc/cselib.cc +++ b/gcc/cselib.cc @@ -70,6 +70,9 @@ static rtx autoinc_split (rtx, rtx *, machine_mode); #define SP_DERIVED_VALUE_P(RTX) \ (RTL_FLAG_CHECK1 ("SP_DERIVED_VALUE_P", (RTX), VALUE)->call) +#define REG_DERIVED_VALUE_P(RTX) \ + (RTL_FLAG_CHECK1 ("REG_DERIVED_VALUE_P", (RTX), VALUE)->volatil) + struct expand_value_data { bitmap regs_active; @@ -137,7 +140,7 @@ cselib_hasher::equal (const cselib_val *v, const key *x_arg) if (GET_CODE (x) == VALUE) return x == v->val_rtx; - if (SP_DERIVED_VALUE_P (v->val_rtx) && GET_MODE (x) == Pmode) + if (REG_DERIVED_VALUE_P (v->val_rtx) && GET_MODE (x) == Pmode) { rtx xoff = NULL; if (autoinc_split (x, &xoff, memmode) == v->val_rtx && xoff == NULL_RTX) @@ -905,7 +908,7 @@ autoinc_split (rtx x, rtx *off, machine_mode memmode) e = cselib_lookup (x, GET_MODE (x), 0, memmode); if (e) { - if (SP_DERIVED_VALUE_P (e->val_rtx) + if (REG_DERIVED_VALUE_P (e->val_rtx) && (*off == NULL_RTX || *off == const0_rtx)) { *off = NULL_RTX; @@ -914,7 +917,7 @@ autoinc_split (rtx x, rtx *off, machine_mode memmode) for (struct elt_loc_list *l = e->locs; l; l = l->next) if (GET_CODE (l->loc) == PLUS && GET_CODE (XEXP (l->loc, 0)) == VALUE - && SP_DERIVED_VALUE_P (XEXP (l->loc, 0)) + && REG_DERIVED_VALUE_P (XEXP (l->loc, 0)) && CONST_INT_P (XEXP (l->loc, 1))) { if (*off == NULL_RTX) @@ -971,8 +974,8 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, machine_mode memmode, int depth) if (GET_CODE (y) == VALUE) return e == canonical_cselib_val (CSELIB_VAL_PTR (y)); - if ((SP_DERIVED_VALUE_P (x) - || SP_DERIVED_VALUE_P (e->val_rtx)) + if ((REG_DERIVED_VALUE_P (x) + || REG_DERIVED_VALUE_P (e->val_rtx)) && GET_MODE (y) == Pmode) { rtx yoff = NULL; @@ -1004,8 +1007,8 @@ rtx_equal_for_cselib_1 (rtx x, rtx y, machine_mode memmode, int depth) cselib_val *e = canonical_cselib_val (CSELIB_VAL_PTR (y)); struct elt_loc_list *l; - if ((SP_DERIVED_VALUE_P (y) - || SP_DERIVED_VALUE_P (e->val_rtx)) + if ((REG_DERIVED_VALUE_P (y) + || REG_DERIVED_VALUE_P (e->val_rtx)) && GET_MODE (x) == Pmode) { rtx xoff = NULL; @@ -1257,11 +1260,11 @@ cselib_hash_plus_const_int (rtx x, HOST_WIDE_INT c, int create, if (! e) return 0; - if (! SP_DERIVED_VALUE_P (e->val_rtx)) + if (! REG_DERIVED_VALUE_P (e->val_rtx)) for (struct elt_loc_list *l = e->locs; l; l = l->next) if (GET_CODE (l->loc) == PLUS && GET_CODE (XEXP (l->loc, 0)) == VALUE - && SP_DERIVED_VALUE_P (XEXP (l->loc, 0)) + && REG_DERIVED_VALUE_P (XEXP (l->loc, 0)) && CONST_INT_P (XEXP (l->loc, 1))) { e = CSELIB_VAL_PTR (XEXP (l->loc, 0)); @@ -2233,13 +2236,13 @@ cselib_subst_to_values (rtx x, machine_mode memmode) rtx t = cselib_subst_to_values (XEXP (x, 0), memmode); if (GET_CODE (t) == VALUE) { - if (SP_DERIVED_VALUE_P (t) && XEXP (x, 1) == const0_rtx) + if (REG_DERIVED_VALUE_P (t) && XEXP (x, 1) == const0_rtx) return t; for (struct elt_loc_list *l = CSELIB_VAL_PTR (t)->locs; l; l = l->next) if (GET_CODE (l->loc) == PLUS && GET_CODE (XEXP (l->loc, 0)) == VALUE - && SP_DERIVED_VALUE_P (XEXP (l->loc, 0)) + && REG_DERIVED_VALUE_P (XEXP (l->loc, 0)) && CONST_INT_P (XEXP (l->loc, 1))) return plus_constant (Pmode, l->loc, INTVAL (XEXP (x, 1))); } @@ -2355,6 +2358,8 @@ cselib_lookup_1 (rtx x, machine_mode mode, e = new_cselib_val (next_uid, GET_MODE (x), x); if (GET_MODE (x) == Pmode && x == stack_pointer_rtx) SP_DERIVED_VALUE_P (e->val_rtx) = 1; + if (GET_MODE (x) == Pmode && REG_P (x)) + REG_DERIVED_VALUE_P (e->val_rtx) = 1; new_elt_loc_list (e, x); scalar_int_mode int_mode; @@ -2436,7 +2441,7 @@ cselib_lookup_1 (rtx x, machine_mode mode, /* If cselib_preserve_constants, we might get a SP_DERIVED_VALUE_P VALUE that isn't in the hash tables anymore. */ - if (GET_CODE (v) == VALUE && SP_DERIVED_VALUE_P (v) && PRESERVED_VALUE_P (v)) + if (GET_CODE (v) == VALUE && REG_DERIVED_VALUE_P (v) && PRESERVED_VALUE_P (v)) PRESERVED_VALUE_P (e->val_rtx) = 1; new_elt_loc_list (e, v); diff --git a/gcc/rtl.h b/gcc/rtl.h index f298096a5a6..6ea206af04f 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -360,6 +360,7 @@ struct GTY((desc("0"), tag("0"), In a PREFETCH, this flag indicates that it should be considered a scheduling barrier. 1 in a CONCAT is VAL_NEEDS_RESOLUTION in var-tracking.cc. + 1 in a VALUE that is REG_DERIVED_VALUE_P in cselib.cc. Dumped as "/v" in RTL dumps. */ unsigned int volatil : 1; /* 1 in a REG if the register is used only in exit code a loop. diff --git a/gcc/testsuite/gcc.target/i386/cselib-1.c b/gcc/testsuite/gcc.target/i386/cselib-1.c new file mode 100644 index 00000000000..248193add8c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/cselib-1.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target { x86_64-*-* } } } */ +/* { dg-options "-O3" } */ +/* { dg-final { scan-assembler-not "leaq" } } */ + +extern int l(int *, int *); +extern void as(int *, int *); +extern int *q(); + +void m(int *k, int *al, int *aw) { + if (k != al) + as(aw, al); +} + +void d() { + int *p = q(), *e = q(); + int *c; + for (int *b = p; b != e; ++b) + if (l(b, p)) { + c = b + 1; + m(p, b, c); + } +} -- 2.46.0