On Tue, Feb 4, 2020 at 6:44 PM Richard Sandiford <richard.sandif...@arm.com> wrote: > > Richard Sandiford <richard.sandif...@arm.com> writes: > > [...] > >> I'm not sure given the issues you've introduced if I could actually > >> fill out the matrix of answers without more underlying information. > >> ie, when can we get symbols without source level decls, > >> anchors+interposition issues, etc. > > > > OK. In that case, I wonder whether it would be safer to have a > > fourth state on top of the three above: > > > > - known distance apart > > - independent > > - known distance apart or independent > > - don't know > > > > with "don't know" being anything that involves bare symbols? > > > > Richard > > How does this look? Tested on aarch64-linux-gnu and > x86_64-linux-gnu. > > Full description from scratch: > > memrefs_conflict_p has a slightly odd structure. It first checks > whether two addresses based on SYMBOL_REFs refer to the same object, > with a tristate result: > > int cmp = compare_base_symbol_refs (x,y); > > If the addresses do refer to the same object, we can use offset-based checks: > > /* If both decls are the same, decide by offsets. */ > if (cmp == 1) > return offset_overlap_p (c, xsize, ysize); > > But then, apart from the special case of forced address alignment, > we use an offset-based check even if we don't know whether the > addresses refer to the same object: > > /* Assume a potential overlap for symbolic addresses that went > through alignment adjustments (i.e., that have negative > sizes), because we can't know how far they are from each > other. */ > if (maybe_lt (xsize, 0) || maybe_lt (ysize, 0)) > return -1; > /* If decls are different or we know by offsets that there is no > overlap, > we win. */ > if (!cmp || !offset_overlap_p (c, xsize, ysize)) > return 0; > > This somewhat contradicts: > > /* In general we assume that memory locations pointed to by different labels > may overlap in undefined ways. */
Sorry for not chiming in earlier but isn't the bug that > at the end of compare_base_symbol_refs. In other words, we're taking -1 > to mean that either (a) the symbols are equal (via aliasing) or (b) the > references access non-overlapping objects. > > But even assuming that's true for normal symbols, it doesn't cope > correctly with section anchors. If a symbol X at ANCHOR+OFFSET > is preemptible, either (a) X = ANDHOR+OFFSET or (b) X and ANCHOR > reference non-overlapping objects. > > And an offset-based comparison makes no sense for an anchor symbol > vs. a bare symbol with no decl. If the bare symbol is allowed to > alias other symbols then it can surely alias any symbol in the > anchor's block, so there are multiple anchor offsets that might > induce an alias. But then isn't the simple fix to honor the -1 and do diff --git a/gcc/alias.c b/gcc/alias.c index 3794f9b6a9e..bf13d37c0f7 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -2490,9 +2490,8 @@ memrefs_conflict_p (poly_int64 xsize, rtx x, poly_int64 ysize, rtx y, other. */ if (maybe_lt (xsize, 0) || maybe_lt (ysize, 0)) return -1; - /* If decls are different or we know by offsets that there is no overlap, - we win. */ - if (!cmp || !offset_overlap_p (c, xsize, ysize)) + /* If decls are different, we win. */ + if (cmp == 0) return 0; /* Decls may or may not be different and offsets overlap....*/ return -1; ? > This patch therefore replaces the current tristate: > > - known equal > - known independent (two accesses can't alias) > - equal or independent > > with: > > - known distance apart > - known independent (two accesses can't alias) > - known distance apart or independent > - don't know > > For safety, the patch puts all bare symbols in the "don't know" > category. If that turns out to be too conservative, we at least > need that behaviour for combinations involving a bare symbol > and a section anchor. This sounds complicated (for this stage). Do you have any statistics as to how it affects actual alias queries (thus outcome in {true,...}_dependence) when you do the "simple" fix? Thanks, Richard. > 2020-02-04 Richard Sandiford <richard.sandif...@arm.com> > > gcc/ > PR rtl-optimization/92294 > * alias.c (compare_base_symbol_refs): Take an extra parameter > and add the distance between two symbols to it. Enshrine in > comments that -1 means "either 0 or 1, but we can't tell > which at compile time". Return -2 for symbols whose > relationship is unknown. > (memrefs_conflict_p): Update call accordingly. > (rtx_equal_for_memref_p): Likewise. Punt for a return value of -2, > without even checking the offset. Take the distance between symbols > into account. > --- > gcc/alias.c | 53 ++++++++++++++++++++++++++++++++++++++--------------- > 1 file changed, 38 insertions(+), 15 deletions(-) > > diff --git a/gcc/alias.c b/gcc/alias.c > index 3794f9b6a9e..c8b53df0b48 100644 > --- a/gcc/alias.c > +++ b/gcc/alias.c > @@ -159,7 +159,8 @@ static tree decl_for_component_ref (tree); > static int write_dependence_p (const_rtx, > const_rtx, machine_mode, rtx, > bool, bool, bool); > -static int compare_base_symbol_refs (const_rtx, const_rtx); > +static int compare_base_symbol_refs (const_rtx, const_rtx, > + HOST_WIDE_INT * = NULL); > > static void memory_modified_1 (rtx, const_rtx, void *); > > @@ -1806,7 +1807,11 @@ rtx_equal_for_memref_p (const_rtx x, const_rtx y) > return label_ref_label (x) == label_ref_label (y); > > case SYMBOL_REF: > - return compare_base_symbol_refs (x, y) == 1; > + { > + HOST_WIDE_INT distance = 0; > + return (compare_base_symbol_refs (x, y, &distance) == 1 > + && distance == 0); > + } > > case ENTRY_VALUE: > /* This is magic, don't go through canonicalization et al. */ > @@ -2138,10 +2143,24 @@ compare_base_decls (tree base1, tree base2) > return ret; > } > > -/* Same as compare_base_decls but for SYMBOL_REF. */ > +/* Compare SYMBOL_REFs X_BASE and Y_BASE. > + > + - Return 1 if Y_BASE - X_BASE is constant, adding that constant > + to *DISTANCE if DISTANCE is nonnull. > + > + - Return 0 if no valid accesses based on X_BASE can alias valid > + accesses based on Y_BASE. > + > + - Return -1 if one of the two results above applies, but we can't > + tell which at compile time. Update DISTANCE in the same way as > + for a return value of 1, for the case in which that result holds > + at runtime. > + > + - Return -2 otherwise. */ > > static int > -compare_base_symbol_refs (const_rtx x_base, const_rtx y_base) > +compare_base_symbol_refs (const_rtx x_base, const_rtx y_base, > + HOST_WIDE_INT *distance) > { > tree x_decl = SYMBOL_REF_DECL (x_base); > tree y_decl = SYMBOL_REF_DECL (y_base); > @@ -2161,7 +2180,7 @@ compare_base_symbol_refs (const_rtx x_base, const_rtx > y_base) > /* We handle specially only section anchors and assume that other > labels may overlap with user variables in an arbitrary way. */ > if (!SYMBOL_REF_HAS_BLOCK_INFO_P (y_base)) > - return -1; > + return -2; > /* Anchors contains static VAR_DECLs and CONST_DECLs. We are safe > to ignore CONST_DECLs because they are readonly. */ > if (!VAR_P (x_decl) > @@ -2188,15 +2207,14 @@ compare_base_symbol_refs (const_rtx x_base, const_rtx > y_base) > { > if (SYMBOL_REF_BLOCK (x_base) != SYMBOL_REF_BLOCK (y_base)) > return 0; > - if (SYMBOL_REF_BLOCK_OFFSET (x_base) == SYMBOL_REF_BLOCK_OFFSET > (y_base)) > - return binds_def ? 1 : -1; > - if (SYMBOL_REF_ANCHOR_P (x_base) != SYMBOL_REF_ANCHOR_P (y_base)) > - return -1; > - return 0; > + if (distance) > + *distance += (SYMBOL_REF_BLOCK_OFFSET (y_base) > + - SYMBOL_REF_BLOCK_OFFSET (x_base)); > + return binds_def ? 1 : -1; > } > /* In general we assume that memory locations pointed to by different > labels > may overlap in undefined ways. */ > - return -1; > + return -2; > } > > /* Return 0 if the addresses X and Y are known to point to different > @@ -2479,11 +2497,16 @@ memrefs_conflict_p (poly_int64 xsize, rtx x, > poly_int64 ysize, rtx y, > > if (GET_CODE (x) == SYMBOL_REF && GET_CODE (y) == SYMBOL_REF) > { > - int cmp = compare_base_symbol_refs (x,y); > + HOST_WIDE_INT distance = 0; > + int cmp = compare_base_symbol_refs (x, y, &distance); > > - /* If both decls are the same, decide by offsets. */ > + /* Punt if we have no information about the relationship between > + X and Y. */ > + if (cmp == -2) > + return -1; > + /* If the symbols are a known distance apart, decide by offsets. */ > if (cmp == 1) > - return offset_overlap_p (c, xsize, ysize); > + return offset_overlap_p (c + distance, xsize, ysize); > /* Assume a potential overlap for symbolic addresses that went > through alignment adjustments (i.e., that have negative > sizes), because we can't know how far they are from each > @@ -2492,7 +2515,7 @@ memrefs_conflict_p (poly_int64 xsize, rtx x, poly_int64 > ysize, rtx y, > return -1; > /* If decls are different or we know by offsets that there is no > overlap, > we win. */ > - if (!cmp || !offset_overlap_p (c, xsize, ysize)) > + if (!cmp || !offset_overlap_p (c + distance, xsize, ysize)) > return 0; > /* Decls may or may not be different and offsets overlap....*/ > return -1;