[flang-commits] [flang] [flang][DRAFT-DEV][DO NOT REVIEW] Copy-in/Copy-out determination (PR #151426)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Thu Jul 31 19:20:34 PDT 2025
https://github.com/eugeneepshteyn updated https://github.com/llvm/llvm-project/pull/151426
>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 1/9] [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 2/9] 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 3/9] 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 4/9] 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 5/9] 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 6/9] 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 7/9] 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 8/9] 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 9/9] 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;
More information about the flang-commits
mailing list