Hello! This message revives an old thread [1], where the miscompilation of gfortran on alpha was found that that resulted in:
FAIL: gfortran.dg/assumed_rank_3.f90:15.20: print *, ubound(x,dim=3) ! << wrong dim 1 Error: Assumed-rank variable x at (1) may only be used as actual argument The problem was in the miscompilation of resolve_actual_arglist from resolve.c. This function initializes two nearby global bool variables with the following sequence: actual_arg = true; first_actual_arg = true; but due to the miscompilation, the actual_arg was never set to true. This happened due to the way stores to QImode and HImode locations are implemented on non-BWX targets. The sequence reads full word, does its magic to the part and stores the full word with changed part back to the memory. However - the scheduler mixed two sequences, violating the atomicity of RMW sequence. As demostrated in the great detail in the PR [2], the problem is in early exit for MEM_READOLNY_P in true_dependence_1 in alias.c. This early exit declares all MEM_READONLY_P references as non-aliasing, which is not true when possibly aliasing references with alignment ANDs are involved. Proposed patch prevents MEM_READONLY_P memory references to be moved over possibly aliased memory (with alignment ANDs). The patch prevents early exit for MEM_READONLY_P references when alignment ANDs are involved. The aliasing is then determined later in the function. In effect, it changes early exit to: - if (MEM_READONLY_P (x)) - return 0; + if (MEM_READONLY_P (x) + && GET_CODE (x_addr) != AND + && GET_CODE (mem_addr) != AND) + return 0; The comment also mentions "... We don't expect to find read-only set on MEM, but stupid user tricks can produce them, so don't die.". We certainly don't die anymore, as confirmed by a native alpha-linux-gnu (please note - not alphaev6!) bootstrap and regression test. 2014-10-08 Uros Bizjak <ubiz...@gmail.com> * alias.c (true_dependence_1): Do not exit early for MEM_READONLY_P references when alignment ANDs are involved. The patch was bootstrapped and regression tested on alpha-linux-gnu. OK for mainline and release branches? Please note that the patch by itself is not enough to fix the original problem with gfortran miscompilation. Another problem in this area is summarised in PR 63475 [3], where postreload CSE propagates aliased memory operand. [1] https://gcc.gnu.org/ml/gcc-patches/2014-06/msg02251.html [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63483 [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63475 Uros.
Index: alias.c =================================================================== --- alias.c (revision 215966) +++ alias.c (working copy) @@ -2458,18 +2458,6 @@ true_dependence_1 (const_rtx mem, enum machine_mod || MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER) return 1; - /* Read-only memory is by definition never modified, and therefore can't - conflict with anything. We don't expect to find read-only set on MEM, - but stupid user tricks can produce them, so don't die. */ - if (MEM_READONLY_P (x)) - return 0; - - /* If we have MEMs referring to different address spaces (which can - potentially overlap), we cannot easily tell from the addresses - whether the references overlap. */ - if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) - return 1; - if (! mem_addr) { mem_addr = XEXP (mem, 0); @@ -2493,6 +2481,22 @@ true_dependence_1 (const_rtx mem, enum machine_mod } } + /* Read-only memory is by definition never modified, and therefore can't + conflict with anything. However, don't assume anything when AND + addresses are involved and leave to the code below to determine + dependence. We don't expect to find read-only set on MEM, but + stupid user tricks can produce them, so don't die. */ + if (MEM_READONLY_P (x) + && GET_CODE (x_addr) != AND + && GET_CODE (mem_addr) != AND) + return 0; + + /* If we have MEMs referring to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + base = find_base_term (x_addr); if (base && (GET_CODE (base) == LABEL_REF || (GET_CODE (base) == SYMBOL_REF