On Thu, Nov 21, 2019 at 2:16 PM Tobias Burnus <tob...@codesourcery.com> wrote: > > Hi Richard, > > On 11/21/19 1:16 PM, Richard Biener wrote: > > OK, so I found it, it's handled via SSA_NAME_POINTS_TO_READONLY_MEMORY > > which is initialized during the rewrite into SSA form from the > > information given by the "fn spec" attribute […] so when the frontend > > sets "fn spec" from the intent it should already work. > > Which I can confirm for the following made-up example: > > real function foo(n) > implicit none (type) > integer, intent(in) :: n > integer :: i > foo = 0.5 > if (n /= 0) return > call bar() > do i = 1, n > foo = foo + sin(foo) > end do > end > > The optimized dump shows the following, i.e. GCC nicely optimizes both the > loop and the 'sin' call away: > > foo (integer(kind=4) & restrict n) > { > integer(kind=4) _1; > <bb 2> [local count: 241635843]: > _1 = *n_9(D); > if (_1 != 0) > goto <bb 4>; [51.12%] > else > goto <bb 3>; [48.88%] > > <bb 3> [local count: 118111600]: > bar (); > > <bb 4> [local count: 241635844]: > return 5.0e-1; > } > > I think this optimization permits some crucial optimizations. > I have not fully followed the later versions of the patch whether > they exploit some additional language semantics to permit optimizations > even without intent(in), but the initial discussion started with intent(in). > > > But the examples I saw above didn't use INTENT(IN) for the scalar > > parameters. > > I concur that a well-written program should make use of intent(in) where > sensible. > > There are cases, which could be optimized likewise – but based on the > case that the pointer address cannot escape instead of just assuming > that the argument cannot change. – The question is how to convey this to > the middle end. > > I wonder whether there is a 'fn attr' which can tell that the first > argument of 'print_i' does not cause the address of 'i' escape. If so, > one could mark all procedure arguments such – unless they have the > pointer, target or asynchronous attribute or are coarrays. [Probably > needs some fine tuning.] > > In this example, variable values do change, but only in a controlled way > ('print_i' could change it, 'bar' cannot). The semantic is also mainly a > property of the (local) variable (or dummy argument) declaration and not > of the functions which are called – although, if 'i' has no target > attribute, print_i's argument cannot have neither – hence, one could > generated a function interface > > real function foo(i, y) > implicit none (type) > integer :: i > real :: y > foo = 0.0 > call print_i(i) > i = 5 > call bar() ! < this prevents optimizing the sin(y) away > if (i == 5) return > foo = sin(y) > end > > Fortran semantics implies that 'i' can only change after the 'i = 5' if: > 'i' has the TARGET (or POINTER) attribute. Or it is possible if 'i' has > the ASYNCHRONOUS or VOLATILE attribute – or it is a coarray (where a > remote image can modify the local value).
So I think what you'd need to do is make 'i' marked as TYPE_RESTRICT then. I think we don't yet handle it but it means that bar() may not modify 'i' but via 'i' (but it doesn't get 'i' as a parameter). > For asynchronous, it would be something like "call read_i(i); call > wait()" which is structurally the same as above. > > TARGET: "An object without the TARGET attribute shall not have a pointer > associated with it." > VOLATILE: "may be referenced, defined, or become undefined, by > means20not specified by the program" > ASYNCHRONOUS: "An entity with the ASYNCHRONOUS attribute is a variable, > and may be subject to asynchronous input/output or asynchronous > communication." I think for GIMPLE everything not obviously on the stack is ASYNCHRONOUS. Richard. > Tobias >