<!--===- docs/Aliasing.md
Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
See https://llvm.org/LICENSE.txt for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
# Aliasing in Fortran
```{contents}
---
local:
---
```
## Introduction
References to the ISO Fortran language standard here are given by subclause number
or constraint number and pertain to Fortran 2018.
## Dummy Arguments
### Basic rule
Fortran famously passes actual arguments by reference, and forbids callers
from associating multiple arguments on a call to conflicting storage when
doing so would cause the called subprogram to write to a bit of that
storage by means of one dummy argument and read or write that same bit
by means of another.
For example:
```
function f(a,b,j,k)
real a(*), b(*)
a(j) = 1.
b(k) = 2.
f = a(j) ! can optimize to: f = 1.
end function
```
This prohibition applies to programs (or programmers) and has been in place
since Fortran acquired subroutines and functions in Fortran II.
A Fortran compiler is free to assume that a program conforms with this rule
when optimizing; and while obvious violations should of course be diagnosed,
the programmer bears the responsibility to understand and comply with this rule.
It should be noted that this restriction on dummy argument aliasing works
"both ways", in general.
Modifications to a dummy argument cannot affect other names by which that
bit of storage may be known;
conversely, modifications to anything other than a dummy argument cannot
affect that dummy argument.
When a subprogram modifies storage by means of a particular dummy argument,
Fortran's prohibition against dummy argument aliasing is not limited just to other
dummy arguments, but to any other name by which that storage might be visible.
For example:
```
module m
real x
contains
function f(y)
real y
x = 1.
y = 2.
f = x ! can optimize to: f = 1.
end function
subroutine bad
print *, f(x) ! nonconforming usage!
end subroutine
end module
```
Similar examples can be written using variables in `COMMON` blocks, host-association
in internal subprograms, and so forth.
Further, the general rule that a dummy argument by which some particular bit
of storage has been modified must be the only means by which that storage is
referenced during the lifetime of a subprogram extends to cover any associations
with that dummy argument via pointer association, argument association in
procedure references deeper on the call chain, and so on.
### Complications
Subclause 15.5.2.13 ("Restrictions on entities associated with dummy arguments"),
which the reader is encouraged to try to understand despite its opacity,
formalizes the rules for aliasing of dummy arguments.
In addition to the "basic rule" above, Fortran imposes these additional
requirements on programs.
1. When a dummy argument is `ALLOCATABLE` or `POINTER`, it can be deallocated
or reallocated only through the dummy argument during the life of the
subprogram.
1. When a dummy argument has a derived type with a component, possibly nested,
that is `ALLOCATABLE` or `POINTER`, the same restriction applies.
1. If a subprogram ever deallocates or reallocates a dummy argument or one of its
components, the program cannot access that data by any other means, even
before the change in allocation.
That subclause also *relaxes* the rules against dummy argument aliasing in
some situations.
1. When a dummy argument is a `POINTER`, it is essentially treated like any
other pointer for the purpose of alias analysis (see below), and its
status as a dummy argument is reduced to being relevant only for
deallocation and reallocation (see above).
1. When a dummy argument is a `TARGET`, the actual argument is really
a variable (not an expression or something that needs to be passed via
a temporary), and that variable could be a valid data target in a pointer
assignment statement, then the compiler has to worry about aliasing
between that dummy argument and pointers if some other circumstances
apply. (See the standard, this one is weird and complicated!)
1. Aliasing doesn't extend its restrictions to what other images might do
to a coarray dummy argument's associated local storage during the lifetime
of a subprogram -- i.e., other images don't have to worry about avoiding
accesses to the local image's storage when its coarray nature is explicit
in the declaration of the dummy argument.
(But when the local image's storage is associated with a non-coarray dummy
argument, the rules still apply.
In other words, the compiler doesn't have to worry about corrays unless
it sees coarrays.)
### Implications for inlining
A naive implementation of inlining might rewrite a procedure reference
something like this:
```
module m
contains
function addto(x, y)
real, intent(in out) :: x
real, intent(in) :: y
x = x + y
addto = y
end function
function f(a,j,k)
real a(*)
a(k) = 1.
f = addto(a(j), a(k)) ! optimizable to 1.
end function
end module
```
becoming, after inline expansion at the Fortran language level,
```
function f(a,j,k)
real a(*)
a(k) = 1.
a(j) = a(j) + a(k)
f = a(k) ! no longer optimizable to 1.
end function
```
The problem for a compiler is this: at the Fortran language level, no
language construct has the same useful guarantees against aliasing as
dummy arguments have.
A program transformation that changes dummy arguments into something
else needs to implement in its internal or intermediate representations
some kind of metadata that preserves assumptions against aliasing.
### `INTENT(IN)`
A dummy argument may have an`INTENT` attribute.
The relevant case for alias analysis is `INTENT(IN)`, as constraint
C844 prohibits the appearance of an `INTENT(IN)` non-pointer dummy
argument in any "variable definition context" (19.6.7), which is
Fortran's way of saying that it might be at risk of modification.
It would be great if the compiler could assume that an actual argument
that corresponds to an `INTENT(IN)` dummy argument is unchanged after
the called subprogram returns.
Unfortunately, the language has holes that admit ways by which an
`INTENT(IN)` dummy argument may change, even in a conforming program
(paragraph 2 and note 4 in subclause 8.5.10 notwithstanding).
In particular, Fortran nowhere states that a non-pointer `INTENT(IN)`
dummy argument is not "definable".
1. `INTENT(IN)` does not prevent the same variable from also being
associated with another dummy argument in the same call *without*
`INTENT(IN)` and being modified thereby, which is conforming so
long as the subprogram never references the dummy argument that
has `INTENT(IN)`.
In other words, `INTENT(IN)` is necessary but not sufficient to
guarantee safety from modification.
1. A dummy argument may have `INTENT(IN)` and `TARGET` attributes,
and in a non-`PURE` subprogram this would allow modification of
its effective argument by means of a local pointer.
1. An `INTENT(IN)` dummy argument may be forwarded to another
procedure's dummy argument with no `INTENT` attribute, and is
susceptible to being modified during that call.
This case includes references to procedures with implicit
interfaces.
So, for the purposes of use/def/kill analysis, associating a variable with
a non-`PURE` procedure's non-pointer dummy argument may be fraught
even when `INTENT(IN)` is present without `VALUE`.
Arguing the other side of this:
an interoperable procedure's `INTENT(IN)` dummy
arguments are forbidden from being modified, and it would be odd
for calls to foreign C functions to be safer than native calls (18.7).
### `VALUE`
A dummy argument with the `VALUE` attribute is effectively meant to
be copied into a temporary for a call and not copied back into
its original variable (if any).
A `VALUE` dummy argument is therefore as safe from aliasing as
a local variable of the subprogram is.
## Pointers and targets
Modern Fortran's pointers can't associate with arbitrary data.
They can be pointed only at objects that have the explicit `TARGET`
attribute, or at the targets of other pointers.
A variable that does not have the `TARGET` attribute is generally
safe from aliasing with pointers (but see exceptions below).
And generally, pointers must be assumed to alias all other pointers and
all `TARGET` data (perhaps reduced with data flow analysis).
A `VOLATILE` pointer can only point to a `VOLATILE` target, and
a non-`VOLATILE` pointer cannot.
A clever programmer might try to exploit this requirement to
clarify alias analysis, but I have not encountered such usage
so far.
### The `TARGET` hole for dummy arguments
An actual argument that doesn't have the `TARGET` attribute can still be
associated with a dummy argument that *is* a target.
This allows a non-target variable to become a target during the lifetime
of a call.
In a non-`PURE` subprogram (15.7), a pointer may be assigned to such a
dummy argument or to a portion of it.
Such a pointer has a valid lifetime that ends when the subprogram does.
### Valid lifetimes of pointers to dummy arguments
The Fortran standard doesn't mention compiler-generated and -populated
temporary storage in the context of argument association in 15.5.2,
apart from `VALUE`, but instead tries to name all of the circumstances
in which an actual argument's value may have to be transmitted by means
of a temporary in each of the paragraphs that constrain the usable
lifetimes of a pointer that has been pointed to a dummy argument
during a call.
It would be more clear, I think, had the standard simply described
the reasons for which an actual argument might have to occupy temporary
storage, and then just said that pointers to temporaries must not be
used once those temporaries no longer exist.
### Lack of pointer target `INTENT`
`INTENT` attributes for dummy pointer arguments apply to the pointer
itself, not to the data to which the pointer points.
Fortran still has no means of declaring a read-only pointer.
Fortran also has no rule against associating read-only data with a pointer.
### Cray pointers
Cray pointers are, or were, an extension that attempted to provide
some of the capabilities of modern pointers and allocatables before those
features were standardized.
They had some aliasing restrictions; in particular, Cray pointers were
not allowed to alias each other.
They are now more or less obsolete and we have no plan in place to
support them.
## Type considerations
Pointers with distinct types may alias so long as their types are
compatible in the sense of the standard.
Pointers to derived types and `COMPLEX` may alias with pointers to the
types of their components.
For example:
```
complex, pointer :: pz(:)
real, pointer :: pa(:)
pa => z(:)%re ! points to all of the real components
```
### Shape and rank
Array rank is not a material consideration to alias analysis.
Two pointers may alias even if their ranks or shapes differ.
For example, a pointer may associate with a column in a matrix
to which another pointer associates;
or a matrix pointer with only one column or one row may associate
with a vector.
It is also possible in Fortran to "remap" target data by establishing
a pointer of arbitrary rank as a view of a storage sequence.
For example:
```
real, target :: vector(100)
real, pointer :: matrix(:,:)
matrix(1:10,1:10) => v ! now vector's elements look like a matrix
```
## Selectors in `ASSOCIATE`, `SELECT TYPE`, and `CHANGE TEAM`
Selectors in `ASSOCIATE` and related constructs may associate with
either expression values or variables.
In the case of variables, the language imposes no restriction on
aliasing during the lifetime of the construct, and the compiler must
not assume that a selector works in a manner that is analogous to
that of a dummy argument.
## Allocatables
There really isn't anything special about `ALLOCATABLE` objects
from the perspective of aliasing, apart from rules (above) that requiring
`ALLOCATABLE` dummy arguments be (de)allocated only by way of the dummy
argument.
Because an `ALLOCATABLE` dummy argument preserves the values of lower
bounds and can be assumed to be contiguous, some programmers advocate
the use of explicitly `ALLOCATABLE` dummy arguments even when subprograms
do not modify their allocation status.
The usual aliasing restrictions still apply, even when the same `ALLOCATABLE`
is associated with two or more dummy arguments on a call.
## `ASYNCHRONOUS` and `VOLATILE`
These attributes can, unlike any other, be scoped in Fortran by means of
redeclaration in a `BLOCK` construct or nested procedure.
`ASYNCHRONOUS` data must be assumed to be read or written by some other
agent during its lifetime.
For example, Fortran's asynchronous I/O capabilities might be implemented
in a runtime support library by means of threading or explicitly asynchronous
system calls.
An MPI implementation might use `ASYNCHRONOUS` dummy arguments to indicate
that data transfers may take place during program execution in some way that
is not visible to the Fortran compiler.
The optimizer must handle `ASYNCHRONOUS` and `VOLATILE` data with great care.
Reads and writes of `ASYNCHRONOUS` data cannot be moved across statements
that might initiate or complete background operations.
Reads and writes of `VOLATILE` data should be treated like `volatile` in C:
there are no "dead" writes, reads cannot be CSE'd, and both operations should
be properly fenced.
## Storage assocation via `EQUIVALENCE`
A non-allocatable object, or parts of one, may have multiple names in Fortran
via `EQUIVALENCE`.
These objects cannot be have the `POINTER` or `TARGET` attributes.
Their offsets in static, stack, or `COMMON` storage is resolved by semantics
prior to lowering.