From 8a6b189dbd277089ae5d8a8a8cfdd2bc800732bd Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Tue, 4 Jun 2024 12:26:27 -0700 Subject: [PATCH] [flang] Refine checks for intrinsic operator conflicts with CUDA defined operators The checks for conflicts between defined operators/assignments and the intrinsic operators/assignment need to take CUDA procedure and data attributes into account to avoid false positive error messages. --- flang/lib/Semantics/check-declarations.cpp | 55 ++++++++++--- flang/test/Semantics/cuf16.cuf | 95 ++++++++++++++++++++++ 2 files changed, 138 insertions(+), 12 deletions(-) create mode 100644 flang/test/Semantics/cuf16.cuf diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp index 25de9d4af1ffb9..bfb38fa1340ecb 100644 --- a/flang/lib/Semantics/check-declarations.cpp +++ b/flang/lib/Semantics/check-declarations.cpp @@ -1887,11 +1887,34 @@ void CheckHelper::CheckSpecifics( helper.Check(generic.owner()); } +static bool CUDAHostDeviceDiffer( + const Procedure &proc, const DummyDataObject &arg) { + auto procCUDA{ + proc.cudaSubprogramAttrs.value_or(common::CUDASubprogramAttrs::Host)}; + bool procIsHostOnly{procCUDA == common::CUDASubprogramAttrs::Host}; + bool procIsDeviceOnly{ + !procIsHostOnly && procCUDA != common::CUDASubprogramAttrs::HostDevice}; + const auto &argCUDA{arg.cudaDataAttr}; + bool argIsHostOnly{!argCUDA || *argCUDA == common::CUDADataAttr::Pinned}; + bool argIsDeviceOnly{(!argCUDA && procIsDeviceOnly) || + (argCUDA && + (*argCUDA != common::CUDADataAttr::Managed && + *argCUDA != common::CUDADataAttr::Pinned && + *argCUDA != common::CUDADataAttr::Unified))}; + return (procIsHostOnly && argIsDeviceOnly) || + (procIsDeviceOnly && argIsHostOnly); +} + static bool ConflictsWithIntrinsicAssignment(const Procedure &proc) { - auto lhs{std::get(proc.dummyArguments[0].u).type}; - auto rhs{std::get(proc.dummyArguments[1].u).type}; - return Tristate::No == - IsDefinedAssignment(lhs.type(), lhs.Rank(), rhs.type(), rhs.Rank()); + const auto &lhsData{std::get(proc.dummyArguments[0].u)}; + const auto &lhsTnS{lhsData.type}; + const auto &rhsData{std::get(proc.dummyArguments[1].u)}; + const auto &rhsTnS{rhsData.type}; + return !CUDAHostDeviceDiffer(proc, lhsData) && + !CUDAHostDeviceDiffer(proc, rhsData) && + Tristate::No == + IsDefinedAssignment( + lhsTnS.type(), lhsTnS.Rank(), rhsTnS.type(), rhsTnS.Rank()); } static bool ConflictsWithIntrinsicOperator( @@ -1899,8 +1922,12 @@ static bool ConflictsWithIntrinsicOperator( if (!kind.IsIntrinsicOperator()) { return false; } - auto arg0{std::get(proc.dummyArguments[0].u).type}; - auto type0{arg0.type()}; + const auto &arg0Data{std::get(proc.dummyArguments[0].u)}; + if (CUDAHostDeviceDiffer(proc, arg0Data)) { + return false; + } + const auto &arg0TnS{arg0Data.type}; + auto type0{arg0TnS.type()}; if (proc.dummyArguments.size() == 1) { // unary return common::visit( common::visitors{ @@ -1910,10 +1937,14 @@ static bool ConflictsWithIntrinsicOperator( }, kind.u); } else { // binary - int rank0{arg0.Rank()}; - auto arg1{std::get(proc.dummyArguments[1].u).type}; - auto type1{arg1.type()}; - int rank1{arg1.Rank()}; + int rank0{arg0TnS.Rank()}; + const auto &arg1Data{std::get(proc.dummyArguments[1].u)}; + if (CUDAHostDeviceDiffer(proc, arg1Data)) { + return false; + } + const auto &arg1TnS{arg1Data.type}; + auto type1{arg1TnS.type()}; + int rank1{arg1TnS.Rank()}; return common::visit( common::visitors{ [&](common::NumericOperator) { @@ -2087,8 +2118,8 @@ bool CheckHelper::CheckDefinedAssignment( if (!(ok0 && ok1)) { return false; // error was reported } else if (ConflictsWithIntrinsicAssignment(proc)) { - msg = "Defined assignment subroutine '%s' conflicts with" - " intrinsic assignment"_err_en_US; + msg = + "Defined assignment subroutine '%s' conflicts with intrinsic assignment"_err_en_US; } else { return true; // OK } diff --git a/flang/test/Semantics/cuf16.cuf b/flang/test/Semantics/cuf16.cuf new file mode 100644 index 00000000000000..4a7595b4795038 --- /dev/null +++ b/flang/test/Semantics/cuf16.cuf @@ -0,0 +1,95 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 +module m + interface operator(-) + !ERROR: OPERATOR(-) function 'f1' conflicts with intrinsic operator + function f1(x) + real, intent(in) :: x + end + !ERROR: OPERATOR(-) function 'f2' conflicts with intrinsic operator + attributes(device) function f2(x) + real, intent(in), device :: x(:) + end + function f3(x) ! ok + real, intent(in), device :: x(:,:) + end + !ERROR: OPERATOR(-) function 'f4' conflicts with intrinsic operator + attributes(device) function f4(x) + real, intent(in) :: x(:,:,:) + end + !ERROR: OPERATOR(-) function 'f5' conflicts with intrinsic operator + function f5(x) + real, intent(in), unified :: x(:,:,:,:) + end + !ERROR: OPERATOR(-) function 'f6' conflicts with intrinsic operator + attributes(device) function f6(x) + real, intent(in), managed :: x(:,:,:,:,:) + end + end interface + interface operator(*) + !ERROR: OPERATOR(*) function 'f11' conflicts with intrinsic operator + function f11(x, y) + real, intent(in) :: x, y + end + !ERROR: OPERATOR(*) function 'f12' conflicts with intrinsic operator + attributes(device) function f12(x, y) + real, intent(in), device :: x, y(:) + end + !ERROR: OPERATOR(*) function 'f13' conflicts with intrinsic operator + attributes(device) function f13(x, y) + real, intent(in) :: x(:), y + end + function f14a(x, y) ! ok + real, intent(in), device :: x(:) + real, intent(in) :: y(:) + end + function f14b(x, y) ! ok + real, intent(in) :: x + real, intent(in), device :: y(:,:) + end + !ERROR: OPERATOR(*) function 'f15' conflicts with intrinsic operator + function f15(x, y) + real, intent(in) :: x(:,:) + real, intent(in), unified :: y + end + !ERROR: OPERATOR(*) function 'f16' conflicts with intrinsic operator + attributes(device) function f16(x, y) + real, intent(in), device :: x(:,:) + real, intent(in), managed :: y(:,:) + end + end interface + interface assignment(=) + !ERROR: Defined assignment subroutine 's1' conflicts with intrinsic assignment + subroutine s1(x, y) + real, intent(in out) :: x + real, intent(in) :: y + end + !ERROR: Defined assignment subroutine 's2' conflicts with intrinsic assignment + attributes(device) subroutine s2(x, y) + real, intent(in out), device :: x(:) + real, intent(in), device :: y + end + !ERROR: Defined assignment subroutine 's3' conflicts with intrinsic assignment + attributes(device) subroutine s3(x, y) + real, intent(in out) :: x(:) + real, intent(in) :: y(:) + end + subroutine s4a(x, y) ! ok + real, intent(in out), device :: x(:,:) + real, intent(in) :: y + end + subroutine s4b(x, y) ! ok + real, intent(in out) :: x(:,:) + real, intent(in), device :: y(:,:) + end + !ERROR: Defined assignment subroutine 's5' conflicts with intrinsic assignment + subroutine s5(x, y) + real, intent(in out) :: x(:,:,:) + real, intent(in), unified :: y + end + !ERROR: Defined assignment subroutine 's6' conflicts with intrinsic assignment + attributes(device) subroutine s6(x, y) + real, intent(in out), device :: x(:,:,:) + real, intent(in), managed :: y(:,:,:) + end + end interface +end