[flang-commits] [flang] [flang] Refine checks for intrinsic operator conflicts with CUDA defi… (PR #94389)

via flang-commits flang-commits at lists.llvm.org
Tue Jun 4 12:29:33 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

<details>
<summary>Changes</summary>

…ned 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.

---
Full diff: https://github.com/llvm/llvm-project/pull/94389.diff


2 Files Affected:

- (modified) flang/lib/Semantics/check-declarations.cpp (+43-12) 
- (added) flang/test/Semantics/cuf16.cuf (+95) 


``````````diff
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 25de9d4af1ffb..bfb38fa1340ec 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<DummyDataObject>(proc.dummyArguments[0].u).type};
-  auto rhs{std::get<DummyDataObject>(proc.dummyArguments[1].u).type};
-  return Tristate::No ==
-      IsDefinedAssignment(lhs.type(), lhs.Rank(), rhs.type(), rhs.Rank());
+  const auto &lhsData{std::get<DummyDataObject>(proc.dummyArguments[0].u)};
+  const auto &lhsTnS{lhsData.type};
+  const auto &rhsData{std::get<DummyDataObject>(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<DummyDataObject>(proc.dummyArguments[0].u).type};
-  auto type0{arg0.type()};
+  const auto &arg0Data{std::get<DummyDataObject>(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<DummyDataObject>(proc.dummyArguments[1].u).type};
-    auto type1{arg1.type()};
-    int rank1{arg1.Rank()};
+    int rank0{arg0TnS.Rank()};
+    const auto &arg1Data{std::get<DummyDataObject>(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 0000000000000..4a7595b479503
--- /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

``````````

</details>


https://github.com/llvm/llvm-project/pull/94389


More information about the flang-commits mailing list