Skip to content

[flang][cuda] Extends matching distance computation #91810

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
IndistinguishableSpecifics, SubroutineAndFunctionSpecifics,
EmptySequenceType, NonSequenceCrayPointee, BranchIntoConstruct,
BadBranchTarget, ConvertedArgument, HollerithPolymorphic, ListDirectedSize,
NonBindCInteroperability)
NonBindCInteroperability, CudaManaged, CudaUnified)

// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
Expand Down Expand Up @@ -81,6 +81,8 @@ class LanguageFeatureControl {
disable_.set(LanguageFeature::OpenACC);
disable_.set(LanguageFeature::OpenMP);
disable_.set(LanguageFeature::CUDA); // !@cuf
disable_.set(LanguageFeature::CudaManaged);
disable_.set(LanguageFeature::CudaUnified);
disable_.set(LanguageFeature::ImplicitNoneTypeNever);
disable_.set(LanguageFeature::ImplicitNoneTypeAlways);
disable_.set(LanguageFeature::DefaultSave);
Expand Down
4 changes: 3 additions & 1 deletion flang/include/flang/Common/Fortran.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <string>

namespace Fortran::common {
class LanguageFeatureControl;

// Fortran has five kinds of intrinsic data types, plus the derived types.
ENUM_CLASS(TypeCategory, Integer, Real, Complex, Character, Logical, Derived)
Expand Down Expand Up @@ -115,7 +116,8 @@ static constexpr IgnoreTKRSet ignoreTKRAll{IgnoreTKR::Type, IgnoreTKR::Kind,
std::string AsFortran(IgnoreTKRSet);

bool AreCompatibleCUDADataAttrs(std::optional<CUDADataAttr>,
std::optional<CUDADataAttr>, IgnoreTKRSet, bool allowUnifiedMatchingRule);
std::optional<CUDADataAttr>, IgnoreTKRSet, bool allowUnifiedMatchingRule,
const LanguageFeatureControl *features = nullptr);

static constexpr char blankCommonObjectName[] = "__BLNK__";

Expand Down
37 changes: 26 additions & 11 deletions flang/lib/Common/Fortran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "flang/Common/Fortran.h"
#include "flang/Common/Fortran-features.h"

namespace Fortran::common {

Expand Down Expand Up @@ -102,7 +103,13 @@ std::string AsFortran(IgnoreTKRSet tkr) {
/// dummy argument attribute while `y` represents the actual argument attribute.
bool AreCompatibleCUDADataAttrs(std::optional<CUDADataAttr> x,
std::optional<CUDADataAttr> y, IgnoreTKRSet ignoreTKR,
bool allowUnifiedMatchingRule) {
bool allowUnifiedMatchingRule, const LanguageFeatureControl *features) {
bool isCudaManaged{features
? features->IsEnabled(common::LanguageFeature::CudaManaged)
: false};
bool isCudaUnified{features
? features->IsEnabled(common::LanguageFeature::CudaUnified)
: false};
if (!x && !y) {
return true;
} else if (x && y && *x == *y) {
Expand All @@ -120,19 +127,27 @@ bool AreCompatibleCUDADataAttrs(std::optional<CUDADataAttr> x,
return true;
} else if (allowUnifiedMatchingRule) {
if (!x) { // Dummy argument has no attribute -> host
if (y && (*y == CUDADataAttr::Managed || *y == CUDADataAttr::Unified)) {
if ((y && (*y == CUDADataAttr::Managed || *y == CUDADataAttr::Unified)) ||
(!y && (isCudaUnified || isCudaManaged))) {
return true;
}
} else {
if (*x == CUDADataAttr::Device && y &&
(*y == CUDADataAttr::Managed || *y == CUDADataAttr::Unified)) {
return true;
} else if (*x == CUDADataAttr::Managed && y &&
*y == CUDADataAttr::Unified) {
return true;
} else if (*x == CUDADataAttr::Unified && y &&
*y == CUDADataAttr::Managed) {
return true;
if (*x == CUDADataAttr::Device) {
if ((y &&
(*y == CUDADataAttr::Managed || *y == CUDADataAttr::Unified)) ||
(!y && (isCudaUnified || isCudaManaged))) {
return true;
}
} else if (*x == CUDADataAttr::Managed) {
if ((y && *y == CUDADataAttr::Unified) ||
(!y && (isCudaUnified || isCudaManaged))) {
return true;
}
} else if (*x == CUDADataAttr::Unified) {
if ((y && *y == CUDADataAttr::Managed) ||
(!y && (isCudaUnified || isCudaManaged))) {
return true;
}
}
}
return false;
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Semantics/check-call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
}
if (!common::AreCompatibleCUDADataAttrs(dummyDataAttr, actualDataAttr,
dummy.ignoreTKR,
/*allowUnifiedMatchingRule=*/true)) {
/*allowUnifiedMatchingRule=*/true, &context.languageFeatures())) {
auto toStr{[](std::optional<common::CUDADataAttr> x) {
return x ? "ATTRIBUTES("s +
parser::ToUpperCaseLetters(common::EnumToString(*x)) + ")"s
Expand Down
34 changes: 27 additions & 7 deletions flang/lib/Semantics/expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2501,8 +2501,13 @@ static constexpr int cudaInfMatchingValue{std::numeric_limits<int>::max()};

// Compute the matching distance as described in section 3.2.3 of the CUDA
// Fortran references.
static int GetMatchingDistance(const characteristics::DummyArgument &dummy,
static int GetMatchingDistance(const common::LanguageFeatureControl &features,
const characteristics::DummyArgument &dummy,
const std::optional<ActualArgument> &actual) {
bool isCudaManaged{features.IsEnabled(common::LanguageFeature::CudaManaged)};
bool isCudaUnified{features.IsEnabled(common::LanguageFeature::CudaUnified)};
CHECK(!(isCudaUnified && isCudaManaged) && "expect only one enabled.");

std::optional<common::CUDADataAttr> actualDataAttr, dummyDataAttr;
if (actual) {
if (auto *expr{actual->UnwrapExpr()}) {
Expand All @@ -2529,6 +2534,9 @@ static int GetMatchingDistance(const characteristics::DummyArgument &dummy,

if (!dummyDataAttr) {
if (!actualDataAttr) {
if (isCudaUnified || isCudaManaged) {
return 3;
}
return 0;
} else if (*actualDataAttr == common::CUDADataAttr::Device) {
return cudaInfMatchingValue;
Expand All @@ -2538,6 +2546,9 @@ static int GetMatchingDistance(const characteristics::DummyArgument &dummy,
}
} else if (*dummyDataAttr == common::CUDADataAttr::Device) {
if (!actualDataAttr) {
if (isCudaUnified || isCudaManaged) {
return 2;
}
return cudaInfMatchingValue;
} else if (*actualDataAttr == common::CUDADataAttr::Device) {
return 0;
Expand All @@ -2546,15 +2557,21 @@ static int GetMatchingDistance(const characteristics::DummyArgument &dummy,
return 2;
}
} else if (*dummyDataAttr == common::CUDADataAttr::Managed) {
if (!actualDataAttr || *actualDataAttr == common::CUDADataAttr::Device) {
if (!actualDataAttr) {
return isCudaUnified ? 1 : isCudaManaged ? 0 : cudaInfMatchingValue;
}
if (*actualDataAttr == common::CUDADataAttr::Device) {
return cudaInfMatchingValue;
} else if (*actualDataAttr == common::CUDADataAttr::Managed) {
return 0;
} else if (*actualDataAttr == common::CUDADataAttr::Unified) {
return 1;
}
} else if (*dummyDataAttr == common::CUDADataAttr::Unified) {
if (!actualDataAttr || *actualDataAttr == common::CUDADataAttr::Device) {
if (!actualDataAttr) {
return isCudaUnified ? 0 : isCudaManaged ? 1 : cudaInfMatchingValue;
}
if (*actualDataAttr == common::CUDADataAttr::Device) {
return cudaInfMatchingValue;
} else if (*actualDataAttr == common::CUDADataAttr::Managed) {
return 1;
Expand All @@ -2566,6 +2583,7 @@ static int GetMatchingDistance(const characteristics::DummyArgument &dummy,
}

static int ComputeCudaMatchingDistance(
const common::LanguageFeatureControl &features,
const characteristics::Procedure &procedure,
const ActualArguments &actuals) {
const auto &dummies{procedure.dummyArguments};
Expand All @@ -2574,7 +2592,7 @@ static int ComputeCudaMatchingDistance(
for (std::size_t i{0}; i < dummies.size(); ++i) {
const characteristics::DummyArgument &dummy{dummies[i]};
const std::optional<ActualArgument> &actual{actuals[i]};
int d{GetMatchingDistance(dummy, actual)};
int d{GetMatchingDistance(features, dummy, actual)};
if (d == cudaInfMatchingValue)
return d;
distance += d;
Expand Down Expand Up @@ -2666,7 +2684,9 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
CheckCompatibleArguments(*procedure, localActuals)) {
if ((procedure->IsElemental() && elemental) ||
(!procedure->IsElemental() && nonElemental)) {
int d{ComputeCudaMatchingDistance(*procedure, localActuals)};
int d{ComputeCudaMatchingDistance(
context_.languageFeatures(), *procedure, localActuals)};
llvm::errs() << "matching distance: " << d << "\n";
if (d != crtMatchingDistance) {
if (d > crtMatchingDistance) {
continue;
Expand All @@ -2688,8 +2708,8 @@ std::pair<const Symbol *, bool> ExpressionAnalyzer::ResolveGeneric(
} else {
elemental = &specific;
}
crtMatchingDistance =
ComputeCudaMatchingDistance(*procedure, localActuals);
crtMatchingDistance = ComputeCudaMatchingDistance(
context_.languageFeatures(), *procedure, localActuals);
}
}
}
Expand Down
55 changes: 55 additions & 0 deletions flang/test/Semantics/cuf14.cuf
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
! RUN: bbc -emit-hlfir -fcuda -gpu=unified %s -o - | FileCheck %s

module matching
interface host_and_device
module procedure sub_host
module procedure sub_device
end interface

interface all
module procedure sub_host
module procedure sub_device
module procedure sub_managed
module procedure sub_unified
end interface

interface all_without_unified
module procedure sub_host
module procedure sub_device
module procedure sub_managed
end interface

contains
subroutine sub_host(a)
integer :: a(:)
end

subroutine sub_device(a)
integer, device :: a(:)
end

subroutine sub_managed(a)
integer, managed :: a(:)
end

subroutine sub_unified(a)
integer, unified :: a(:)
end
end module

program m
use matching

integer, allocatable :: actual_host(:)

allocate(actual_host(10))

call host_and_device(actual_host) ! Should resolve to sub_device
call all(actual_host) ! Should resolved to unified
call all_without_unified(actual_host) ! Should resolved to managed
end

! CHECK: fir.call @_QMmatchingPsub_device
! CHECK: fir.call @_QMmatchingPsub_unified
! CHECK: fir.call @_QMmatchingPsub_managed

55 changes: 55 additions & 0 deletions flang/test/Semantics/cuf15.cuf
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
! RUN: bbc -emit-hlfir -fcuda -gpu=managed %s -o - | FileCheck %s

module matching
interface host_and_device
module procedure sub_host
module procedure sub_device
end interface

interface all
module procedure sub_host
module procedure sub_device
module procedure sub_managed
module procedure sub_unified
end interface

interface all_without_managed
module procedure sub_host
module procedure sub_device
module procedure sub_unified
end interface

contains
subroutine sub_host(a)
integer :: a(:)
end

subroutine sub_device(a)
integer, device :: a(:)
end

subroutine sub_managed(a)
integer, managed :: a(:)
end

subroutine sub_unified(a)
integer, unified :: a(:)
end
end module

program m
use matching

integer, allocatable :: actual_host(:)

allocate(actual_host(10))

call host_and_device(actual_host) ! Should resolve to sub_device
call all(actual_host) ! Should resolved to unified
call all_without_managed(actual_host) ! Should resolved to managed
end

! CHECK: fir.call @_QMmatchingPsub_device
! CHECK: fir.call @_QMmatchingPsub_managed
! CHECK: fir.call @_QMmatchingPsub_unified

10 changes: 10 additions & 0 deletions flang/tools/bbc/bbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ static llvm::cl::opt<bool> enableCUDA("fcuda",
llvm::cl::desc("enable CUDA Fortran"),
llvm::cl::init(false));

static llvm::cl::opt<std::string>
enableGPUMode("gpu", llvm::cl::desc("Enable GPU Mode managed|unified"),
llvm::cl::init(""));

static llvm::cl::opt<bool> fixedForm("ffixed-form",
llvm::cl::desc("enable fixed form"),
llvm::cl::init(false));
Expand Down Expand Up @@ -495,6 +499,12 @@ int main(int argc, char **argv) {
options.features.Enable(Fortran::common::LanguageFeature::CUDA);
}

if (enableGPUMode == "managed") {
options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);
} else if (enableGPUMode == "unified") {
options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);
}

if (fixedForm) {
options.isFixedForm = fixedForm;
}
Expand Down
Loading