[flang-commits] [flang] [flang][DRAFT] Copy-in/Copy-out determination (PR #151408)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Thu Aug 7 09:10:34 PDT 2025
https://github.com/eugeneepshteyn updated https://github.com/llvm/llvm-project/pull/151408
>From 54c0158dcce9b5ebb6a3658298dedcda72b41f52 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 17:08:06 -0400
Subject: [PATCH 01/15] [flang][DRAFT] Copy-in/Copy-out determination
Plumbing/API for copy-in/copy-out
---
flang/include/flang/Evaluate/call.h | 19 +++++++++++++++++--
flang/lib/Evaluate/call.cpp | 16 ++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index 2a5929b873d74..ac11527e4ecaa 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -52,7 +52,7 @@ using SymbolRef = common::Reference<const Symbol>;
class ActualArgument {
public:
- ENUM_CLASS(Attr, PassedObject, PercentVal, PercentRef);
+ ENUM_CLASS(Attr, PassedObject, PercentVal, PercentRef, CopyIn, CopyOut);
using Attrs = common::EnumSet<Attr, Attr_enumSize>;
// Dummy arguments that are TYPE(*) can be forwarded as actual arguments.
@@ -131,7 +131,6 @@ class ActualArgument {
return *this;
}
- bool Matches(const characteristics::DummyArgument &) const;
common::Intent dummyIntent() const { return dummyIntent_; }
ActualArgument &set_dummyIntent(common::Intent intent) {
dummyIntent_ = intent;
@@ -161,6 +160,20 @@ class ActualArgument {
return *this;
}
+ // This actual argument may need copy-in before the procedure call
+ bool mayNeedCopyIn() const { return attrs_.test(Attr::CopyIn); };
+ ActualArgument &set_mayNeedCopyIn() {
+ attrs_ = attrs_ + Attr::CopyIn;
+ return *this;
+ }
+
+ // This actual argument may need copy-out after the procedure call
+ bool mayNeedCopyOut() const { return attrs_.test(Attr::CopyOut); };
+ ActualArgument &set_mayNeedCopyOut() {
+ attrs_ = attrs_ + Attr::CopyOut;
+ return *this;
+ }
+
private:
// Subtlety: There is a distinction that must be maintained here between an
// actual argument expression that is a variable and one that is not,
@@ -272,6 +285,8 @@ class ProcedureRef {
bool operator==(const ProcedureRef &) const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
+ void DetermineCopyInOut();
+
protected:
ProcedureDesignator proc_;
ActualArguments arguments_;
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index f77df92a7597a..1e582a516a694 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -13,6 +13,7 @@
#include "flang/Evaluate/expression.h"
#include "flang/Evaluate/tools.h"
#include "flang/Semantics/symbol.h"
+#include "flang/Semantics/semantics.h"
#include "flang/Support/Fortran.h"
namespace Fortran::evaluate {
@@ -247,4 +248,19 @@ ProcedureRef::~ProcedureRef() {}
void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
+void ProcedureRef::DetermineCopyInOut() {
+ if (!proc().GetSymbol()) {
+ return;
+ }
+ // Get folding context of the call site owner
+ FoldingContext &fc{proc_.GetSymbol()->owner().context().foldingContext()};
+ auto procInfo{characteristics::Procedure::Characterize(
+ proc(), fc, /*emitError=*/false)};
+ if (!procInfo) {
+ return;
+ }
+ // TODO: at this point have dummy arguments as procInfo->dummyArguments
+ // and have actual arguments via arguments_
+}
+
} // namespace Fortran::evaluate
>From 808fb20c3e4d6dc80b7e3793fb28b4f7854b07f8 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 17:44:37 -0400
Subject: [PATCH 02/15] Call DetermineCopyInOut() from lowering
---
flang/include/flang/Lower/CallInterface.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h
index 72bc9dd890a94..eca697d474c47 100644
--- a/flang/include/flang/Lower/CallInterface.h
+++ b/flang/include/flang/Lower/CallInterface.h
@@ -284,6 +284,9 @@ class CallerInterface : public CallInterface<CallerInterface> {
CallerInterface(const Fortran::evaluate::ProcedureRef &p,
Fortran::lower::AbstractConverter &c)
: CallInterface{c}, procRef{p} {
+ // Ensure that procRef gathers necessary information to determine the
+ // need for copy-in and copy-out
+ const_cast<Fortran::evaluate::ProcedureRef &>(procRef).DetermineCopyInOut();
declare();
mapPassedEntities();
actualInputs.resize(getNumFIRArguments());
>From 28bc5bd95f83f131c4a905f69e402fc97a1b7e9d Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 18:20:23 -0400
Subject: [PATCH 03/15] clang-format
---
flang/lib/Evaluate/call.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 1e582a516a694..0cfad4cfae17e 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -12,8 +12,8 @@
#include "flang/Evaluate/check-expression.h"
#include "flang/Evaluate/expression.h"
#include "flang/Evaluate/tools.h"
-#include "flang/Semantics/symbol.h"
#include "flang/Semantics/semantics.h"
+#include "flang/Semantics/symbol.h"
#include "flang/Support/Fortran.h"
namespace Fortran::evaluate {
>From f44b9459f6e2c0f60d6f66d00ec37d383befe021 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 19:54:01 -0400
Subject: [PATCH 04/15] DetermineCopyInOut() is now called from ProcedureRef
constructor
---
flang/include/flang/Evaluate/call.h | 8 ++++++--
flang/include/flang/Lower/CallInterface.h | 3 ---
flang/lib/Evaluate/call.cpp | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index ac11527e4ecaa..56338901b22bb 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -248,7 +248,11 @@ class ProcedureRef {
ProcedureRef(ProcedureDesignator &&p, ActualArguments &&a,
bool hasAlternateReturns = false)
: proc_{std::move(p)}, arguments_{std::move(a)},
- hasAlternateReturns_{hasAlternateReturns} {}
+ hasAlternateReturns_{hasAlternateReturns} {
+ // Gathers necessary information to determine the need for copy-in and
+ // copy-out
+ DetermineCopyInOut();
+ }
~ProcedureRef();
static void Deleter(ProcedureRef *);
@@ -285,9 +289,9 @@ class ProcedureRef {
bool operator==(const ProcedureRef &) const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
+protected:
void DetermineCopyInOut();
-protected:
ProcedureDesignator proc_;
ActualArguments arguments_;
Chevrons chevrons_;
diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h
index eca697d474c47..72bc9dd890a94 100644
--- a/flang/include/flang/Lower/CallInterface.h
+++ b/flang/include/flang/Lower/CallInterface.h
@@ -284,9 +284,6 @@ class CallerInterface : public CallInterface<CallerInterface> {
CallerInterface(const Fortran::evaluate::ProcedureRef &p,
Fortran::lower::AbstractConverter &c)
: CallInterface{c}, procRef{p} {
- // Ensure that procRef gathers necessary information to determine the
- // need for copy-in and copy-out
- const_cast<Fortran::evaluate::ProcedureRef &>(procRef).DetermineCopyInOut();
declare();
mapPassedEntities();
actualInputs.resize(getNumFIRArguments());
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 0cfad4cfae17e..c558335c16545 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -255,7 +255,7 @@ void ProcedureRef::DetermineCopyInOut() {
// Get folding context of the call site owner
FoldingContext &fc{proc_.GetSymbol()->owner().context().foldingContext()};
auto procInfo{characteristics::Procedure::Characterize(
- proc(), fc, /*emitError=*/false)};
+ proc_, fc, /*emitError=*/true)};
if (!procInfo) {
return;
}
>From ffd65635da52fb2788056113b9fa3bdf2d430436 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 19:57:40 -0400
Subject: [PATCH 05/15] clang-format
---
flang/lib/Evaluate/call.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index c558335c16545..5a94071d9bf20 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -254,8 +254,8 @@ void ProcedureRef::DetermineCopyInOut() {
}
// Get folding context of the call site owner
FoldingContext &fc{proc_.GetSymbol()->owner().context().foldingContext()};
- auto procInfo{characteristics::Procedure::Characterize(
- proc_, fc, /*emitError=*/true)};
+ auto procInfo{
+ characteristics::Procedure::Characterize(proc_, fc, /*emitError=*/true)};
if (!procInfo) {
return;
}
>From fb3a93c6da7f34110734f606e795533b83ff1562 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 30 Jul 2025 22:39:44 -0400
Subject: [PATCH 06/15] Minor tweak
---
flang/lib/Evaluate/call.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 5a94071d9bf20..605931d5d6dfb 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -249,7 +249,7 @@ ProcedureRef::~ProcedureRef() {}
void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
void ProcedureRef::DetermineCopyInOut() {
- if (!proc().GetSymbol()) {
+ if (!proc_.GetSymbol()) {
return;
}
// Get folding context of the call site owner
>From 527b2d7646ca11a4fa9921695b4efd360a9c5b54 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Thu, 31 Jul 2025 13:32:10 -0400
Subject: [PATCH 07/15] DetermineCopyInOut() is now called at ProcedureRef
instantiation
---
flang/include/flang/Evaluate/call.h | 5 +----
flang/lib/Semantics/expression.cpp | 1 +
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index 56338901b22bb..3d4f791380fba 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -249,9 +249,6 @@ class ProcedureRef {
bool hasAlternateReturns = false)
: proc_{std::move(p)}, arguments_{std::move(a)},
hasAlternateReturns_{hasAlternateReturns} {
- // Gathers necessary information to determine the need for copy-in and
- // copy-out
- DetermineCopyInOut();
}
~ProcedureRef();
static void Deleter(ProcedureRef *);
@@ -289,9 +286,9 @@ class ProcedureRef {
bool operator==(const ProcedureRef &) const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
-protected:
void DetermineCopyInOut();
+protected:
ProcedureDesignator proc_;
ActualArguments arguments_;
Chevrons chevrons_;
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 92dbe0e5da11c..29917a570ddc5 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3455,6 +3455,7 @@ void ExpressionAnalyzer::Analyze(const parser::CallStmt &callStmt) {
HasAlternateReturns(callee->arguments)},
ProcedureRef::Deleter);
DEREF(callStmt.typedCall.get()).set_chevrons(std::move(*chevrons));
+ DEREF(callStmt.typedCall.get()).DetermineCopyInOut();
return;
}
}
>From 9c1755b248f4fe7b38547af5ee74563cfdcd6753 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Thu, 31 Jul 2025 22:01:17 -0400
Subject: [PATCH 08/15] Very rough beginnings of argument handling in
DetermineCopyInOut()
---
flang/lib/Evaluate/call.cpp | 61 +++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 605931d5d6dfb..6f604d2aed28b 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -248,6 +248,23 @@ ProcedureRef::~ProcedureRef() {}
void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
+// We don't know the dummy argument info (e.g., procedure with implicit
+// interface
+static void DetermineCopyInOutArgument(
+ const characteristics::Procedure &procInfo, ActualArgument &actual) {
+
+ // Only check that actual argument is contiguous
+ // For non-contiguous, do copy-in
+}
+
+static void DetermineCopyInOutArgument(
+ const characteristics::Procedure &procInfo,
+ ActualArgument &actual, characteristics::DummyArgument &dummy) {
+
+ // TODO: assert? procInfo.HasExplicitInterface()
+
+}
+
void ProcedureRef::DetermineCopyInOut() {
if (!proc_.GetSymbol()) {
return;
@@ -261,6 +278,50 @@ void ProcedureRef::DetermineCopyInOut() {
}
// TODO: at this point have dummy arguments as procInfo->dummyArguments
// and have actual arguments via arguments_
+
+ // TODO: implicitly declared procedure may not have any information about
+ // its dummy args. Handle this case.
+
+ // Don't change anything about actual or dummy arguments, except for
+ // computing copy-in/copy-out information. If detect something wrong with
+ // the arguments, stop processing and let semantic analysis generate the
+ // error messages.
+ size_t index{0};
+ std::set<std::string> processedKeywords;
+ bool seenKeyword{false};
+ for (auto &actual : arguments_) {
+ if (!actual) {
+ continue;
+ }
+ if (index >= procInfo->dummyArguments.size()) {
+ // More actual arguments than dummy arguments. Semantic analysis will
+ // deal with the error.
+ return;
+ }
+ if (actual->keyword()) {
+ seenKeyword = true;
+ auto actualName = actual->keyword()->ToString();
+ if (processedKeywords.find(actualName) != processedKeywords.end()) {
+ // Actual arguments with duplicate keywords. Semantic analysis will
+ // deal with the error.
+ return;
+ }
+ else {
+ processedKeywords.insert(actualName);
+
+ }
+ }
+ else if (seenKeyword) {
+ // Non-keyword actual argument after have seen at least one keyword
+ // actual argument. Semantic analysis will deal with the error.
+ return;
+ }
+ else {
+ // Positional argument processing
+ }
+
+ ++index;
+ }
}
} // namespace Fortran::evaluate
>From 3198e9059218f6a1ecccd9e609e6eb9e425281e0 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Thu, 31 Jul 2025 22:20:18 -0400
Subject: [PATCH 09/15] More args handing in DetermineCopyInOut()
---
flang/lib/Evaluate/call.cpp | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 6f604d2aed28b..be5db758e9717 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -276,12 +276,15 @@ void ProcedureRef::DetermineCopyInOut() {
if (!procInfo) {
return;
}
- // TODO: at this point have dummy arguments as procInfo->dummyArguments
- // and have actual arguments via arguments_
-
- // TODO: implicitly declared procedure may not have any information about
- // its dummy args. Handle this case.
-
+ if (!procInfo->HasExplicitInterface()) {
+ for (auto &actual : arguments_) {
+ if (!actual) {
+ continue;
+ }
+ DetermineCopyInOutArgument(*procInfo, *actual);
+ }
+ return;
+ }
// Don't change anything about actual or dummy arguments, except for
// computing copy-in/copy-out information. If detect something wrong with
// the arguments, stop processing and let semantic analysis generate the
@@ -308,7 +311,13 @@ void ProcedureRef::DetermineCopyInOut() {
}
else {
processedKeywords.insert(actualName);
-
+ if (auto it = std::find_if(procInfo->dummyArguments.begin(),
+ procInfo->dummyArguments.end(),
+ [&](const characteristics::DummyArgument &dummy) {
+ return dummy.name == actualName;
+ }); it != procInfo->dummyArguments.end()) {
+ DetermineCopyInOutArgument(*procInfo, *actual, *it);
+ }
}
}
else if (seenKeyword) {
@@ -318,6 +327,8 @@ void ProcedureRef::DetermineCopyInOut() {
}
else {
// Positional argument processing
+ DetermineCopyInOutArgument(*procInfo, *actual,
+ procInfo->dummyArguments[index]);
}
++index;
>From 0378a5f48279171a255c102c9c4b1401a2875161 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sun, 3 Aug 2025 13:05:00 -0400
Subject: [PATCH 10/15] clang-format
---
flang/lib/Evaluate/call.cpp | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index be5db758e9717..d8663d137e958 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -312,10 +312,11 @@ void ProcedureRef::DetermineCopyInOut() {
else {
processedKeywords.insert(actualName);
if (auto it = std::find_if(procInfo->dummyArguments.begin(),
- procInfo->dummyArguments.end(),
- [&](const characteristics::DummyArgument &dummy) {
- return dummy.name == actualName;
- }); it != procInfo->dummyArguments.end()) {
+ procInfo->dummyArguments.end(),
+ [&](const characteristics::DummyArgument &dummy) {
+ return dummy.name == actualName;
+ });
+ it != procInfo->dummyArguments.end()) {
DetermineCopyInOutArgument(*procInfo, *actual, *it);
}
}
@@ -327,8 +328,8 @@ void ProcedureRef::DetermineCopyInOut() {
}
else {
// Positional argument processing
- DetermineCopyInOutArgument(*procInfo, *actual,
- procInfo->dummyArguments[index]);
+ DetermineCopyInOutArgument(
+ *procInfo, *actual, procInfo->dummyArguments[index]);
}
++index;
>From 5d5418a6add0e279870ba05be44b9a3e5dd3ee6d Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sun, 3 Aug 2025 13:05:50 -0400
Subject: [PATCH 11/15] clang-format
---
flang/lib/Evaluate/call.cpp | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index d8663d137e958..10920a4cf6b2f 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -258,11 +258,10 @@ static void DetermineCopyInOutArgument(
}
static void DetermineCopyInOutArgument(
- const characteristics::Procedure &procInfo,
- ActualArgument &actual, characteristics::DummyArgument &dummy) {
+ const characteristics::Procedure &procInfo, ActualArgument &actual,
+ characteristics::DummyArgument &dummy) {
// TODO: assert? procInfo.HasExplicitInterface()
-
}
void ProcedureRef::DetermineCopyInOut() {
@@ -308,8 +307,7 @@ void ProcedureRef::DetermineCopyInOut() {
// Actual arguments with duplicate keywords. Semantic analysis will
// deal with the error.
return;
- }
- else {
+ } else {
processedKeywords.insert(actualName);
if (auto it = std::find_if(procInfo->dummyArguments.begin(),
procInfo->dummyArguments.end(),
@@ -320,13 +318,11 @@ void ProcedureRef::DetermineCopyInOut() {
DetermineCopyInOutArgument(*procInfo, *actual, *it);
}
}
- }
- else if (seenKeyword) {
+ } else if (seenKeyword) {
// Non-keyword actual argument after have seen at least one keyword
// actual argument. Semantic analysis will deal with the error.
return;
- }
- else {
+ } else {
// Positional argument processing
DetermineCopyInOutArgument(
*procInfo, *actual, procInfo->dummyArguments[index]);
>From 2cce4bba70f2ce3ad8f331601fc35a317468f5e2 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sun, 3 Aug 2025 13:06:10 -0400
Subject: [PATCH 12/15] clang-format
---
flang/include/flang/Evaluate/call.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index 3d4f791380fba..ac11527e4ecaa 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -248,8 +248,7 @@ class ProcedureRef {
ProcedureRef(ProcedureDesignator &&p, ActualArguments &&a,
bool hasAlternateReturns = false)
: proc_{std::move(p)}, arguments_{std::move(a)},
- hasAlternateReturns_{hasAlternateReturns} {
- }
+ hasAlternateReturns_{hasAlternateReturns} {}
~ProcedureRef();
static void Deleter(ProcedureRef *);
>From de06d25274f168993def6ba1bc3a28017ad68975 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 6 Aug 2025 22:10:30 -0400
Subject: [PATCH 13/15] Initial implementation of DetermineCopyInOutArgument()
for implicit interfaces.
Certain helper routines gained overloads to work with ActualArgument.
---
.../include/flang/Evaluate/check-expression.h | 3 ++
flang/include/flang/Evaluate/tools.h | 1 +
flang/lib/Evaluate/call.cpp | 45 ++++++++++++++-----
flang/lib/Evaluate/check-expression.cpp | 11 +++++
flang/lib/Evaluate/tools.cpp | 5 +++
5 files changed, 54 insertions(+), 11 deletions(-)
diff --git a/flang/include/flang/Evaluate/check-expression.h b/flang/include/flang/Evaluate/check-expression.h
index 0cf12f340ec5c..46b91cd2f93cc 100644
--- a/flang/include/flang/Evaluate/check-expression.h
+++ b/flang/include/flang/Evaluate/check-expression.h
@@ -118,6 +118,9 @@ std::optional<bool> IsContiguous(const A &, FoldingContext &,
extern template std::optional<bool> IsContiguous(const Expr<SomeType> &,
FoldingContext &, bool namedConstantSectionsAreContiguous,
bool firstDimensionStride1);
+extern template std::optional<bool> IsContiguous(const ActualArgument &,
+ FoldingContext &, bool namedConstantSectionsAreContiguous,
+ bool firstDimensionStride1);
extern template std::optional<bool> IsContiguous(const ArrayRef &,
FoldingContext &, bool namedConstantSectionsAreContiguous,
bool firstDimensionStride1);
diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h
index 212356136d6ee..0be3f66321e4f 100644
--- a/flang/include/flang/Evaluate/tools.h
+++ b/flang/include/flang/Evaluate/tools.h
@@ -1123,6 +1123,7 @@ extern template semantics::UnorderedSymbolSet CollectCudaSymbols(
// Predicate: does a variable contain a vector-valued subscript (not a triplet)?
bool HasVectorSubscript(const Expr<SomeType> &);
+bool HasVectorSubscript(const ActualArgument &);
// Predicate: does an expression contain constant?
bool HasConstant(const Expr<SomeType> &);
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 10920a4cf6b2f..365e98a7d800f 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -251,17 +251,39 @@ void ProcedureRef::Deleter(ProcedureRef *p) { delete p; }
// We don't know the dummy argument info (e.g., procedure with implicit
// interface
static void DetermineCopyInOutArgument(
- const characteristics::Procedure &procInfo, ActualArgument &actual) {
-
- // Only check that actual argument is contiguous
- // For non-contiguous, do copy-in
+ const characteristics::Procedure &procInfo, ActualArgument &actual,
+ semantics::SemanticsContext &sc) {
+ if (actual.isAlternateReturn()) {
+ return;
+ }
+ if (!evaluate::IsVariable(actual)) {
+ // Actual argument expressions that aren’t variables are copy-in, but
+ // not copy-out.
+ actual.set_mayNeedCopyIn();
+ }
+ else if (!IsSimplyContiguous(actual, sc.foldingContext())) {
+ // Actual arguments that are variables are copy-in when non-contiguous.
+ // They are copy-out when don't have vector subscripts
+ actual.set_mayNeedCopyIn();
+ if (!HasVectorSubscript(actual)) {
+ actual.set_mayNeedCopyOut();
+ }
+ }
+ else if (ExtractCoarrayRef(actual)) {
+ // Coindexed actual args need copy-in and copy-out
+ actual.set_mayNeedCopyIn();
+ actual.set_mayNeedCopyOut();
+ }
}
static void DetermineCopyInOutArgument(
const characteristics::Procedure &procInfo, ActualArgument &actual,
- characteristics::DummyArgument &dummy) {
-
- // TODO: assert? procInfo.HasExplicitInterface()
+ characteristics::DummyArgument &dummy, semantics::SemanticsContext &sc) {
+ assert(procInfo.HasExplicitInterface() && "expect explicit interface proc");
+ if (actual.isAlternateReturn()) {
+ return;
+ }
+ // TODO
}
void ProcedureRef::DetermineCopyInOut() {
@@ -269,7 +291,8 @@ void ProcedureRef::DetermineCopyInOut() {
return;
}
// Get folding context of the call site owner
- FoldingContext &fc{proc_.GetSymbol()->owner().context().foldingContext()};
+ semantics::SemanticsContext &sc{proc_.GetSymbol()->owner().context()};
+ FoldingContext &fc{sc.foldingContext()};
auto procInfo{
characteristics::Procedure::Characterize(proc_, fc, /*emitError=*/true)};
if (!procInfo) {
@@ -280,7 +303,7 @@ void ProcedureRef::DetermineCopyInOut() {
if (!actual) {
continue;
}
- DetermineCopyInOutArgument(*procInfo, *actual);
+ DetermineCopyInOutArgument(*procInfo, *actual, sc);
}
return;
}
@@ -315,7 +338,7 @@ void ProcedureRef::DetermineCopyInOut() {
return dummy.name == actualName;
});
it != procInfo->dummyArguments.end()) {
- DetermineCopyInOutArgument(*procInfo, *actual, *it);
+ DetermineCopyInOutArgument(*procInfo, *actual, *it, sc);
}
}
} else if (seenKeyword) {
@@ -325,7 +348,7 @@ void ProcedureRef::DetermineCopyInOut() {
} else {
// Positional argument processing
DetermineCopyInOutArgument(
- *procInfo, *actual, procInfo->dummyArguments[index]);
+ *procInfo, *actual, procInfo->dummyArguments[index], sc);
}
++index;
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index 3d7f01d56c465..eddccc57885e3 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -1198,9 +1198,20 @@ std::optional<bool> IsContiguous(const A &x, FoldingContext &context,
}
}
+std::optional<bool> IsContiguous(const ActualArgument &actual,
+ FoldingContext &fc, bool namedConstantSectionsAreContiguous,
+ bool firstDimensionStride1) {
+ auto *expr{actual.UnwrapExpr()};
+ return expr && IsContiguous(*expr, fc, namedConstantSectionsAreContiguous,
+ firstDimensionStride1);
+}
+
template std::optional<bool> IsContiguous(const Expr<SomeType> &,
FoldingContext &, bool namedConstantSectionsAreContiguous,
bool firstDimensionStride1);
+template std::optional<bool> IsContiguous(const ActualArgument &,
+ FoldingContext &, bool namedConstantSectionsAreContiguous,
+ bool firstDimensionStride1);
template std::optional<bool> IsContiguous(const ArrayRef &, FoldingContext &,
bool namedConstantSectionsAreContiguous, bool firstDimensionStride1);
template std::optional<bool> IsContiguous(const Substring &, FoldingContext &,
diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp
index 9c059b08dd41c..3ac605d650b9f 100644
--- a/flang/lib/Evaluate/tools.cpp
+++ b/flang/lib/Evaluate/tools.cpp
@@ -1203,6 +1203,11 @@ bool HasVectorSubscript(const Expr<SomeType> &expr) {
return HasVectorSubscriptHelper{}(expr);
}
+bool HasVectorSubscript(const ActualArgument &actual) {
+ auto expr = actual.UnwrapExpr();
+ return expr && HasVectorSubscript(*expr);
+}
+
// HasConstant()
struct HasConstantHelper : public AnyTraverse<HasConstantHelper, bool,
/*TraverseAssocEntityDetails=*/false> {
>From cf42b128d0d3b679e338c7719883a82a9e659272 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 6 Aug 2025 22:16:38 -0400
Subject: [PATCH 14/15] Removed empty line
---
flang/lib/Evaluate/call.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 365e98a7d800f..21117893f7698 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -350,7 +350,6 @@ void ProcedureRef::DetermineCopyInOut() {
DetermineCopyInOutArgument(
*procInfo, *actual, procInfo->dummyArguments[index], sc);
}
-
++index;
}
}
>From 9373b90cb8fe1406dc4abf98869a9a511d3ed01c Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Wed, 6 Aug 2025 22:17:39 -0400
Subject: [PATCH 15/15] clang-format
---
flang/lib/Evaluate/call.cpp | 6 ++----
flang/lib/Evaluate/check-expression.cpp | 5 +++--
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/flang/lib/Evaluate/call.cpp b/flang/lib/Evaluate/call.cpp
index 21117893f7698..05fb29174e90e 100644
--- a/flang/lib/Evaluate/call.cpp
+++ b/flang/lib/Evaluate/call.cpp
@@ -260,16 +260,14 @@ static void DetermineCopyInOutArgument(
// Actual argument expressions that aren’t variables are copy-in, but
// not copy-out.
actual.set_mayNeedCopyIn();
- }
- else if (!IsSimplyContiguous(actual, sc.foldingContext())) {
+ } else if (!IsSimplyContiguous(actual, sc.foldingContext())) {
// Actual arguments that are variables are copy-in when non-contiguous.
// They are copy-out when don't have vector subscripts
actual.set_mayNeedCopyIn();
if (!HasVectorSubscript(actual)) {
actual.set_mayNeedCopyOut();
}
- }
- else if (ExtractCoarrayRef(actual)) {
+ } else if (ExtractCoarrayRef(actual)) {
// Coindexed actual args need copy-in and copy-out
actual.set_mayNeedCopyIn();
actual.set_mayNeedCopyOut();
diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp
index eddccc57885e3..13bc4d4a05ab9 100644
--- a/flang/lib/Evaluate/check-expression.cpp
+++ b/flang/lib/Evaluate/check-expression.cpp
@@ -1202,8 +1202,9 @@ std::optional<bool> IsContiguous(const ActualArgument &actual,
FoldingContext &fc, bool namedConstantSectionsAreContiguous,
bool firstDimensionStride1) {
auto *expr{actual.UnwrapExpr()};
- return expr && IsContiguous(*expr, fc, namedConstantSectionsAreContiguous,
- firstDimensionStride1);
+ return expr &&
+ IsContiguous(
+ *expr, fc, namedConstantSectionsAreContiguous, firstDimensionStride1);
}
template std::optional<bool> IsContiguous(const Expr<SomeType> &,
More information about the flang-commits
mailing list