Skip to content

Commit cbec0b5

Browse files
authored
[SYCL] Emit diagnostics appropriately when coexisting with OpenMP (#3750)
In the presence of OpenMP, calls to undefined functions get diagnosed incorrectly in SYCL. With this change, the diagnostic is emitted only when the reason for the emission is SYCL. This change leverages the diagnostic "reason" infrastructure implemented in PR #3511. Signed-off-by: Premanand M Rao <[email protected]>
1 parent 093f89b commit cbec0b5

File tree

5 files changed

+64
-12
lines changed

5 files changed

+64
-12
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,29 @@ class Sema final {
18091809
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/All)
18101810
};
18111811

1812+
private:
1813+
// A collection of a pair of undefined functions and their callers known
1814+
// to be reachable from a routine on the device (kernel or device function).
1815+
typedef std::pair<const FunctionDecl *, const FunctionDecl *> CallPair;
1816+
llvm::SmallVector<CallPair> UndefinedReachableFromSyclDevice;
1817+
1818+
public:
1819+
// Helper routine to add a pair of Callee-Caller pair of FunctionDecl *
1820+
// to UndefinedReachableFromSyclDevice.
1821+
void addFDToReachableFromSyclDevice(const FunctionDecl *Callee,
1822+
const FunctionDecl *Caller) {
1823+
UndefinedReachableFromSyclDevice.push_back(std::make_pair(Callee, Caller));
1824+
}
1825+
// Helper routine to check if a pair of Callee-Caller FunctionDecl *
1826+
// is in UndefinedReachableFromSyclDevice.
1827+
bool isFDReachableFromSyclDevice(const FunctionDecl *Callee,
1828+
const FunctionDecl *Caller) {
1829+
return llvm::any_of(UndefinedReachableFromSyclDevice,
1830+
[Callee, Caller](const CallPair &P) {
1831+
return P.first == Callee && P.second == Caller;
1832+
});
1833+
}
1834+
18121835
/// A generic diagnostic builder for errors which may or may not be deferred.
18131836
///
18141837
/// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch)
@@ -13288,7 +13311,8 @@ class Sema final {
1328813311
/// properly declared for device compilation.
1328913312
void finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller,
1329013313
const FunctionDecl *Callee,
13291-
SourceLocation Loc);
13314+
SourceLocation Loc,
13315+
DeviceDiagnosticReason Reason);
1329213316

1329313317
/// Tells whether given variable is a SYCL explicit SIMD extension's "private
1329413318
/// global" variable - global variable in the private address space.

clang/lib/Sema/Sema.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1665,7 +1665,7 @@ class DeferredDiagnosticsEmitter
16651665
S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc);
16661666
// Finalize analysis of SYCL-specific constructs.
16671667
if (Caller && S.LangOpts.SYCLIsDevice)
1668-
S.finalizeSYCLDelayedAnalysis(Caller, FD, Loc);
1668+
S.finalizeSYCLDelayedAnalysis(Caller, FD, Loc, RootReason);
16691669
if (Caller)
16701670
S.DeviceKnownEmittedFns[FD] = {Caller, Loc};
16711671
// Always emit deferred diagnostics for the direct users. This does not

clang/lib/Sema/SemaDecl.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18469,11 +18469,19 @@ Decl *Sema::getObjCDeclContext() const {
1846918469
}
1847018470

1847118471
Sema::DeviceDiagnosticReason Sema::getEmissionReason(const FunctionDecl *FD) {
18472+
// FIXME: This should really be a bitwise-or of the language modes.
1847218473
if (FD->hasAttr<SYCLSimdAttr>())
1847318474
return Sema::DeviceDiagnosticReason::Esimd;
18474-
else if (FD->hasAttr<SYCLDeviceAttr>() || FD->hasAttr<SYCLKernelAttr>())
18475+
if (FD->hasAttr<SYCLDeviceAttr>() || FD->hasAttr<SYCLKernelAttr>())
1847518476
return Sema::DeviceDiagnosticReason::Sycl;
18476-
// FIXME: Figure out the logic for OMP and CUDA.
18477+
// FIXME: Refine the logic for CUDA and OpenMP.
18478+
if (getLangOpts().CUDA)
18479+
return getLangOpts().CUDAIsDevice ? Sema::DeviceDiagnosticReason::CudaDevice
18480+
: Sema::DeviceDiagnosticReason::CudaHost;
18481+
if (getLangOpts().OpenMP)
18482+
return getLangOpts().OpenMPIsDevice
18483+
? Sema::DeviceDiagnosticReason::OmpDevice
18484+
: Sema::DeviceDiagnosticReason::OmpHost;
1847718485
return Sema::DeviceDiagnosticReason::All;
1847818486
}
1847918487

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,15 @@ class SingleDeviceFunctionTracker {
597597
return;
598598
}
599599

600+
// If this is a routine that is not defined and it does not have either
601+
// a SYCLKernel or SYCLDevice attribute on it, add it to the set of
602+
// routines potentially reachable on device. This is to diagnose such
603+
// cases later in finalizeSYCLDeviceAnalysis().
604+
if (!CurrentDecl->isDefined() && !CurrentDecl->hasAttr<SYCLKernelAttr>() &&
605+
!CurrentDecl->hasAttr<SYCLDeviceAttr>())
606+
Parent.SemaRef.addFDToReachableFromSyclDevice(CurrentDecl,
607+
CallStack.back());
608+
600609
// We previously thought we could skip this function if we'd seen it before,
601610
// but if we haven't seen it before in this call graph, we can end up
602611
// missing a recursive call. SO, we have to revisit call-graphs we've
@@ -3885,22 +3894,29 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
38853894

38863895
void Sema::finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller,
38873896
const FunctionDecl *Callee,
3888-
SourceLocation Loc) {
3897+
SourceLocation Loc,
3898+
DeviceDiagnosticReason Reason) {
38893899
// Somehow an unspecialized template appears to be in callgraph or list of
38903900
// device functions. We don't want to emit diagnostic here.
38913901
if (Callee->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
38923902
return;
38933903

38943904
Callee = Callee->getMostRecentDecl();
3895-
bool HasAttr =
3896-
Callee->hasAttr<SYCLDeviceAttr>() || Callee->hasAttr<SYCLKernelAttr>();
38973905

3898-
// Disallow functions with neither definition nor SYCL_EXTERNAL mark
3899-
bool NotDefinedNoAttr = !Callee->isDefined() && !HasAttr;
3906+
// If the reason for the emission of this diagnostic is not SYCL-specific,
3907+
// and it is not known to be reachable from a routine on device, do not
3908+
// issue a diagnostic.
3909+
if ((Reason & DeviceDiagnosticReason::Sycl) == DeviceDiagnosticReason::None &&
3910+
!isFDReachableFromSyclDevice(Callee, Caller))
3911+
return;
3912+
3913+
// If Callee has a SYCL attribute, no diagnostic needed.
3914+
if (Callee->hasAttr<SYCLDeviceAttr>() || Callee->hasAttr<SYCLKernelAttr>())
3915+
return;
39003916

3901-
if (NotDefinedNoAttr && !Callee->getBuiltinID()) {
3902-
Diag(Loc, diag::err_sycl_restrict)
3903-
<< Sema::KernelCallUndefinedFunction;
3917+
// Diagnose if this is an undefined function and it is not a builtin.
3918+
if (!Callee->isDefined() && !Callee->getBuiltinID()) {
3919+
Diag(Loc, diag::err_sycl_restrict) << Sema::KernelCallUndefinedFunction;
39043920
Diag(Callee->getLocation(), diag::note_previous_decl) << Callee;
39053921
Diag(Caller->getLocation(), diag::note_called_by) << Caller;
39063922
}

clang/test/SemaSYCL/call-to-undefined-function.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -sycl-std=2020 -verify -fsyntax-only %s
2+
// RUN: %clang_cc1 -fsycl-is-device -fopenmp-simd -internal-isystem %S/Inputs -sycl-std=2020 -verify -fsyntax-only %s
3+
4+
// This test checks whether we diagnose cases of unmarked, undefined
5+
// functions called on device from either kernels or sycl device functions.
26

37
#include "sycl.hpp"
48

0 commit comments

Comments
 (0)