The runtime Assign function is not meant to initialize an array from a
scalar. For that we need to use DoAssignFromSource. Update the data
transfer from scalar to descriptor to use a new entry point that use
this function underneath.
There were two bugs in derived type array assignment processing that
caused finalization to fail to occur for a test case. The first bug was
an off-by-one error in address overlap testing that caused a false
positive result for the test, whose left-hand side's allocatable's
descriptor was immediately adjacent in memory to the right-hand side's
array's data.
The second bug was that in such overlap cases (even when legitimate)
finalization would fail due to the LHS's descriptor having been copied
to a temporary for deferred deallocation and then nullified.
This patch corrects the overlap analysis for this test, and also
properly finalizes the LHS when overlap does exist. Some nearby dead
code was removed to avoid future confusion.
Fixes https://github.com/llvm/llvm-project/issues/113375.
- Add a parameter to the `Assign` function to be able to use a different
`memmove` function. This is preparatory work to be able to use the
`Assign` function between host and device data.
- Expose the `Assign` function so it can be used from different files.
- The new `memmoveFct` is not used in `BlankPadCharacterAssignment` yet
since it is not clear if there is a need. It will be updated in case it
is needed.
A defined assignment generic interface for a given LHS/RHS type & rank
combination may have a specific procedure with LHS dummy argument that
is neither allocatable nor pointer, or specific procedure(s) whose LHS
dummy arguments are allocatable or pointer. It is possible to have two
specific procedures if one's LHS dummy argument is allocatable and the
other's is pointer.
However, the runtime doesn't work with LHS dummy arguments that are
allocatable, and will crash with a mysterious "invalid descriptor" error
message.
Extend the list of special bindings to include
ScalarAllocatableAssignment and ScalarPointerAssignment, use them when
appropriate in the runtime type information tables, and handle them in
Assign() in the runtime support library.
The runtime API for copy-in copy-out currently only has an entry only
for the copy-out. This entry has a "skipInit" boolean that is never set
to false by lowering and it does not deal with the deallocation of the
temporary.
The generated code was a mix of inline code and runtime calls This is not a big deal,
but this is unneeded compiler and generated code complexity.
With assumed-rank, it is also more cumbersome to establish a
temporary descriptor.
Instead, this patch:
- Adds a CopyInAssignment API that deals with establishing the temporary
descriptor and does the copy.
- Removes unused arg to CopyOutAssign, and pushes
destruction/deallocation responsibility inside it.
Note that this runtime API are still not responsible for deciding the
need of copying-in and out. This is kept as a separate runtime call to
IsContiguous, which is easier to inline/replace by inline code with the
hope of removing the copy-in/out calls after user function inlining.
@vzakhari has already shown that always inlining all the copy part
increase Fortran compilation time due to loop optimization attempts for
loops that are known to have little optimization profitability (the
variable being copied from and to is not contiguous).
The runtime was currently only deallocating the direct allocatable
components, which caused leaks when there are allocatable components
nested in the direct components.
Update Destroy to recursively destroy components.
Also call Destroy from Assign to deallocate nested allocatable
components before doing the assignment as required by F2018 9.7.3.2
point 7.
This lack of deallocation was visible if the nested components had user
defined assignment "observing" the allocation state.
The general implementation of intrinsic assignment of derived types in
the runtime support library has a doubly-nested loop: an outer loop that
traverses the components and inner loops than traverse the array
elements. It's done this way to amortize the per-component overhead.
However, this turns out to be wrong when the program cares about the
order in which defined assignment subroutines are called; the Fortran
standard allows less latitude here than we need to invert the ordering
in this way when any component is itself an array. So invert the two
loops: traverse the array elements, and for each element, traverse its
components.
When a FINAL subroutine is being invoked for a discontiguous array, which can
happen for INTENT(OUT) dummy arguments and for some left-hand side variables
in intrinsic assignment statements, it may be the case that the subroutine
being called was defined with a dummy argument that requires contiguous data.
Extend the derived type descriptions used by the runtime to signify when
a special procedure binding requires contiguity; set the flags accordingly;
check them in the runtime support library, and, when necessary, use a
temporary shallow copy of the finalized array data in the call to the
final subroutine.
Differential Revision: https://reviews.llvm.org/D156760
When creating a temporary for conflicting LHS and RHS we have to deep copy
the dynamic (allocatable, automatic) components from RHS to the temp.
Otherwise, the conflict may still be present between LHS and temp.
gfortran/regression/alloc_comp_assign_1.f90 is an example where the current
runtime code produces wrong result:
7b5b5dcbf9/Fortran/gfortran/regression/alloc_comp_assign_1.f90 (L50)
Reviewed By: klausler, tblah
Differential Revision: https://reviews.llvm.org/D156364
Component-by-component assignment must be able to handle unallocated
allocatable values in structure constructor. F2018 7.5.10 p. 7 states
that the component must have unallocated status as a result of such
construction. The structure constructor temporary is initialized
such that all the allocatable components are unallocated, so we just
need to make sure not to do the component assignment if RHS is deallocated.
Depends on D152482 (the same LIT test is affected)
Reviewed By: jeanPerier, tblah
Differential Revision: https://reviews.llvm.org/D152493
The TODO was left there to verify that Assign() runtime handles
overlaps of allocatable components. It did not, and this change-set
fixes it. Note that the same Assign() issue can be reproduced
without HLFIR. In the following example the LHS would be reallocated
before value of RHS (essentially, the same memory) is read:
```
program main
type t1
integer, allocatable :: a(:)
end type t1
type(t1) :: x, y
allocate(x%a(10))
do i =1,10
x%a(i) = 2*i
end do
x = x
print *, x%a
deallocate(x%a)
end program main
```
The test's output would be incorrect (though, this depends on the memory
reuse by malloc):
0 0 0 0 10 12 14 16 18 20
It is very hard to add a Flang unittest exploiting derived types.
Reviewed By: klausler
Differential Revision: https://reviews.llvm.org/D152306
There are several observations regarding the copy-in/copy-out:
* Actual argument associated with INTENT(OUT) dummy argument that
requires finalization (7.5.6.3 p. 7) may be read by the finalization
function, so a copy-in is required.
* A temporary created for the copy-in/copy-out must be destroyed
without finalization after the call (or after the corresponding copy-out),
otherwise, memory leaks may occur.
* The copy-out assignment must not perform finalization for the LHS.
* The copy-out assignment from the temporary to the actual argument
may or may not need to initialize the LHS.
This change-set introduces new runtime methods: CopyOutAssign and
DestroyWithoutFinalization. They are called by the compiler generated
code to match the behavior described above.
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D151135
The temporary descriptor must be either Pointer or Allocatable,
otherwise its memory will not be freed.
Reviewed By: klausler
Differential Revision: https://reviews.llvm.org/D150534
If LHS is of derived type that needs initialization, then it must be
initialized before doing the assignment. Otherwise, the assignment
might behave incorrectly based on uninitialized components that are
descriptors themselves.
Differential Revision: https://reviews.llvm.org/D149681
One piece of pointer arithmetic was adding the number of bytes instead
of the number of characters. This caused failures in CHARACTER(KIND>1)
that required padding.
This was caught using HLFIR that currently uses the runtime for array
assignment where the current lowering does everything inline.
Reviewed By: vzakhari, klausler
Differential Revision: https://reviews.llvm.org/D149062
In the Fortran standard 2018 section 10.2.1.3 (13), it is mentioned
that all noncoarray allocatable component must follow this sequence of
operations:
1) If the component of the variable is allocated, it is deallocated.
2) If the component of the value of expr is allocated, the corresponding
component of the variable is allocated with the same dynamic type and
type parameters as the component of the value of expr. If it is an
array, it is allocated with the same bounds. The value of the
component of the value of expr is then assigned to the corresponding
component of the variable using defined assignment if the declared type
of the component has a type-bound defined assignment consistent with the
component, and intrinsic assignment for the dynamic type of that component
otherwise.
This patch updates the code to make use of the user defined assignment for
allocatable component and make sure the component is allocated correctly.
Reviewed By: klausler
Differential Revision: https://reviews.llvm.org/D147797
The code in DoElementalDefinedAssignment() needs to establish its
to & from per-element descriptors with Establish() rather than
copying an array's descriptor and then setting its rank to zero;
the current technique loses the information in the addendum.
Differential Revision: https://reviews.llvm.org/D145753
When the left-hand side of an allocatable assignment has an explicit character length,
rather than a deferred length that might imply reallocation, handle any discrepancy
in lengths via truncation or blank padding.
Differential Revision: https://reviews.llvm.org/D145111
This runtime API can be used to lower any flavor of array constructors,
but is mainly intended to be used with:
- array constructors for which the extent or length parameters cannot
be computed without lowering some ac-value or ac-implied-do-control
that cannot be pre-evaluated.
- array constructors of a derived type with allocatable component where
copy is not trivial or PDTS.
Example of use cases:
- `[((i+j,i=1, ifoo()), j=1,n)]` where ifoo() is not pure.
- `[return_allocatable_array(), return_allocatable_array()]`
Differential Revision: https://reviews.llvm.org/D144411
When the rhs is polymorphic and allocated during assignment, the
derivedType might have change from the one set in `toDerived`.
Use the one set in the addendum so it is always up to date.
This can happen in cases like the one shown below:
```
type :: t1
end type t1
type, extends(t1) :: t2
integer, allocatable :: i(:)
end type
subroutine assign(t)
class(t2), intent(in) :: t
class(t1), allocatable :: cp
cp = t
end subroutine
```
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D144171
When either descriptor argument to MayAlias() is not allocated, the
result must be false by definition, since the values of the extents
in the dimensional information may be uninitialized.
Differential Revision: https://reviews.llvm.org/D144134
Detect and handle LHS/RHS aliasing when effecting intrinsic
assignments via the Assign() runtime function.
Also: don't apply special handling for allocatable LHS when calling
a user-defined type-bound ASSIGNMENT(=) generic procedure for a
polymorphic type, and refactor some code into utility functions to
make Assign() more comprehensible.
Differential Revision: https://reviews.llvm.org/D144026
First call to Assign is issuing finalization for the
LHS and its components. Avoid calling finalization for components
again when doing the component by component assignment.
Reviewed By: klausler
Differential Revision: https://reviews.llvm.org/D143187
As Fortran 2018 9.7.1.2(7), the value of each element of allocate object
becomes the value of source when the allocate object is array and the
source is scalar.
Fix#60090.
Reviewed By: PeteSteinfeld
Differential Revision: https://reviews.llvm.org/D142112
Support allocate statement with source in runtime version. The source
expression is evaluated only once for each allocate statement. When the
source expression has shape-spec, uses it for bounds. Otherwise, get
the bounds from the source expression. Get the length if the source
expression has deferred length parameter.
Reviewed By: clementval, jeanPerier
Differential Revision: https://reviews.llvm.org/D137812
Component::CreatePointerDescriptor unconditionally expects a
vector of subscripts to be passed as an argument, but is called
from NAMELIST input with a null pointer. Make that argument
a nullable pointer, move it to the end of the argument list,
and give it a default value of nullptr.
Differential Revision: https://reviews.llvm.org/D113312
Move the closure of the subset of flang/runtime/*.h header files that
are referenced by source files outside flang/runtime (apart from unit tests)
into a new directory (flang/include/flang/Runtime) so that relative
include paths into ../runtime need not be used.
flang/runtime/pgmath.h.inc is moved to flang/include/flang/Evaluate;
it's not used by the runtime.
Differential Revision: https://reviews.llvm.org/D109107
Define an API for, and implement, runtime support for arbitrary
assignment of one descriptor's data to another, with full support for
(re)allocation of allocatables with finalization when necessary,
user-defined derived type assignment TBP calls, and intrinsic (default)
componentwise assignment of derived type instances with allocation of
automatic components. Also clean up API and implementation of
finalization/destruction using knowledge gained while studying
edge cases for assignment in the 2018 standard.
The look-up procedure for special procedure bindings in derived
types has been optimized from O(N) to O(1) since it will probably
matter more. This required some analysis in runtime derived type
description table construction in semantics and some changes to the
table schemata.
Executable Fortran tests have been developed; they'll be added
to the test base once they can be lowered and run by f18.
Differential Revision: https://reviews.llvm.org/D107678