The number of operations dedicated to CUF grew and where all still in
FIR. In order to have a better organization, the CUF operations,
attributes and code is moved into their specific dialect and files. CUF
dialect is tightly coupled with HLFIR/FIR and their types.
The CUF attributes are bundled into their own library since some
HLFIR/FIR operations depend on them and the CUF dialect depends on the
FIR types. Without having the attributes into a separate library there
would be a dependency cycle.
The HLFIR pass lowering WHERE (hlfir.where op) was too aggressive in its
hoisting of scalar sub-expressions from LHS/RHS/MASKS outside of the
loops generated for the WHERE construct.
This violated F'2023 10.2.3.2 point 10 that stipulated that elemental
operations must be evaluated only for elements corresponding to true
values, because scalar operations are still elemental, and hoisting them
is invalid if they could have side effects (e.g, division by zero) and
if the MASK is always false (i.e., the loop body is never evaluated).
The difficulty is that 10.2.3.2 point 9 mandates that nonelemental
function must be evaluated before the loops. So it is not possible to
simply stop hoisting non hlfir.elemental operations.
Marking calls with an elemental/nonelemental attribute would not allow
the pass to be correct if inlining is run before and drops this
information, beside, extracting the argument tree that may have been
CSE-ed with the rest of the expression evaluation would be a bit
combursome.
Instead, lower nonelemental calls into a new hlfir.exactly_once
operation that will allow retaining the information that the operations
contained inside its region must be hoisted. This allows inlining to
operate before if desired in order to improve alias analysis.
The LowerHLFIROrderedAssignments pass is updated to only hoist the
operations contained inside hlfir.exactly_once bodies.
This PR is to fix issue #88889 .
Because the type of an actual argument of an array expression of
character has type of `hlfir::ExprType`, we need to transform it to
`fir::SequenceType` before calling `getBoxTypeWithNewShape`.
Calling `hlfir::ExprType::getShape` inside of `getBoxTypeWithNewShape`
will introduce a circular dependency on FIRDialect and HLFIRDialect
libraries.
…ted. (#89998)" (#90250)
This partially reverts commit 7aedd7dc75.
This change removes calls to the deprecated member functions. It does
not mark the functions deprecated yet and does not disable the
deprecation warning in TypeSwitch. This seems to cause problems with
MSVC.
Fortran mandates "CHARACTER(1), VALUE" be passed as a C "char" in calls
to BIND(C) procedures (F'2023 18.3.7 (4)). Lowering passed them by
memory instead. Update call interface lowering code to pass them by
register. Fix related test and update it to use HLFIR.
The current lowering did not handle sequence associated argument passed
by descriptor. This case is special because sequence association implies
that the actual and dummy argument need to to agree in rank and shape.
Usually, arguments that can be sequence associated are passed by raw
address, and the shape mistmatch is transparent. But there are three
cases of explicit and assumed-size arrays passed by descriptors:
- polymorphic arguments
- BIND(C) assumed-length arguments (F'2023 18.3.7 (5)).
- length parametrized derived types (TBD)
The callee side is expecting a descriptor containing the dummy rank and
shape. This was not the case. This patch fix that by evaluating the
dummy shape on the caller side using the interface (that has to be
available when arguments are passed by descriptors).
Passing `TYPE(*)`actual to `TYPE(*)` dummy was left TODO. Implement it.
The difference with other actual arguments is that `TYPE(*)` are not
represented as Fortran::evaluate::Expr<T>, so inquiries on
evaluate::Expr<T> must be updated to use evaluate::ActualArgument or
also handle semantics::Symbol case (except in portion of the code where
`TYPE(*)` is impossible, where asserts are added).
This patch introduces a new `fir.cuda_kernel_launch` operation to
represents the call to CUDA kernels with the chervon notation. The
chevrons values in the parse tree can be scalar integer expr or dim3
derived type. The operation describes the grid/block values explicitly
as i32 values.
It lowers the parse-tree call to this new operation.
Flang crashes with the following case. The problem is we missed the case
when passing a reference to a function that returns a procedure pointer
as actual that corresponds to a procedure dummy. This PR is to fix that.
```
PROGRAM main
IMPLICIT NONE
INTERFACE
FUNCTION IntF(Arg)
integer :: Arg, IntF
END FUNCTION
END INTERFACE
INTERFACE
FUNCTION RetPtr(Arg)
IMPORT
PROCEDURE(IntF) :: Arg
PROCEDURE(IntF), POINTER :: RetPtr
END FUNCTION
END INTERFACE
CALL ModSub(RetPtr(IntF))
contains
SUBROUTINE ModSub(Fun1)
PROCEDURE(IntF) :: Fun1
END SUBROUTINE
END
```
Fortran requires finalizing function results when the result type have
final procedures.
Lowering was unconditionally "moving" function results into values
"hlfir.expr". This is not correct when the results are finalized because
it means the function result storage will be used after the hlfir.expr.
Only move function results that are not finalized.
Procedure pointer lowering used `prepareUserCallActualArgument` because
it was convenient, but this helper was not meant for POINTERs when
originally written and it did not handled passing NULL to an OPTIONAL
procedure pointer correctly.
The resulting argument should be a disassociated pointer, not an absent
pointer (Fortran 15.5.2.12 point 1.).
Move the logic for procedure pointer argument "cooking" in its own
helper to avoid triggering the logic that created an absent argument in
this case.
This PR adds lowering the reference to a function that returns a
procedure pointer. It also fixed intrinsic ASSOCIATED to take such
argument.
---------
Co-authored-by: jeanPerier <jperier@nvidia.com>
Start implementing assumed-rank support as described in
https://github.com/llvm/llvm-project/blob/main/flang/docs/AssumedRank.md
This commit holds the minimal support for lowering calls to procedure
with assumed-rank arguments where the procedure implementation is done
in C.
The case for passing assumed-size to assumed-rank is left TODO since it
will be done a change in assumed-size lowering that is better done in
another patch.
Care is taken to set the lower bounds to zero when passing non allocatable no pointer as descriptor
to a BIND(C) procedure as required per 18.5.3 point 3. This was not done before while the requirements also applies to non assumed-rank descriptors. This change required special attention with IGNORE_TKR(t) to avoid emitting invalid fir.rebox operations (the actual argument type must be used in this case as the output type).
Implementation of Fortran procedure with assumed-rank arguments is still
TODO.
This is a lot less complex than the data case where the shape has to be
accounted for, so the implementation is done inline.
One corner case will not be supported correctly for now: the case where
POINTER and TARGET points to the same internal procedure may return
false because lowering is creating fir.embox_proc each time the address
of an internal procedure is taken, so different thunk for the same
internal procedure/host link may be created and compare to false. This
will be fixed in a later patch that moves creating of internal procedure
fir.embox_proc in the host so that the addresses are the same when the
host link is the same. This change is required to properly support the
required lifetime of internal procedure addresses anyway (should be the
always be the lifetime of the host, even when the address is taken in an
internal procedure).
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::factory::genFinalization` and
`fir::factory::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