29
29
#include " flang/Optimizer/Builder/Todo.h"
30
30
#include " flang/Optimizer/Dialect/FIROpsSupport.h"
31
31
#include " flang/Optimizer/HLFIR/HLFIROps.h"
32
+ #include " mlir/IR/IRMapping.h"
32
33
#include " llvm/Support/CommandLine.h"
33
34
#include " llvm/Support/Debug.h"
34
35
#include < optional>
@@ -1619,37 +1620,33 @@ class ElementalCallBuilder {
1619
1620
for (unsigned i = 0 ; i < numArgs; ++i) {
1620
1621
auto &preparedActual = loweredActuals[i];
1621
1622
if (preparedActual) {
1622
- hlfir::Entity actual = preparedActual->getOriginalActual ();
1623
1623
// Elemental procedure dummy arguments cannot be pointer/allocatables
1624
1624
// (C15100), so it is safe to dereference any pointer or allocatable
1625
1625
// actual argument now instead of doing this inside the elemental
1626
1626
// region.
1627
- actual = hlfir:: derefPointersAndAllocatables (loc, builder, actual );
1627
+ preparedActual-> derefPointersAndAllocatables (loc, builder);
1628
1628
// Better to load scalars outside of the loop when possible.
1629
1629
if (!preparedActual->handleDynamicOptional () &&
1630
1630
impl ().canLoadActualArgumentBeforeLoop (i))
1631
- actual = hlfir:: loadTrivialScalar (loc, builder, actual );
1631
+ preparedActual-> loadTrivialScalar (loc, builder);
1632
1632
// TODO: merge shape instead of using the first one.
1633
- if (!shape && actual. isArray ()) {
1633
+ if (!shape && preparedActual-> isArray ()) {
1634
1634
if (preparedActual->handleDynamicOptional ())
1635
1635
optionalWithShape = &*preparedActual;
1636
1636
else
1637
- shape = hlfir:: genShape (loc, builder, actual );
1637
+ shape = preparedActual-> genShape (loc, builder);
1638
1638
}
1639
1639
// 15.8.3 p1. Elemental procedure with intent(out)/intent(inout)
1640
1640
// arguments must be called in element order.
1641
1641
if (impl ().argMayBeModifiedByCall (i))
1642
1642
mustBeOrdered = true ;
1643
- // Propagates pointer dereferences and scalar loads.
1644
- preparedActual->setOriginalActual (actual);
1645
1643
}
1646
1644
}
1647
1645
if (!shape && optionalWithShape) {
1648
1646
// If all array operands appear in optional positions, then none of them
1649
1647
// is allowed to be absent as per 15.5.2.12 point 3. (6). Just pick the
1650
1648
// first operand.
1651
- shape =
1652
- hlfir::genShape (loc, builder, optionalWithShape->getOriginalActual ());
1649
+ shape = optionalWithShape->genShape (loc, builder);
1653
1650
// TODO: There is an opportunity to add a runtime check here that
1654
1651
// this array is present as required. Also, the optionality of all actual
1655
1652
// could be checked and reset given the Fortran requirement.
@@ -1663,16 +1660,10 @@ class ElementalCallBuilder {
1663
1660
// intent(inout) arguments. Note that the scalar arguments are handled
1664
1661
// above.
1665
1662
if (mustBeOrdered) {
1666
- for (unsigned i = 0 ; i < numArgs; ++i) {
1667
- auto &preparedActual = loweredActuals[i];
1663
+ for (auto &preparedActual : loweredActuals) {
1668
1664
if (preparedActual) {
1669
- hlfir::Entity actual = preparedActual->getOriginalActual ();
1670
- if (!actual.isVariable () && actual.isArray ()) {
1671
- mlir::Type storageType = actual.getType ();
1672
- hlfir::AssociateOp associate = hlfir::genAssociateExpr (
1673
- loc, builder, actual, storageType, " adapt.impure_arg_eval" );
1674
- preparedActual->setOriginalActual (hlfir::Entity{associate});
1675
-
1665
+ if (hlfir::AssociateOp associate =
1666
+ preparedActual->associateIfArrayExpr (loc, builder)) {
1676
1667
fir::FirOpBuilder *bldr = &builder;
1677
1668
callContext.stmtCtx .attachCleanup (
1678
1669
[=]() { bldr->create <hlfir::EndAssociateOp>(loc, associate); });
@@ -1852,9 +1843,8 @@ class ElementalIntrinsicCallBuilder
1852
1843
if (intrinsic)
1853
1844
if (intrinsic->name == " adjustr" || intrinsic->name == " adjustl" ||
1854
1845
intrinsic->name == " merge" )
1855
- return hlfir::genCharLength (
1856
- callContext.loc , callContext.getBuilder (),
1857
- loweredActuals[0 ].value ().getOriginalActual ());
1846
+ return loweredActuals[0 ].value ().genCharLength (
1847
+ callContext.loc , callContext.getBuilder ());
1858
1848
// Character MIN/MAX is the min/max of the arguments length that are
1859
1849
// present.
1860
1850
TODO (callContext.loc ,
@@ -1874,7 +1864,7 @@ class ElementalIntrinsicCallBuilder
1874
1864
// the same declared and dynamic types. So any of them can be used
1875
1865
// for the mold.
1876
1866
assert (!loweredActuals.empty ());
1877
- return loweredActuals.front ()->getOriginalActual ( );
1867
+ return loweredActuals.front ()->getPolymorphicMold (callContext. loc );
1878
1868
}
1879
1869
1880
1870
return {};
@@ -2137,7 +2127,7 @@ genProcedureRef(CallContext &callContext) {
2137
2127
Fortran::lower::CallerInterface caller (callContext.procRef ,
2138
2128
callContext.converter );
2139
2129
mlir::FunctionType callSiteType = caller.genFunctionType ();
2140
-
2130
+ const bool isElemental = callContext. isElementalProcWithArrayArgs ();
2141
2131
Fortran::lower::PreparedActualArguments loweredActuals;
2142
2132
// Lower the actual arguments
2143
2133
for (const Fortran::lower::CallInterface<
@@ -2162,6 +2152,21 @@ genProcedureRef(CallContext &callContext) {
2162
2152
}
2163
2153
}
2164
2154
2155
+ if (isElemental && !arg.hasValueAttribute () &&
2156
+ Fortran::evaluate::IsVariable (*expr) &&
2157
+ Fortran::evaluate::HasVectorSubscript (*expr)) {
2158
+ // Vector subscripted arguments are copied in calls, except in elemental
2159
+ // calls without VALUE attribute where Fortran 2018 15.5.2.4 point 21
2160
+ // does not apply and the address of each element must be passed.
2161
+ hlfir::ElementalAddrOp elementalAddr =
2162
+ Fortran::lower::convertVectorSubscriptedExprToElementalAddr (
2163
+ loc, callContext.converter , *expr, callContext.symMap ,
2164
+ callContext.stmtCtx );
2165
+ loweredActuals.emplace_back (
2166
+ Fortran::lower::PreparedActualArgument{elementalAddr});
2167
+ continue ;
2168
+ }
2169
+
2165
2170
auto loweredActual = Fortran::lower::convertExprToHLFIR (
2166
2171
loc, callContext.converter , *expr, callContext.symMap ,
2167
2172
callContext.stmtCtx );
@@ -2178,7 +2183,7 @@ genProcedureRef(CallContext &callContext) {
2178
2183
// Optional dummy argument for which there is no actual argument.
2179
2184
loweredActuals.emplace_back (std::nullopt);
2180
2185
}
2181
- if (callContext. isElementalProcWithArrayArgs () ) {
2186
+ if (isElemental ) {
2182
2187
bool isImpure = false ;
2183
2188
if (const Fortran::semantics::Symbol *procSym =
2184
2189
callContext.procRef .proc ().GetSymbol ())
@@ -2189,6 +2194,27 @@ genProcedureRef(CallContext &callContext) {
2189
2194
return genUserCall (loweredActuals, caller, callSiteType, callContext);
2190
2195
}
2191
2196
2197
+ hlfir::Entity Fortran::lower::PreparedActualArgument::getActual (
2198
+ mlir::Location loc, fir::FirOpBuilder &builder) const {
2199
+ if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) {
2200
+ if (oneBasedElementalIndices)
2201
+ return hlfir::getElementAt (loc, builder, *actualEntity,
2202
+ *oneBasedElementalIndices);
2203
+ return *actualEntity;
2204
+ }
2205
+ assert (oneBasedElementalIndices && " expect elemental context" );
2206
+ hlfir::ElementalAddrOp elementalAddr =
2207
+ std::get<hlfir::ElementalAddrOp>(actual);
2208
+ mlir::IRMapping mapper;
2209
+ auto alwaysFalse = [](hlfir::ElementalOp) -> bool { return false ; };
2210
+ mlir::Value addr = hlfir::inlineElementalOp (
2211
+ loc, builder, elementalAddr, *oneBasedElementalIndices, mapper,
2212
+ /* mustRecursivelyInline=*/ alwaysFalse);
2213
+ assert (elementalAddr.getCleanup ().empty () && " no clean-up expected" );
2214
+ elementalAddr.erase ();
2215
+ return hlfir::Entity{addr};
2216
+ }
2217
+
2192
2218
bool Fortran::lower::isIntrinsicModuleProcRef (
2193
2219
const Fortran::evaluate::ProcedureRef &procRef) {
2194
2220
const Fortran::semantics::Symbol *symbol = procRef.proc ().GetSymbol ();
0 commit comments