Lower procedure pointer components, except in the context of structure
constructor (left TODO).
Procedure pointer components lowering share most of the lowering logic
of procedure poionters with the following particularities:
- They are components, so an hlfir.designate must be generated to
retrieve the procedure pointer address from its derived type base.
- They may have a PASS argument. While there is no dispatching as with
type bound procedure, special care must be taken to retrieve the derived
type component base in this case since semantics placed it in the
argument list and not in the evaluate::ProcedureDesignator.
These components also bring a new level of recursive MLIR types since a
fir.type may now contain a component with an MLIR function type where
one of the argument is the fir.type itself. This required moving the
"derived type in construction" stackto the converter so that the object
and function type lowering utilities share the same state (currently the
function type utilty would end-up creating a new stack when lowering its
arguments, leading to infinite loops). The BoxedProcedurePass also
needed an update to deal with this recursive aspect.
VALUE derived type are passed by reference outside of BIND(C) interface.
The ABI is much simpler and it is possible for these arguments to have
the OPTIONAL attribute.
In the BIND(C) context, these arguments must follow the C ABI for
struct, which may lead the data to be passed in register. OPTIONAL is
also forbidden for those arguments, so it is safe to directly use the
fir.type<T> type for the func.func argument.
Codegen is in charge of later applying the C passing ABI according to
the target (https://github.com/llvm/llvm-project/pull/74829).
This patch is fixing two issue relative to the dynamic dispatch for
polymorphic entities.
1. Fix the `requireDispatchCall` function. It was checking for the first
symbol of the component but this is not the one to be checked. Instead
the last symbol of the base of the component object is the one to check
to know if it is polymorphic object with a dispatch call or not. This is
demonstrated in the new added test in `flang/test/Lower/dispatch.f90`
where the first symbol would point to `q` which is monomorphic and would
result in a simple `fir.call`
2. Fix the pass object in a no pass situation. In a no pass situation
the pass object is lowered anyway to be able to do the lookup in the
binding table. It was previously lowered wrongly an lead to unresolved
lookup. The base of the component is the passed object and should be
lowered. To achieve this, the `gen(DataRef)` entry point is exposed form
`ConvertExprToHLFIR` through a `convertDataRefToValue` function. The
same test added in `flang/test/Lower/dispatch.f90` is checking for the
correct passed object.
In addition couple of tests were updated to HLFIR since the lowering
used only works with it.
This got "lost" in the HLFIR transformation. This patch applies the old
attribute to the AssociateOp that needs it, and forwards it to the
AllocaOp that is generated when lowering to FIR.
**Scope of the PR:**
1. Lowering global and local procedure pointer declaration statement
with explicit or implicit interface. The explicit interface can be from
an interface block, a module procedure or an internal procedure.
2. Lowering procedure pointer assignment, where the target procedure
could be external, module or internal procedures.
3. Lowering reference to procedure pointers so that it works end to end.
**PR notes:**
1. The first commit of the PR does not include testing. I would like to
collect some comments first, which may alter the output. Once I confirm
the implementation, I will add some testing as a follow up commit to
this PR.
2. No special handling of the host-associated entities when an internal
procedure is the target of a procedure pointer assignment in this PR.
**Implementation notes:**
1. The implementation is using the HLFIR path.
2. Flang currently uses `getUntypedBoxProcType` to get the
`fir::BoxProcType` for `ProcedureDesignator` when getting the address of
a procedure in order to pass it as an actual argument. This PR inherits
the same design decision for procedure pointer as the `fir::StoreOp`
requires the same memory type.
Note: this commit is actually resubmitting the original commit from
PR #70461 that was reverted. See PR #73221.
**Scope of the PR:**
1. Lowering global and local procedure pointer declaration statement
with explicit or implicit interface. The explicit interface can be from
an interface block, a module procedure or an internal procedure.
2. Lowering procedure pointer assignment, where the target procedure
could be external, module or internal procedures.
3. Lowering reference to procedure pointers so that it works end to end.
**PR notes:**
1. The first commit of the PR does not include testing. I would like to
collect some comments first, which may alter the output. Once I confirm
the implementation, I will add some testing as a follow up commit to
this PR.
2. No special handling of the host-associated entities when an internal
procedure is the target of a procedure pointer assignment in this PR.
**Implementation notes:**
1. The implementation is using the HLFIR path.
2. Flang currently uses `getUntypedBoxProcType` to get the
`fir::BoxProcType` for `ProcedureDesignator` when getting the address of
a procedure in order to pass it as an actual argument. This PR inherits
the same design decision for procedure pointer as the `fir::StoreOp`
requires the same memory type.
When attempting to lower an intrinsic module procedure call, take into
account bind(c). Such procedures cannot be lowered as intrinsics since
their implementation is external to the module.
With this solution, the hardcoded "omp_lib" string can be removed when
checking if intrinsic module procedure since all procedure interfaces in
that module use bind(c).
In case of small interface mismatches between a function on the caller
and callee side, lowering insert converts. These are very often no-ops
at runtime (casting a descriptor to a descriptor), but they matter in
the strongly type IR.
The IR type of an object argument of a fir.dispatch must be the one of
the object, not the one of the callee side dummy, which may differ in
case of mismatches. Otherwise, the codgeneration of fir.dispatch cannot
succeed (it will not access the right binding tables).
I missed that vector subscripted arguments must still be passed by
address in an elemental call where the dummy argument does not have
the VALUE attribute.
Update PreparedActualArgument to hold an hlfir::Entity or an
hlfir::ElementalOp and to inline the elementalOp body in `getActual`.
…result.
If function result have allocatable components or components that may
require finalization, we have to call Destroy runtime for them. We also
have to free the top-level entity's memory regardless of whether we
called Destroy or not.
PowerPC Vector type intrinsics currently crashes with
`-flang-experimental-hlfir` is specified.
This patch is to fix the HLFIR path for PowerPC Vector type intrinsics.
The patch:
1. Added the `flang-experimental-hlfir` option to all PowerPC vector intrinsic testing.
2. Removed the FIR/MLIR testing to reduce the maintenance cost.
3. Fixed a few verification IR for some non-functional changes in LLVM IR in HLFIR path.
This set of commits resolves some of the issues with elemental calls producing
results that may require finalization, and also some memory leak issues due to
the missing deallocation of allocatable components of the temporary buffers
created by the bufferization pass.
- [flang][runtime] Expose Finalize API for derived types.
- [flang][hlfir] Add 'finalize' attribute for DestroyOp.
- [flang][hlfir] Postpone result finalization for elemental calls.
The results of elemental calls generated inside hlfir.elemental must not
be finalized/destructed before they are copied into the resulting
array. The finalization must be done on the array as a whole
(e.g. there might be different scalar and array finalization routines).
The finalization work is left to the hlfir.destroy corresponding
to this hlfir.elemental.
- [flang][hlfir] Tighten requirements on hlfir.end_associate operand.
If component deallocation might be required for the operand of
hlfir.end_associate, we have to be able to get the variable
shape/params to create a descriptor for calling the runtime.
This commit adds verification that we can do so.
- [flang][hlfir] Lower argument clean-ups using valid hlfir.end_associate.
The operand must be a Fortran entity, when allocatable component
deallocation may be required.
- [flang][hlfir] Properly clean-up temporary buffers in bufferization pass.
This commit combines changes for proper finalization and component
deallocation of the temporary buffers. The finalization part
relates to hlfir.destroy operations with 'finalize' attribute.
The component deallocation might be invoked for both hlfir.destroy
and hlfir.end_associate, if the operand is of a derived type
with allocatable component(s).
The changes are mostly in one function, so I decided not to split them.
- [flang][hlfir] Disable optimizations for hlfir.elemental requiring finalization.
If hlfir.elemental is coupled with hlfir.destroy with 'finalize' attribute,
the temporary array result of hlfir.elemental needs to be created
for the purpose of finalization. We cannot do certain optimizations
on such hlfir.elemental operations.
I was not able to come up with a test for the OptimizedBufferization pass,
but I put the check there as well.
There are currently several places that automatically deallocate
allocatble if they are allocated:
- INTENT(OUT) allocatable are deallocated on entry in the callee
- INTENT(OUT) allocatable are also deallocated on the caller side of
BIND(C) function in case the implementation is in C.
- Results of function returning allocatable are deallocated after usage.
- OPENMP privatized allocatable are deallocated at the end of OPENMP
region.
Introduce genDeallocateIfAllocated that centralize all this code, except
for the function return that use genFreememIfAllocated since
finalization is done separately currently.
`fir:🏭:genFinalization` and
`fir:🏭:genInlinedDeallocation` are removed and replaced by
genFreemem since their name were misleading: finalization was not
called.
There is a fallout in the tests because previous generated code did not
check the allocated status when doing inline deallocation. This was OK
since free(null) is guaranteed to be a no-op, but this makes compiler
code more complex, is a bit surprising in the generated IR IMHO, and it
relied on knowing when genDeallocateBox inserts runtime calls or uses
inlined code.
The POINTER= and TARGET= arguments to the intrinsic function
ASSOCIATED() can be the results of references to functions that return
object pointers or procedure pointers. NULL() was working well but not
program-defined pointer-valued functions. Correct the validation of
ASSOCIATED() and extend the infrastructure used to detect and
characterize procedures and pointers.
The actual polymorphic expression argument that is passed to a non-polymorphic
contiguous dummy has to be made a contiguous entity with the dynamic type
matching the declared type of the dummy argument.
The solution is to associate the expression with a temporary of the dynamic
type of the expression, then rebox the temporary to the declared type
of the dummy argument, and then, if necessary, make copy-in into another
temporary that is, finally, a contiguous entity with the required dynamic type.
With this change a single prepared argument may have up to two associated
clean-ups, so I had to change the clean-ups handling.
Reviewed By: tblah
Differential Revision: https://reviews.llvm.org/D157464
Pass the first argument as the polymorphic mold for the generated
hlfir.elemental.
Depends on D157316
Reviewed By: tblah, clementval
Differential Revision: https://reviews.llvm.org/D157317
These should be lowered with genOptionalValue as in D154897, but I
haven't found any cases where this code path is actually hit (flang
tests, gfortran test suite), so I don't think it would be testable.
Adding an assertion for if this code path ever becomes live.
Differential Revision: https://reviews.llvm.org/D155477
The previous code path created the elemental kernel by generating a
scalar intrinsic call using pre-prepared arguments using genIntrinsicRefCore,
which then generated the intrinsic call using genIntrinsicCall().
The problem with this approach was that the dynamically optional
arguments were marked as having no argLowering, which meant that they
were unconditionally passed by value without any check to see if they
were present.
It would be nice to put an if operation in the path for !argLowering,
doing something similar to genOptionalValue(). However, this can't be
done because it isn't clear what value should be used for the default.
If zero was used (like in genOptionalValue) this could effect the result
of MIN or MAX.
Instead, this patch re-uses the implementation for scalar dynamically
optional arguments (in non-elemental calls). This does the correct
thing, entirely ignoring absent optional arguments.
Depends On: D155292
Differential Revision: https://reviews.llvm.org/D155293
Only minimal argument processing is needed here because they will be
lowered properly either by the elemental intrinsic call builder or the
lowering of the scalar call inside the elemental kernel.
Dynamically optional arrays are coming in the next patch.
Depends On: D155291
Differential Revision: https://reviews.llvm.org/D155292
In the context of elemental operation a dynamically optional
intrinsic argument must be lowered such that the elemental
designator is generated under isPresent check.
Reviewed By: tblah
Differential Revision: https://reviews.llvm.org/D154897
This patch implements HLFIR lowering for associating an actual
TARGET argument to a dummy POINTER argument.
Reviewed By: tblah, jeanPerier
Differential Revision: https://reviews.llvm.org/D154311
genElementalCall can return a null option when lowering elemental
subroutine calls (as there is no return value). Therefore
std::option::value should not be used as it will cause an
assertion failure.
This fixes uses of the mvbits intrinsic with array arguments, as used in
the gfortran test suite.
Differential Revision: https://reviews.llvm.org/D154340
This adds support for dynamically optional arguments for intrinsics
which do not have their own hlfir operations.
The functions for processing these arguments are mostly the same as the
equivalent functions in ConvertExpr.cpp. I chose not to share
implementations so that HLFIR helpers can be used here. Presumably
ConvertExpr.cpp will go away one day.
Depends on D154236
Differential Revision: https://reviews.llvm.org/D154237
The old code had overgrown itself and become difficult to read and
modify. I've rewritten it and moved it into its own translation unit.
I moved PreparedActualArgument to the header file for the
transformational intrinsic lowering. Logically, it belongs in
ConvertCall.h, but putting it there would create a circular dependency
between HlfirIntrinsics and ConvertCall.
Differential Revision: https://reviews.llvm.org/D154235
Actual argument expressions must be evaluated before the invocation
of the sequence of per-element calls of an impure elemental subprogram.
Otherwise, the side effects of the calls may affect the input for
the consequent elements.
The proposed changes are described by Jean in D154174.
Reviewed By: tblah
Differential Revision: https://reviews.llvm.org/D154263
HLFIR lowering was currently hitting errors like "not yet implemented:
intrinsic: z0$iso_c_binding$c_associated_c_ptr". These error were caused
by HLFIR lowering using the name with the full context instead of
the ultimate one.
I do not want to change proc.GetName() because I think it may be best
if it retains the full context for its usages in semantics, so I fixed
the helper to get the name in lowering to HLFIR.
Differential Revision: https://reviews.llvm.org/D154230
This patch adds 'unordered' attribute handling the HLFIR elementals'
builders and fixes the attribute handling in lowering and transformations.
Depends on D154031, D154032
Reviewed By: jeanPerier, tblah
Differential Revision: https://reviews.llvm.org/D154035
This patch sets `unordered` `fir.do_loop` attribute during lowering
of elemental subroutine calls to HLFIR, when it is safe to do so.
Proper handling of `hlfir.elemental` will be done in a separate patch.
Reviewed By: jeanPerier, tblah
Differential Revision: https://reviews.llvm.org/D154031
This patch implements the lowering for the `hlfir.char_extremum` operation.
Discussion for this patch can be found in the draft patch [here](https://reviews.llvm.org/D143326). The reason
for not promoting this draft to a true patch for review was because I needed to separate the op
definition/codegen and lowering into two separate patches, as preferred by @jeanPerier.
Depends on D152474
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D152475
Lower user defined assignment inside the hlfir.region_assign
"userDefinedAssignment" mlir region.
This is done by adding an entry point to ConvertCall.h in order
to call genUserCall with the region block arguments as arguments.
The codegen for hlfir.region_assign with user defined assignment
will be added in a later patch.
Differential Revision: https://reviews.llvm.org/D153404
Adds a new HLFIR operation for the COUNT intrinsic according to
the design set out in flang/docs/HighLevel.md. This patch includes all
the necessary changes to create a new HLFIR operation and lower it into
the fir runtime call.
Author was @jacob-crawley. Minor adjustments by @tblah
Differential Revision: https://reviews.llvm.org/D152521
Adds a new HLFIR operation for the DOT_PRODUCT intrinsic according to
the design set out in flang/docs/HighLevel.md. This patch includes all
the necessary changes to create a new HLFIR operation and lower it into
the fir runtime call.
Differential Revision: https://reviews.llvm.org/D152252
The copy must made according to the actual type, not the dummy type. In
case the dummy is polymorphic, these types will be different and the
dynamic type of the copy passed in the call should be the one of the
actual.
There is no support for "class(t), value" yet (it is hitting a TODO in
CallInterface that is moot for HLFIR but has not been lifted for lack of
proper testing) so the bug was dormant, but D151271 created a situation
where a copy is needed with polymorphic dummies and exposed the bug.
This led to a compile time assert
"value.isScalar() && fir::isa_trivial(value.getType())" in "hlfir::genAssociateExpr".
Differential Revision: https://reviews.llvm.org/D151413
Even though the constant expression actual argument is not definable,
and the associated dummy argument is not definable, the compiler may produce
implicit copies into the memory storage associated with the constant expression.
For example, a constant expression storage passed by reference to a subprogram
may be used for implicit copy-out:
```
subroutine sub(i, n)
interface
subroutine sub2(i)
integer :: i(*)
end subroutine sub2
end interface
integer :: i(n)
call sub2(i(3::2)) ! copy-out after the call will write to 'i'
end subroutine sub
subroutine test
call sub((/1,2,3,4,5/), 5)
end subroutine test
```
If we pass a reference to constant expression storage to 'sub' directly,
the copy-out inside 'sub' will try to write into readonly memory.
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D151271
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
Reboxing of the actual argument according to the type of the dummy
argument has to be aware of the potential rank mismatch, when
IGNORE_TKR(R) is used. This change only adds support for the mismatching
rank when the dummy argument has unlimited polymorphic type.
Reviewed By: jeanPerier
Differential Revision: https://reviews.llvm.org/D151016
Comments in the recent patch https://reviews.llvm.org/D149964,
mentioned that using hlfir_ExprType in cases where intrinsics
return simple scalars adds unnecessary abstraction that isn't
needed unless an array type is being used.
This patch modifies the HLFIR operations for product, sum and any
so that they only return a hlfir_ExprType when the result is an array,
otherwise they will return just the simple scalar type.
Differential Revision: https://reviews.llvm.org/D150877
Fortran doesn't allow inaccessible procedure bindings to be
overridden, and this needs to apply to generic resolution.
When resolving a type-bound generic procedure from another
module, ensure only that the most extended override from its
module is used if it is PRIVATE, not a later apparent override
from another module.
Differential Revision: https://reviews.llvm.org/D150721