https://gcc.gnu.org/g:3da0e5adc113eebb2519d5b4374b2ff5491425d4
commit 3da0e5adc113eebb2519d5b4374b2ff5491425d4 Author: Alexandre Oliva <[email protected]> Date: Wed Dec 17 02:44:37 2025 -0300 cselib: lookup mem addr during invalidation When processing stores for e.g. parameters passed on the stack, as in gcc.dg/pr117239.c, each store invalidates other stores pertaining to the same argument, because we can tell they refer to the same object, but not that the offsets don't overlap. The reason for that is that the mem_rtx being invalidated is canonicalized to an SP offset, while those in the cselib table have canonical values as addresses, and alias.cc can't resolve SP to values to compare the offsets. With this change, pr117239.c doesn't require -fschedule-insns to fail, with the PR117239 fixes reverted. for gcc/ChangeLog * cselib.cc (cselib_invalidate_mem): Lookup the address as part of canonicalizing it. Diff: --- gcc/alias.cc | 90 ++++++++++++++++++++++++++++++++++++++++++++++++----- gcc/cselib.cc | 71 +++++++++++++++++++++++++++++++++++++++++- gcc/rtl.def | 3 ++ gcc/var-tracking.cc | 1 + 4 files changed, 156 insertions(+), 9 deletions(-) diff --git a/gcc/alias.cc b/gcc/alias.cc index a23396eaa35e..f1efb4fd9471 100644 --- a/gcc/alias.cc +++ b/gcc/alias.cc @@ -1659,6 +1659,16 @@ get_reg_base_value (unsigned int regno) return (*reg_base_value)[regno]; } +rtx +get_reg_base_value_checked (unsigned int regno) +{ + if (!reg_base_value) + return NULL_RTX; + if (regno >= reg_base_value->length ()) + return NULL_RTX; + return get_reg_base_value (regno); +} + /* If a value is known for REGNO, return it. */ rtx @@ -1964,6 +1974,12 @@ find_base_term (rtx x, vec<std::pair<cselib_val *, return temp; } + case VALUE_ADDRESS: + x = XEXP (x, 0); + if (GET_CODE (x) != VALUE) + return x; + /* Fall through. */ + case VALUE: val = CSELIB_VAL_PTR (x); ret = NULL_RTX; @@ -2070,6 +2086,13 @@ find_base_term (rtx x) return res; } +rtx +find_value_base_term (rtx x) +{ + gcc_checking_assert (GET_CODE (x) == VALUE); + return find_base_term (x); +} + /* Return true if accesses to address X may alias accesses based on the stack pointer. */ @@ -2315,8 +2338,16 @@ get_addr (rtx x) for (l = v->locs; l; l = l->next) if (CONSTANT_P (l->loc)) return l->loc; +#if 0 + else if (GET_CODE (l->loc) == VALUE_ADDRESS) + return x; +#endif for (l = v->locs; l; l = l->next) if (!REG_P (l->loc) && !MEM_P (l->loc) + /* ENTRY_VALUEs are not useful addresses, we can't get aliasing + information from them. */ + && GET_CODE (l->loc) != ENTRY_VALUE + && GET_CODE (l->loc) != VALUE_ADDRESS /* Avoid infinite recursion when potentially dealing with var-tracking artificial equivalences, by skipping the equivalences themselves, and not choosing expressions @@ -2330,6 +2361,8 @@ get_addr (rtx x) for (l = v->locs; l; l = l->next) if (REG_P (l->loc) || (GET_CODE (l->loc) != VALUE + && GET_CODE (l->loc) != ENTRY_VALUE + && GET_CODE (l->loc) != VALUE_ADDRESS && !refs_newer_value_p (l->loc, x))) return l->loc; /* Return the canonical value. */ @@ -3080,6 +3113,36 @@ canon_true_dependence (const_rtx mem, machine_mode mem_mode, rtx mem_addr, x, x_addr, /*mem_canonicalized=*/true); } +/* Return true iff x and m are addresses with the same base term, and that are + equivalent memrefs. Both are presumed canonicalized. */ +bool +same_base_term_known_overlap_p (rtx x, rtx m, poly_int64 size) +{ + rtx tx = get_addr (x); + rtx tm = get_addr (m); + + rtx bx = find_base_term (tx); + rtx bm = find_base_term (tm); + + if (bx != bm && bx && bm + && !(GET_CODE (bx) == ADDRESS + && GET_CODE (bm) == ADDRESS + && bx->u.fld[0].rt_int <= 0 + && bm->u.fld[0].rt_int <= 0) + /* libgo runtime may different decls for the same symbol used within the + same function, because they come from different units compiled + together. */ + && !(GET_CODE (bx) == SYMBOL_REF + && GET_CODE (bm) == SYMBOL_REF + && XSTR (bx, 0) == XSTR (bm, 0))) + return false; + + x = canon_rtx (tx); + m = canon_rtx (tm); + + return memrefs_conflict_p (size, x, size, m, 0) != 0; +} + /* Returns true if a write to X might alias a previous read from (or, if WRITEP is true, a write to) MEM. If X_CANONCALIZED is true, then X_ADDR is the canonicalized address of X, @@ -3290,16 +3353,25 @@ init_alias_target (void) && targetm.hard_regno_mode_ok (i, Pmode)) static_reg_base_value[i] = arg_base_value; - /* RTL code is required to be consistent about whether it uses the - stack pointer, the frame pointer or the argument pointer to - access a given area of the frame. We can therefore use the - base address to distinguish between the different areas. */ + /* RTL code is required to be consistent about whether it uses the stack + pointer, the frame pointer or the argument pointer to access a given area + of the frame. We can therefore use the base address to distinguish + between the different areas. However, after register allocation and + especially prologue generation, cselib makes all these areas part of the + same cluster of VALUEs, making it hard to distinguish the areas, so make + them all share the same base term then. */ static_reg_base_value[STACK_POINTER_REGNUM] - = unique_base_value (UNIQUE_BASE_VALUE_SP); + = (reload_completed + ? arg_base_value + : unique_base_value (UNIQUE_BASE_VALUE_SP)); static_reg_base_value[ARG_POINTER_REGNUM] - = unique_base_value (UNIQUE_BASE_VALUE_ARGP); + = (reload_completed + ? arg_base_value + : unique_base_value (UNIQUE_BASE_VALUE_ARGP)); static_reg_base_value[FRAME_POINTER_REGNUM] - = unique_base_value (UNIQUE_BASE_VALUE_FP); + = (reload_completed + ? arg_base_value + : unique_base_value (UNIQUE_BASE_VALUE_FP)); /* The above rules extend post-reload, with eliminations applying consistently to each of the three pointers. Cope with cases in @@ -3307,7 +3379,9 @@ init_alias_target (void) rather than the stack pointer. */ if (!HARD_FRAME_POINTER_IS_FRAME_POINTER) static_reg_base_value[HARD_FRAME_POINTER_REGNUM] - = unique_base_value (UNIQUE_BASE_VALUE_HFP); + = (reload_completed + ? arg_base_value + : unique_base_value (UNIQUE_BASE_VALUE_HFP)); } /* Set MEMORY_MODIFIED when X modifies DATA (that is assumed diff --git a/gcc/cselib.cc b/gcc/cselib.cc index 930357409bc5..a6cae62bb2fe 100644 --- a/gcc/cselib.cc +++ b/gcc/cselib.cc @@ -2505,6 +2505,8 @@ cselib_lookup (rtx x, machine_mode mode, static void cselib_invalidate_regno_val (unsigned int regno, struct elt_list **l) { + extern rtx get_reg_base_value_checked (unsigned); + rtx value_address = get_reg_base_value_checked (regno); cselib_val *v = (*l)->elt; if (*l == REG_VALUES (regno)) { @@ -2517,7 +2519,12 @@ cselib_invalidate_regno_val (unsigned int regno, struct elt_list **l) l = &(*l)->next; } else - unchain_one_elt_list (l); + { + if (value_address + && GET_MODE (value_address) != GET_MODE (v->val_rtx)) + value_address = NULL_RTX; + unchain_one_elt_list (l); + } v = canonical_cselib_val (v); @@ -2533,6 +2540,56 @@ cselib_invalidate_regno_val (unsigned int regno, struct elt_list **l) if (REG_P (x) && REGNO (x) == regno) { unchain_one_elt_loc_list (p); + + extern rtx find_value_base_term (rtx); + /* Preserve the VALUE_ADDRESS associated with the regno previously + held in v, if we can't identify it any longer. */ + rtx found_value_address = find_value_base_term (v->val_rtx); + cselib_val *add_address_to = NULL; + if (value_address && found_value_address != value_address) + add_address_to = v; + + rtx wanted_value_address + = value_address ? value_address : found_value_address; + + if (wanted_value_address) + { + cselib_val *addrv = v; + for (;;) + { + rtx addr = canon_rtx (get_addr (addrv->val_rtx)); + if (addr == addrv->val_rtx + || GET_CODE (addr) != PLUS + || GET_CODE (XEXP (addr, 0)) != VALUE + || !CONSTANT_P (XEXP (addr, 1))) + break; + + rtx addr_value_address + = find_value_base_term (XEXP (addr, 0)); + if (addr_value_address) + break; + else + { + gcc_checking_assert (addr_value_address + != wanted_value_address); + addrv = add_address_to + = canonical_cselib_val (CSELIB_VAL_PTR (XEXP (addr, 0))); + } + } + } + + if (add_address_to) + { + if (add_address_to != v) + p = &add_address_to->locs; + + elt_loc_list *n = *p; + *p = elt_loc_list_pool.allocate (); + (*p)->loc = gen_rtx_VALUE_ADDRESS (GET_MODE (v->val_rtx), + wanted_value_address); + (*p)->setting_insn = setting_insn; + (*p)->next = n; + } break; } } @@ -2623,6 +2680,18 @@ cselib_invalidate_mem (rtx mem_rtx) rtx mem_addr; mem_addr = canon_rtx (get_addr (XEXP (mem_rtx, 0))); + /* Resolve MEM_ADDR to a VALUE_RTX, so that canon_anti_dependence can compare + offsets from the same base, even for SP-based addresses. */ + if ((v = cselib_lookup (mem_addr, GET_MODE (mem_addr), + 0, GET_MODE (mem_rtx)))) + { + extern bool same_base_term_known_overlap_p (rtx, rtx, poly_int64); + gcc_checking_assert (same_base_term_known_overlap_p + (mem_addr, v->val_rtx, + GET_MODE_SIZE (GET_MODE (mem_rtx)))); + mem_addr = v->val_rtx; + mem_rtx = replace_equiv_address_nv (mem_rtx, mem_addr); + } mem_rtx = canon_rtx (mem_rtx); vp = &first_containing_mem; diff --git a/gcc/rtl.def b/gcc/rtl.def index 15ae7d10fcc1..b1f68fb00d25 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -128,6 +128,9 @@ DEF_RTL_EXPR(SEQUENCE, "sequence", "E", RTX_EXTRA) /* Represents a non-global base address. This is only used in alias.cc. */ DEF_RTL_EXPR(ADDRESS, "address", "i", RTX_EXTRA) +/* Represents a base address within a cselib table. */ +DEF_RTL_EXPR(VALUE_ADDRESS, "value_address", "e", RTX_OBJ) + /* ---------------------------------------------------------------------- Expression types used for things in the instruction chain. diff --git a/gcc/var-tracking.cc b/gcc/var-tracking.cc index 7c255b1a8833..e0b9364a3d9e 100644 --- a/gcc/var-tracking.cc +++ b/gcc/var-tracking.cc @@ -2442,6 +2442,7 @@ unsuitable_loc (rtx loc) case SCRATCH: case ASM_INPUT: case ASM_OPERANDS: + case VALUE_ADDRESS: return true; default:
