Skip to content
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

[SYCL] Diagnose __float128 type usage in device code, fixes and cleanups #971

Merged
merged 5 commits into from
Jan 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -12079,11 +12079,33 @@ class Sema final {
KernelCallDllimportFunction,
KernelCallVariadicFunction
};
DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);
bool isKnownGoodSYCLDecl(const Decl *D);
void ConstructOpenCLKernel(FunctionDecl *KernelCallerFunc, MangleContext &MC);
void MarkDevice(void);
bool CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee);

/// Creates a DeviceDiagBuilder that emits the diagnostic if the current
/// context is "used as device code".
///
/// - If CurLexicalContext is a kernel function or it is known that the
/// function will be emitted for the device, emits the diagnostics
/// immediately.
/// - If CurLexicalContext is a function and we are compiling
/// for the device, but we don't know that this function will be codegen'ed
/// for devive yet, creates a diagnostic which is emitted if and when we
/// realize that the function will be codegen'ed.
///
/// Example usage:
///
/// Variables with thread storage duration are not allowed to be used in SYCL
/// device code
/// if (getLangOpts().SYCLIsDevice)
/// SYCLDiagIfDeviceCode(Loc, diag::err_thread_unsupported);
DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);

/// Checks if Callee function is a device function and emits
/// diagnostics if it is known that it is a device function, adds this
/// function to the DeviceCallGraph otherwise.
void checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee);
};

/// RAII object that enters a new expression evaluation context.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,9 @@ Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
if (getLangOpts().CUDA)
return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID)
: CUDADiagIfHostCode(Loc, DiagID);
// TODO: analyze which usages of targetDiag could be reused for SYCL.
// if (getLangOpts().SYCLIsDevice)
// return SYCLDiagIfDeviceCode(Loc, DiagID);
return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID,
getCurFunctionDecl(), *this);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14644,7 +14644,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor))
return ExprError();
if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(ConstructLoc, Constructor);
checkSYCLDeviceFunction(ConstructLoc, Constructor);

return CXXConstructExpr::Create(
Context, DeclInitType, ConstructLoc, Constructor, Elidable,
Expand Down
14 changes: 3 additions & 11 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
return true;

if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(Loc, FD);
checkSYCLDeviceFunction(Loc, FD);
}

if (auto *MD = dyn_cast<CXXMethodDecl>(D)) {
Expand Down Expand Up @@ -15649,7 +15649,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (getLangOpts().CUDA)
CheckCUDACall(Loc, Func);
if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(Loc, Func);
checkSYCLDeviceFunction(Loc, Func);

// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
Expand Down Expand Up @@ -17219,15 +17219,7 @@ namespace {
}

void VisitCXXNewExpr(CXXNewExpr *E) {
FunctionDecl *FD = E->getOperatorNew();
if (FD && S.getLangOpts().SYCLIsDevice) {
if (FD->isReplaceableGlobalAllocationFunction())
S.SYCLDiagIfDeviceCode(E->getExprLoc(), diag::err_sycl_restrict)
<< S.KernelAllocateStorage;
else if (FunctionDecl *Def = FD->getDefinition())
S.CheckSYCLCall(E->getExprLoc(), Def);
}
if (FD)
if (E->getOperatorNew())
S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew());
if (E->getOperatorDelete())
S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete());
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2171,16 +2171,15 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (DiagnoseUseOfDecl(OperatorNew, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorNew);
if (getLangOpts().SYCLIsDevice) {
CheckSYCLCall(StartLoc, OperatorNew);
}
if (getLangOpts().SYCLIsDevice &&
OperatorNew->isReplaceableGlobalAllocationFunction())
SYCLDiagIfDeviceCode(StartLoc, diag::err_sycl_restrict)
<< KernelAllocateStorage;
}
if (OperatorDelete) {
if (DiagnoseUseOfDecl(OperatorDelete, StartLoc))
return ExprError();
MarkFunctionReferenced(StartLoc, OperatorDelete);
if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(StartLoc, OperatorDelete);
}

return CXXNewExpr::Create(Context, UseGlobal, OperatorNew, OperatorDelete,
Expand Down
6 changes: 0 additions & 6 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12916,8 +12916,6 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
FnDecl->getType()->castAs<FunctionProtoType>()))
return ExprError();

if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(OpLoc, FnDecl);
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
Expand Down Expand Up @@ -13270,8 +13268,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
isa<CXXMethodDecl>(FnDecl), OpLoc, TheCall->getSourceRange(),
VariadicDoesNotApply);

if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(OpLoc, FnDecl);
ExprResult R = MaybeBindToTemporary(TheCall);
if (R.isInvalid())
return ExprError();
Expand Down Expand Up @@ -13633,8 +13629,6 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
Method->getType()->castAs<FunctionProtoType>()))
return ExprError();

if (getLangOpts().SYCLIsDevice)
CheckSYCLCall(RLoc, FnDecl);
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
Expand Down
21 changes: 7 additions & 14 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
// new operator and any user-defined overloads that
// do not allocate storage are permitted.
if (FunctionDecl *FD = E->getOperatorNew()) {
if (FD->isReplaceableGlobalAllocationFunction()) {
SemaRef.Diag(E->getExprLoc(), diag::err_sycl_restrict)
<< Sema::KernelAllocateStorage;
} else if (FunctionDecl *Def = FD->getDefinition()) {
if (FunctionDecl *Def = FD->getDefinition()) {
if (!Def->hasAttr<SYCLDeviceAttr>()) {
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
SemaRef.addSyclDeviceDecl(Def);
Expand Down Expand Up @@ -521,8 +518,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
if (!CheckSYCLType(Field->getType(), Field->getSourceRange(),
Visited)) {
if (SemaRef.getLangOpts().SYCLIsDevice)
SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(),
diag::note_sycl_used_here);
SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here);
return false;
}
}
Expand All @@ -531,8 +527,7 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
if (!CheckSYCLType(Field->getType(), Field->getSourceRange(),
Visited)) {
if (SemaRef.getLangOpts().SYCLIsDevice)
SemaRef.SYCLDiagIfDeviceCode(Loc.getBegin(),
diag::note_sycl_used_here);
SemaRef.Diag(Loc.getBegin(), diag::note_sycl_used_here);
return false;
}
}
Expand Down Expand Up @@ -1390,8 +1385,7 @@ void Sema::MarkDevice(void) {

// Do we know that we will eventually codegen the given function?
static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
if (!FD)
return true; // Seen in LIT testing
assert(FD && "Given function may not be null.");

if (FD->hasAttr<SYCLDeviceAttr>() || FD->hasAttr<SYCLKernelAttr>())
return true;
Expand All @@ -1407,16 +1401,16 @@ Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
"Should only be called during SYCL compilation");
FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
DeviceDiagBuilder::Kind DiagKind = [this, FD] {
if (ConstructingOpenCLKernel)
if (ConstructingOpenCLKernel || !FD)
Copy link
Contributor

Choose a reason for hiding this comment

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

FD can be NULL in the cases where getCurLexicalContext is TU/namespace/record/etc. Don't we want to diagnose always in these cases, since they are likely static initializers? Something like:

static auto Global = throw 3;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we don't want to diagnose things like static initializers always (if they are not completely invalid for both host and device, but this case is diagnosed out of the box, I suppose).
Yes, I understand that static initializes run before main in regular C++, but there is no main in SYCL device code, only kernels and everything that used by kernels (functions/variables).
We want to diagnose only things that can get into device code. Things like static initializers shouldn't get into device code at all due to SYCL specific. SYCL spec even says: every variable with static storage duration that are odr-used inside a kernel must be const or constexpr and zero-initialized or constant-initialized.
I think all these rules tell that static initializers aren't executed on device and variables initialized in such way cannot be used inside the device code.

In addition, if we will diagnose such cases always, it will prevent from writing regular c++ code for host...

I think we want to diagnose case with in-class initializers, and in this case getCurLexicalContext is record, but we also want to diagnose it with deferred diagnostic because diagnostic is only needed if corresponding type is used in device code, but it requires changes in common parts of deferred diagnostics system, I'm looking into it #1032 ...

return DeviceDiagBuilder::K_Nop;
else if (isKnownEmitted(*this, FD))
if (isKnownEmitted(*this, FD))
return DeviceDiagBuilder::K_ImmediateWithCallStack;
return DeviceDiagBuilder::K_Deferred;
}();
return DeviceDiagBuilder(DiagKind, Loc, DiagID, FD, *this);
}

bool Sema::CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee) {
void Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
assert(Callee && "Callee may not be null.");
FunctionDecl *Caller = dyn_cast<FunctionDecl>(getCurLexicalContext());

Expand All @@ -1426,7 +1420,6 @@ bool Sema::CheckSYCLCall(SourceLocation Loc, FunctionDecl *Callee) {
markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
else if (Caller)
DeviceCallGraph[Caller].insert({Callee, Loc});
return true;
}

// -----------------------------------------------------------------------------
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaStmtAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Skip all the checks if we are compiling SYCL device code, but the function
// is not marked to be used on device, this code won't be codegen'ed anyway.
if (getLangOpts().SYCLIsDevice) {
SYCLDiagIfDeviceCode(AsmLoc, diag::err_sycl_restrict)
Copy link
Contributor

Choose a reason for hiding this comment

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

Has anything changed in this file, or is this simply a formatting change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just formatting.

<< KernelUseAssembly;
SYCLDiagIfDeviceCode(AsmLoc, diag::err_sycl_restrict) << KernelUseAssembly;
return new (Context)
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs,
NumInputs, Names, Constraints, Exprs.data(), AsmString,
NumClobbers, Clobbers, NumLabels, RParenLoc);
GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, NumInputs,
Names, Constraints, Exprs.data(), AsmString, NumClobbers,
Clobbers, NumLabels, RParenLoc);
}

FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1500,11 +1500,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.DoubleTy;
break;
case DeclSpec::TST_float128:
if (!S.Context.getTargetInfo().hasFloat128Type() &&
!S.getLangOpts().SYCLIsDevice &&
!(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
if (!S.Context.getTargetInfo().hasFloat128Type() &&
S.getLangOpts().SYCLIsDevice)
S.SYCLDiagIfDeviceCode(DS.getTypeSpecTypeLoc(),
diag::err_type_unsupported)
<< "__float128";
else if (!S.Context.getTargetInfo().hasFloat128Type() &&
!(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
<< "__float128";
<< "__float128";
Result = Context.Float128Ty;
break;
case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaSYCL/inline-asm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ void bar() {
#endif // LINUX_ASM
}

template <typename name, typename Func>
template <typename Name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
// expected-note@+1 {{called by 'kernel_single_task<fake_kernel, (lambda}}
kernelFunc();
Expand Down
6 changes: 4 additions & 2 deletions clang/test/SemaSYCL/restrict-recursion3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ void kernel3(void) {
using myFuncDef = int(int,int);

void usage3(myFuncDef functionPtr) {
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
int *ip = new int;
kernel3();
}

Expand All @@ -26,14 +28,14 @@ int addInt(int n, int m) {
template <typename name, typename Func>
// expected-note@+1 2{{function implemented using recursion declared here}}
__attribute__((sycl_kernel)) void kernel_single_task2(Func kernelFunc) {
// expected-note@+1 {{called by 'kernel_single_task2}}
kernelFunc();
// expected-error@+1 2{{SYCL kernel cannot allocate storage}}
int *ip = new int;
// expected-error@+1 2{{SYCL kernel cannot call a recursive function}}
kernel_single_task2<name, Func>(kernelFunc);
}

int main() {
// expected-note@+1 {{called by 'operator()'}}
kernel_single_task2<class fake_kernel>([]() { usage3( &addInt ); });
return fib(5);
}
6 changes: 4 additions & 2 deletions clang/test/SemaSYCL/restrict-recursion4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ void kernel2(void) {
using myFuncDef = int(int,int);

void usage2(myFuncDef functionPtr) {
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
int *ip = new int;
// expected-error@+1 {{SYCL kernel cannot call a recursive function}}
kernel2();
}
Expand All @@ -28,12 +30,12 @@ int addInt(int n, int m) {

template <typename name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
int *ip = new int;
// expected-note@+1 {{called by 'kernel_single_task}}
kernelFunc();
}

int main() {
// expected-note@+1 {{called by 'operator()'}}
kernel_single_task<class fake_kernel>([]() {usage2(&addInt);});
return fib(5);
}
16 changes: 12 additions & 4 deletions clang/test/SemaSYCL/sycl-restrict.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -Wno-return-type -verify -fsyntax-only -std=c++17 %s
// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -fno-sycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s
// RUN: %clang_cc1 -fcxx-exceptions -fsycl-is-device -DALLOW_FP=1 -fsycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s
// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -Wno-return-type -verify -fsyntax-only -std=c++17 %s
// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -fno-sycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s
// RUN: %clang_cc1 -fcxx-exceptions -triple spir64 -fsycl-is-device -DALLOW_FP=1 -fsycl-allow-func-ptr -Wno-return-type -verify -fsyntax-only -std=c++17 %s


namespace std {
Expand Down Expand Up @@ -65,6 +65,7 @@ bool isa_B(A *a) {
// expected-error@+1 {{SYCL kernel cannot allocate storage}}
int *ip = new int;
int i; int *p3 = new(&i) int; // no error on placement new
// expected-note@+1 {{called by 'isa_B'}}
OverloadedNewDelete *x = new( struct OverloadedNewDelete );
auto y = new struct OverloadedNewDelete [5];
// expected-error@+1 {{SYCL kernel cannot use rtti}}
Expand Down Expand Up @@ -102,6 +103,7 @@ using myFuncDef = int(int,int);

void eh_ok(void)
{
__float128 A;
try {
;
} catch (...) {
Expand Down Expand Up @@ -138,6 +140,9 @@ void usage(myFuncDef functionPtr) {
Check_RTTI_Restriction::kernel1<class kernel_name>([]() {
Check_RTTI_Restriction::A *a;
Check_RTTI_Restriction::isa_B(a); });

// expected-error@+1 {{__float128 is not supported on this target}}
__float128 A;
}

namespace ns {
Expand Down Expand Up @@ -172,9 +177,12 @@ int use2 ( a_type ab, a_type *abp ) {
// expected-note@+1 {{called by 'use2'}}
eh_not_ok();
Check_RTTI_Restriction:: A *a;
// expected-note@+1 2{{called by 'use2'}}
Check_RTTI_Restriction:: isa_B(a);
// expected-note@+1 {{called by 'use2'}}
usage(&addInt);
Check_User_Operators::Fraction f1(3, 8), f2(1, 2), f3(10, 2);
// expected-note@+1 {{called by 'use2'}}
if (f1 == f2) return false;
}

Expand All @@ -183,7 +191,7 @@ __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
kernelFunc();
a_type ab;
a_type *p;
// expected-note@+1 {{called by 'kernel_single_task'}}
// expected-note@+1 5{{called by 'kernel_single_task'}}
use2(ab, p);
}

Expand Down