Skip to content

Commit b12d2c8

Browse files
Implement copy-in/copy-out determination in Fortran::evaluate::MayNeedCopyInOut()
1 parent f76c9e3 commit b12d2c8

File tree

3 files changed

+157
-2
lines changed

3 files changed

+157
-2
lines changed

flang/include/flang/Evaluate/check-expression.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,5 +163,27 @@ extern template bool IsErrorExpr(const Expr<SomeType> &);
163163
std::optional<parser::Message> CheckStatementFunction(
164164
const Symbol &, const Expr<SomeType> &, FoldingContext &);
165165

166+
// Returns a pair of Booleans. The first boolean specifies whether given actual
167+
// argument may need copy-in operation and the second Boolean specifies whether
168+
// copy-out may be necessary. This function works with implicit interface
169+
// procedures.
170+
std::pair<bool, bool> MayNeedCopyInOut(const ActualArgument &,
171+
FoldingContext &);
172+
173+
// Returns a pair of Booleans. The first boolean specifies whether given actual
174+
// and dummy argument pair may need copy-in operation for the actual argument,
175+
// and the second Boolean specifies whether copy-out may be necessary.
176+
// This function works with explicit interface procedures.
177+
std::pair<bool, bool> MayNeedCopyInOut(const ActualArgument &,
178+
const characteristics::DummyArgument &, FoldingContext &);
179+
180+
inline std::pair<bool, bool> MayNeedCopyInOut(const ActualArgument &actual,
181+
const characteristics::DummyArgument *dummy, FoldingContext &fc) {
182+
if (dummy)
183+
return MayNeedCopyInOut(actual, *dummy, fc);
184+
else
185+
return MayNeedCopyInOut(actual, fc);
186+
}
187+
166188
} // namespace Fortran::evaluate
167189
#endif

flang/lib/Evaluate/check-expression.cpp

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,4 +1446,133 @@ std::optional<parser::Message> CheckStatementFunction(
14461446
return StmtFunctionChecker{sf, context}(expr);
14471447
}
14481448

1449+
std::pair<bool, bool> MayNeedCopyInOut(const ActualArgument &actual,
1450+
FoldingContext &fc) {
1451+
bool mayNeedCopyIn{false};
1452+
bool mayNeedCopyOut{false};
1453+
if (actual.isAlternateReturn()) {
1454+
return {mayNeedCopyIn, mayNeedCopyOut};
1455+
}
1456+
if (!evaluate::IsVariable(actual)) {
1457+
// Actual argument expressions that aren’t variables are copy-in, but
1458+
// not copy-out.
1459+
mayNeedCopyIn = true;
1460+
} else if (bool actualIsArray{actual.Rank() > 0};
1461+
actualIsArray && !IsSimplyContiguous(actual, fc)) {
1462+
// Actual arguments that are variables are copy-in when non-contiguous.
1463+
// They are copy-out when don't have vector subscripts
1464+
mayNeedCopyIn = true;
1465+
if (!HasVectorSubscript(actual)) {
1466+
mayNeedCopyOut = true;
1467+
}
1468+
} else if (ExtractCoarrayRef(actual)) {
1469+
// Coindexed actual args need copy-in and copy-out
1470+
mayNeedCopyIn = true;
1471+
mayNeedCopyOut = true;
1472+
}
1473+
1474+
return {mayNeedCopyIn, mayNeedCopyOut};
1475+
}
1476+
1477+
std::pair<bool, bool> MayNeedCopyInOut(const ActualArgument &actual,
1478+
const characteristics::DummyArgument &dummy, FoldingContext &fc) {
1479+
bool mayNeedCopyIn{false};
1480+
bool mayNeedCopyOut{false};
1481+
if (actual.isAlternateReturn()) {
1482+
return {mayNeedCopyIn, mayNeedCopyOut};
1483+
}
1484+
if (!evaluate::IsVariable(actual)) {
1485+
// Actual argument expressions that aren’t variables are copy-in, but
1486+
// not copy-out.
1487+
mayNeedCopyIn = true;
1488+
return {mayNeedCopyIn, mayNeedCopyOut};
1489+
}
1490+
const auto *dummyObj{std::get_if<characteristics::DummyDataObject>(&dummy.u)};
1491+
if (!dummyObj) {
1492+
// Only DummyDataObject has the information we need
1493+
return {mayNeedCopyIn, mayNeedCopyOut};
1494+
}
1495+
// Pass by value, always copy-in, never copy-out
1496+
bool dummyIsValue{
1497+
dummyObj->attrs.test(characteristics::DummyDataObject::Attr::Value)};
1498+
if (dummyIsValue) {
1499+
mayNeedCopyIn = true;
1500+
return {mayNeedCopyIn, mayNeedCopyOut};
1501+
}
1502+
// All the checks below are for arrays
1503+
1504+
bool actualIsAssumedRank{evaluate::IsAssumedRank(actual)};
1505+
bool actualIsArray{actualIsAssumedRank || actual.Rank() > 0};
1506+
bool dummyIsAssumedRank{dummyObj->type.attrs().test(
1507+
characteristics::TypeAndShape::Attr::AssumedRank)};
1508+
bool dummyIsArray{dummyIsAssumedRank || dummyObj->type.Rank() > 0};
1509+
bool treatDummyScalarAsArray{dummyObj->type.Rank() == 0 &&
1510+
dummyObj->ignoreTKR.test(common::IgnoreTKR::Rank)};
1511+
if (!actualIsArray || !(dummyIsArray || treatDummyScalarAsArray)) {
1512+
return {mayNeedCopyIn, mayNeedCopyOut};
1513+
}
1514+
1515+
bool dummyIntentIn{dummyObj->intent == common::Intent::In};
1516+
bool dummyIntentOut{dummyObj->intent == common::Intent::Out};
1517+
auto setCopyIn = [&]() {
1518+
if (!dummyIntentOut) {
1519+
// INTENT(OUT) dummy args never need copy-in
1520+
mayNeedCopyIn = true;
1521+
}
1522+
};
1523+
auto setCopyOut = [&]() {
1524+
if (!dummyIntentIn) {
1525+
// INTENT(IN) dummy args never need copy-out
1526+
mayNeedCopyOut = true;
1527+
}
1528+
};
1529+
1530+
// Check actual contiguity, unless dummy doesn't care
1531+
bool actualTreatAsContiguous{
1532+
dummyObj->ignoreTKR.test(common::IgnoreTKR::Contiguous) ||
1533+
IsSimplyContiguous(actual, fc)};
1534+
bool actualHasVectorSubscript{HasVectorSubscript(actual)};
1535+
bool dummyIsExplicitShape{dummyObj->type.IsExplicitShape()};
1536+
bool dummyIsAssumedSize{dummyObj->type.attrs().test(
1537+
characteristics::TypeAndShape::Attr::AssumedSize)};
1538+
bool dummyIsPolymorphic{dummyObj->type.type().IsPolymorphic()};
1539+
// Explicit shape and assumed size arrays must be contiguous
1540+
bool dummyNeedsContiguity{dummyIsExplicitShape || dummyIsAssumedSize ||
1541+
// Polymorphic dummy is descriptor based, so should be able to handle
1542+
// discontigunity.
1543+
(treatDummyScalarAsArray && !dummyIsPolymorphic) ||
1544+
dummyObj->attrs.test(characteristics::DummyDataObject::Attr::Contiguous)};
1545+
if (!actualTreatAsContiguous && dummyNeedsContiguity) {
1546+
setCopyIn();
1547+
// Cannot do copy-out for vector subscripts: there could be repeated
1548+
// indices, for example
1549+
if (!actualHasVectorSubscript) {
1550+
setCopyOut();
1551+
}
1552+
return {mayNeedCopyIn, mayNeedCopyOut};
1553+
}
1554+
1555+
bool dummyIsAssumedShape{dummyObj->type.attrs().test(
1556+
characteristics::TypeAndShape::Attr::AssumedShape)};
1557+
bool actualIsAssumedShape{IsAssumedShape(actual)};
1558+
if ((actualIsAssumedRank && dummyIsAssumedRank) ||
1559+
(actualIsAssumedShape && dummyIsAssumedShape)) {
1560+
// Assumed-rank and assumed-shape arrays are represented by descriptors,
1561+
// so don't need to do polymorphic check.
1562+
} else if (!dummyObj->ignoreTKR.test(common::IgnoreTKR::Type)) {
1563+
// flang supports limited cases of passing polymorphic to non-polimorphic.
1564+
// These cases require temporary of non-polymorphic type. (For example,
1565+
// the actual argument could be polymorphic array of child type,
1566+
// while the dummy argument could be non-polymorphic array of parent type.)
1567+
auto actualType{characteristics::TypeAndShape::Characterize(actual, fc)};
1568+
bool actualIsPolymorphic{actualType->type().IsPolymorphic()};
1569+
if (actualIsPolymorphic && !dummyIsPolymorphic) {
1570+
setCopyIn();
1571+
setCopyOut();
1572+
}
1573+
}
1574+
1575+
return {mayNeedCopyIn, mayNeedCopyOut};
1576+
}
1577+
14491578
} // namespace Fortran::evaluate

flang/lib/Lower/ConvertCall.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,8 +1243,12 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
12431243
passingPolymorphicToNonPolymorphic &&
12441244
(actual.isArray() || mlir::isa<fir::BaseBoxType>(dummyType));
12451245

1246-
bool mustDoCopyIn = actual.isArray() && arg.entity->GetMayNeedCopyIn();
1247-
bool mustDoCopyOut = mustDoCopyIn && arg.entity->GetMayNeedCopyOut();
1246+
Fortran::evaluate::FoldingContext &foldingContext{
1247+
callContext.converter.getFoldingContext()};
1248+
auto [suggestCopyIn, suggestCopyOut] = Fortran::evaluate::MayNeedCopyInOut(
1249+
*arg.entity, arg.characteristics, foldingContext);
1250+
bool mustDoCopyIn = actual.isArray() && suggestCopyIn;
1251+
bool mustDoCopyOut = mustDoCopyIn && suggestCopyOut;
12481252

12491253
const bool actualIsAssumedRank = actual.isAssumedRank();
12501254
// Create dummy type with actual argument rank when the dummy is an assumed

0 commit comments

Comments
 (0)