Skip to content

Commit

Permalink
[flang] Refine checks for intrinsic operator conflicts with CUDA defi… (
Browse files Browse the repository at this point in the history
llvm#94389)

…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.
  • Loading branch information
klausler authored Jun 11, 2024
1 parent 3ab6d12 commit 0ee7112
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 12 deletions.
55 changes: 43 additions & 12 deletions flang/lib/Semantics/check-declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1887,20 +1887,47 @@ 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(
const GenericKind &kind, const Procedure &proc) {
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{
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
Expand Down
95 changes: 95 additions & 0 deletions flang/test/Semantics/cuf16.cuf
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 0ee7112

Please sign in to comment.