Skip to content

[CUDA][HIP] warn incompatible redeclare #77359

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 2 commits into from
Jun 10, 2024
Merged

Conversation

yxsamliu
Copy link
Collaborator

@yxsamliu yxsamliu commented Jan 8, 2024

nvcc warns about the following code:

void f(); __device__ void f() {}

but clang does not since clang allows device function to overload host function.

Users want clang to emit similar warning to help code to be compatible with nvcc.

Since this may cause regression with existing code, the warning is off by default and can be enabled by -Wnvcc-compat.

It won't cause warning in system headers, even with -Wnvcc-compat.

@yxsamliu yxsamliu requested a review from Artem-B January 8, 2024 19:08
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2024

@llvm/pr-subscribers-clang

Author: Yaxun (Sam) Liu (yxsamliu)

Changes

nvcc warns about the following code:

void f(); __device__ void f() {}

but clang does not since clang allows device function to overload host function.

Users want clang to emit similar warning to help code to be compatible with nvcc.

Since this may cause regression with existing code, the warning is off by default and can be enabled by -Woffload-incompatible-redeclare.

It won't cause warning in system headers, even with -Woffload-incompatible-redeclare.


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

3 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+6)
  • (modified) clang/lib/Sema/SemaCUDA.cpp (+21-14)
  • (added) clang/test/SemaCUDA/function-redclare.cu (+19)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index a97182cad5d513..a4c5a76b59cb1b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8837,6 +8837,12 @@ def err_cuda_ovl_target : Error<
   "cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
 def note_cuda_ovl_candidate_target_mismatch : Note<
     "candidate template ignored: target attributes do not match">;
+def warn_offload_incompatible_redeclare : Warning<
+  "incompatible host/device attribute with redeclaration: "
+  "new declaration is %select{__device__|__global__|__host__|__host__ __device__}0 function, "
+  "old declaration is %select{__device__|__global__|__host__|__host__ __device__}1 function. "
+  "It will cause warning with nvcc">,
+  InGroup<DiagGroup<"offload-incompatible-redeclare">>, DefaultIgnore;
 
 def err_cuda_device_builtin_surftex_cls_template : Error<
     "illegal device builtin %select{surface|texture}0 reference "
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp
index 6a66ecf6f94c17..27da1775d4751d 100644
--- a/clang/lib/Sema/SemaCUDA.cpp
+++ b/clang/lib/Sema/SemaCUDA.cpp
@@ -992,22 +992,29 @@ void Sema::checkCUDATargetOverload(FunctionDecl *NewFD,
     // HD/global functions "exist" in some sense on both the host and device, so
     // should have the same implementation on both sides.
     if (NewTarget != OldTarget &&
-        ((NewTarget == CFT_HostDevice &&
-          !(LangOpts.OffloadImplicitHostDeviceTemplates &&
-            isCUDAImplicitHostDeviceFunction(NewFD) &&
-            OldTarget == CFT_Device)) ||
-         (OldTarget == CFT_HostDevice &&
-          !(LangOpts.OffloadImplicitHostDeviceTemplates &&
-            isCUDAImplicitHostDeviceFunction(OldFD) &&
-            NewTarget == CFT_Device)) ||
-         (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) &&
         !IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false,
                     /* ConsiderCudaAttrs = */ false)) {
-      Diag(NewFD->getLocation(), diag::err_cuda_ovl_target)
-          << NewTarget << NewFD->getDeclName() << OldTarget << OldFD;
-      Diag(OldFD->getLocation(), diag::note_previous_declaration);
-      NewFD->setInvalidDecl();
-      break;
+      if ((NewTarget == CFT_HostDevice &&
+           !(LangOpts.OffloadImplicitHostDeviceTemplates &&
+             isCUDAImplicitHostDeviceFunction(NewFD) &&
+             OldTarget == CFT_Device)) ||
+          (OldTarget == CFT_HostDevice &&
+           !(LangOpts.OffloadImplicitHostDeviceTemplates &&
+             isCUDAImplicitHostDeviceFunction(OldFD) &&
+             NewTarget == CFT_Device)) ||
+          (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) {
+        Diag(NewFD->getLocation(), diag::err_cuda_ovl_target)
+            << NewTarget << NewFD->getDeclName() << OldTarget << OldFD;
+        Diag(OldFD->getLocation(), diag::note_previous_declaration);
+        NewFD->setInvalidDecl();
+        break;
+      }
+      if ((NewTarget == CFT_Host && OldTarget == CFT_Device) ||
+          (NewTarget == CFT_Device && OldTarget == CFT_Host)) {
+        Diag(NewFD->getLocation(), diag::warn_offload_incompatible_redeclare)
+            << NewTarget << OldTarget;
+        Diag(OldFD->getLocation(), diag::note_previous_declaration);
+      }
     }
   }
 }
diff --git a/clang/test/SemaCUDA/function-redclare.cu b/clang/test/SemaCUDA/function-redclare.cu
new file mode 100644
index 00000000000000..266483ebf49f0e
--- /dev/null
+++ b/clang/test/SemaCUDA/function-redclare.cu
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only \
+// RUN:   -isystem %S/Inputs -verify %s
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsyntax-only \
+// RUN:   -isystem %S/Inputs -fcuda-is-device -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only \
+// RUN:   -isystem %S/Inputs -verify=redecl -Woffload-incompatible-redeclare %s
+// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsyntax-only \
+// RUN:   -isystem %S/Inputs -fcuda-is-device -Woffload-incompatible-redeclare -verify=redecl %s
+
+// expected-no-diagnostics
+#include "cuda.h"
+
+__device__ void f(); // redecl-note {{previous declaration is here}}
+
+void f() {} // redecl-warning {{incompatible host/device attribute with redeclaration: new declaration is __host__ function, old declaration is __device__ function. It will cause warning with nvcc}}
+
+void g(); // redecl-note {{previous declaration is here}}
+
+__device__ void g() {} // redecl-warning {{incompatible host/device attribute with redeclaration: new declaration is __device__ function, old declaration is __host__ function. It will cause warning with nvcc}}

@yxsamliu
Copy link
Collaborator Author

ping

Comment on lines 13 to 15
__device__ void f(); // redecl-note {{previous declaration is here}}

void f() {} // redecl-warning {{incompatible host/device attribute with redeclaration: new declaration is __host__ function, old declaration is __device__ function. It will cause warning with nvcc}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced that it's something we need to fix. As far as CUDA is concerned those are two different function overloads and it's business as usual with no warning required.

nvcc does not have a concept of attribute-based overloads, so for them a function with different attributes is a sign of a potential issue, but it's not the case for clang, IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe turning the warning on will never work in practice, because there will likely almost always be a ton of math functions with host and device overloads.
As I said, it is very common to have those and a lot of such overloads get pulled in from the headers pre-included by clang.

Copy link
Contributor

@philnik777 philnik777 Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO that looks like a nice "this is incompatible with X" warning like we have for GCC, different C/C++ versions etc., but I'm not an expert here, so maybe this isn't actually an incompatibility? FWIW neither the diagnostic nor your comment make this really clear to me. (Also I'd drop the It will cause warning with nvcc and make the flag something like -Wnvcc-compat)

Copy link
Member

@Artem-B Artem-B Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"this is incompatible with X" warning like we have for GCC

OK. If there's a precedent, it makes things easier.

CUDA compilation includes a lot of CUDA SDK and host headers. <cmath> is one of them. Compiler will always see a lot of implicitly __host__ math functions declared/defined by the host headers and a lot of the same functions with __device__ attribute declared/defined for the GPU. Whether or not user code has the same warning becomes rather moot, when all compilations will produce tons of these warnings.

That said, we may be saved by the fact that (IIRC) compiler hides the warnings that come from the system headers.

It would be good to test it on a real CUDA compilation first. If we're guaranteed to have dozens of those warnings for every compilation, it would render the flag practically useless.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked with real HIP apps and the warnings will only show up for user's code or header files. There are no warnings for host/device redeclarations in HIP or clang headers since they are included as system headers.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO that looks like a nice "this is incompatible with X" warning like we have for GCC, different C/C++ versions etc., but I'm not an expert here, so maybe this isn't actually an incompatibility? FWIW neither the diagnostic nor your comment make this really clear to me. (Also I'd drop the It will cause warning with nvcc and make the flag something like -Wnvcc-compat)

sorry. I missed your comments. will rename the flag

@yxsamliu
Copy link
Collaborator Author

yxsamliu commented Jun 6, 2024

ping

Our users keep requesting this feature since they want their HIP code works with both nvcc and clang. I tested it with real HIP apps and did not see warnings emitted for clang wrapper headers and HIP system headers. Only warnings for users' own code were emitted. Also since this warning is off by default, it won't affect normal users.

Copy link
Member

@Artem-B Artem-B left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with some wording/namiung nits.

@@ -9013,6 +9013,12 @@ def err_cuda_ovl_target : Error<
"cannot overload %select{__device__|__global__|__host__|__host__ __device__}2 function %3">;
def note_cuda_ovl_candidate_target_mismatch : Note<
"candidate template ignored: target attributes do not match">;
def warn_offload_incompatible_redeclare : Warning<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have some sort of umbrella warning option for nvcc compatibility. Function overloads are the primary source of the differences, but we have other differences that the users may want to know about. E.g. some of the compiler builtins would be different. There are probably other things.

This option is fine, for now.

Also, we should document it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will document it

"incompatible host/device attribute with redeclaration: "
"new declaration is %select{__device__|__global__|__host__|__host__ __device__}0 function, "
"old declaration is %select{__device__|__global__|__host__|__host__ __device__}1 function. "
"It will cause warning with nvcc">,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will potentially be a more serious issue, than a mere warning. the source code has both functions, it's possible that the implementation lives in different TUs. With clang, they will be treated as function overloads and things will work. With NVCC, they will end up being treated as GPU functions and that will result in potential ORD violation becaue the user will end up with two different GPU-side functions. It will be a problem during RDC compilation which may link both instances into a single GPU executable.

I'd rephrase it in more general terms. Maybe something along the lines of "Target-attribute based function overloads are not supported by NVCC and will be treated as a function redeclaration". We should tell what we're diagnosing, but make no opinion on whether it will be a problem in any specific case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will modify the diagnostic message

nvcc warns about the following code:

but clang does not since clang allows device function to
overload host function.

Users want clang to emit similar warning to help code to be
compatible with nvcc.

Since this may cause regression with existing code, the warning
is off by default and can be enabled by -Woffload-incompatible-redeclare.

It won't cause warning in system headers, even with
-Woffload-incompatible-redeclare.
@yxsamliu yxsamliu merged commit 53d2f4d into llvm:main Jun 10, 2024
8 checks passed
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Jun 11, 2024
reverts: composableKernels
53d2f4d [CUDA][HIP] warn incompatible redeclare (llvm#77359)

breaks MIOpen
18ec885 [RFC][AMDGPU] Remove old llvm.amdgcn.buffer.* and tbuffer intrinsics (llvm#93801)

Change-Id: I7191261fb80fe1dc8a47063f74d785ab415290b0
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Jun 12, 2024
nvcc warns about the following code:

`void f();
__device__ void f() {}`

but clang does not since clang allows device function to overload host
function.

Users want clang to emit similar warning to help code to be compatible
with nvcc.

Since this may cause regression with existing code, the warning is off
by default and can be enabled by -Wnvcc-compat.

It won't cause warning in system headers, even with -Wnvcc-compat.
@HerrCai0907 HerrCai0907 mentioned this pull request Jun 13, 2024
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Aug 22, 2024
This PR was already merged in trunk:

llvm#77359

However, it was reverted in amd-staging due
to ck issue ROCm/composable_kernel#1330

Now try relanding it in amd-staging after ck issue fixed
by

ROCm/composable_kernel#1342

Fixes: SWDEV-431838

Original commit message:

nvcc warns about the following code:

`void f();
__device__ void f() {}`

but clang does not since clang allows device function to overload host
function.

Users want clang to emit similar warning to help code to be compatible
with nvcc.

Since this may cause regression with existing code, the warning is off
by default and can be enabled by -Wnvcc-compat.

It won't cause warning in system headers, even with -Wnvcc-compat.

Change-Id: Ia370700eb3eb1b1928d04ec59e2ec63506f85545
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Apr 15, 2025
nvcc warns about the following code:

`void f();
__device__ void f() {}`

but clang does not since clang allows device function to overload host
function.

Users want clang to emit similar warning to help code to be compatible
with nvcc.

Since this may cause regression with existing code, the warning is off
by default and can be enabled by -Wnvcc-compat.

It won't cause warning in system headers, even with -Wnvcc-compat.
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Apr 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants