Fznamznon updated this revision to Diff 251735. Fznamznon added a comment. Herald added a subscriber: mgorny.
Added diagnosing of __float128 type usage. See the summary of revision for details. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D74387/new/ https://reviews.llvm.org/D74387 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Sema/Sema.h clang/lib/Sema/CMakeLists.txt clang/lib/Sema/SemaAvailability.cpp clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaSYCL.cpp clang/lib/Sema/SemaType.cpp clang/test/SemaSYCL/float128.cpp
Index: clang/test/SemaSYCL/float128.cpp =================================================================== --- /dev/null +++ clang/test/SemaSYCL/float128.cpp @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -triple spir64 -fsycl -fsycl-is-device -verify -fsyntax-only %s +// RUN: %clang_cc1 -fsycl -fsycl-is-device -fsyntax-only %s + +template <class T> +class Z { +public: + // TODO: If T is __float128 This might be a problem + T field; + //expected-error@+1 2{{'__float128' is not supported on this target}} + __float128 field1; +}; + +void host_ok(void) { + __float128 A; + int B = sizeof(__float128); + Z<__float128> C; + C.field1 = A; +} + +void usage() { + //expected-error@+1 5{{'__float128' is not supported on this target}} + __float128 A; + Z<__float128> C; + //expected-error@+2 {{'A' is unavailable}} + //expected-error@+1 {{'field1' is unavailable}} + C.field1 = A; + //expected-error@+1 {{'A' is unavailable}} + decltype(A) D; + + //expected-error@+1 {{'A' is unavailable}} + auto foo1 = [=]() { + //expected-error@+1 {{'__float128' is not supported on this target}} + __float128 AA; + //expected-error@+1 {{'A' is unavailable}} + auto BB = A; + BB += 1; + }; + + //expected-note@+1 {{called by 'usage'}} + foo1(); +} + +template <typename t> +void foo2(){}; + +//expected-error@+1 {{'__float128 (__float128)' is not supported on this target}} +__float128 foo(__float128 P) { return P; } + +template <typename Name, typename Func> +__attribute__((sycl_kernel)) void kernel(Func kernelFunc) { + //expected-note@+1 5{{called by 'kernel}} + kernelFunc(); + //expected-error@+1 {{'__float128' is not supported on this target}} + __float128 A; +} + +int main() { + //expected-error@+1 2{{'__float128' is not supported on this target}} + __float128 CapturedToDevice = 1; + host_ok(); + kernel<class variables>([=]() { + //expected-error@+1 {{'CapturedToDevice' is unavailable}} + decltype(CapturedToDevice) D; + //expected-error@+1 {{'CapturedToDevice' is unavailable}} + auto C = CapturedToDevice; + //expected-error@+1 {{'__float128' is not supported on this target}} + __float128 BBBB; + Z<__float128> S; + //expected-error@+1 {{'field1' is unavailable}} + S.field1 += 1; + S.field = 1; + }); + + kernel<class functions>([=]() { + //expected-note@+1 2{{called by 'operator()'}} + usage(); + // expected-error@+1 2{{'__float128' is not supported on this target}} + __float128 BBBB; + // expected-error@+2 {{'BBBB' is unavailable}} + // expected-error@+1 {{'foo' is unavailable}} + auto A = foo(BBBB); + }); + + kernel<class ok>([=]() { + Z<__float128> S; + foo2<__float128>(); + // TODO: this shouldn't be diagnosed + // expected-error@+1 {{'__float128' is not supported on this target}} + int E = sizeof(__float128); + }); + return 0; +} Index: clang/lib/Sema/SemaType.cpp =================================================================== --- clang/lib/Sema/SemaType.cpp +++ clang/lib/Sema/SemaType.cpp @@ -1516,10 +1516,21 @@ break; case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type() && + !S.getLangOpts().SYCLIsDevice && !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; Result = Context.Float128Ty; + if (!S.Context.getTargetInfo().hasFloat128Type() && + S.getLangOpts().SYCLIsDevice && + S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add(sema::DelayedDiagnostic::makeForbiddenType( + DS.getTypeSpecTypeLoc(), diag::err_type_unsupported, Result, + /*ignored*/ 0)); + S.SYCLDiagIfDeviceCode(DS.getTypeSpecTypeLoc(), + diag::err_type_unsupported) + << Result; + } break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool break; Index: clang/lib/Sema/SemaSYCL.cpp =================================================================== --- /dev/null +++ clang/lib/Sema/SemaSYCL.cpp @@ -0,0 +1,63 @@ +//===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This implements Semantic Analysis for SYCL constructs. +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; + +// ----------------------------------------------------------------------------- +// SYCL device specific diagnostics implementation +// ----------------------------------------------------------------------------- + +Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); + DeviceDiagBuilder::Kind DiagKind = [this, FD] { + if (!FD) + return DeviceDiagBuilder::K_Nop; + if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) + return DeviceDiagBuilder::K_ImmediateWithCallStack; + return DeviceDiagBuilder::K_Deferred; + }(); + return DeviceDiagBuilder(DiagKind, Loc, DiagID, FD, *this); +} + +bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + assert(Callee && "Callee may not be null."); + + // Errors in unevaluated context don't need to be generated, + // so we can safely skip them. + if (isUnevaluatedContext() || isConstantEvaluated()) + return true; + + FunctionDecl *Caller = dyn_cast<FunctionDecl>(getCurLexicalContext()); + + bool CallerKnownEmitted = + getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted; + + // If the caller is known-emitted, mark the callee as known-emitted. + // Otherwise, mark the call in our call graph so we can traverse it later. + if (CallerKnownEmitted) + markKnownEmitted(*this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) { + return S.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted; + }); + else + DeviceCallGraph[Caller].insert({Callee, Loc}); + + DeviceDiagBuilder::Kind DiagKind = DeviceDiagBuilder::K_Nop; + + return DiagKind != DeviceDiagBuilder::K_Immediate && + DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack; +} Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -292,6 +292,9 @@ if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; + + if (getLangOpts().SYCLIsDevice && !checkSYCLDeviceFunction(Loc, FD)) + return true; } if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -15849,6 +15852,9 @@ if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); + if (getLangOpts().SYCLIsDevice) + checkSYCLDeviceFunction(Loc, Func); + // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { runWithSufficientStackSpace(Loc, [&] { Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -14761,6 +14761,9 @@ MarkFunctionReferenced(ConstructLoc, Constructor); if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) return ExprError(); + if (getLangOpts().SYCLIsDevice && + !checkSYCLDeviceFunction(ConstructLoc, Constructor)) + return ExprError(); return CXXConstructExpr::Create( Context, DeclInitType, ConstructLoc, Constructor, Elidable, Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -7763,6 +7763,13 @@ static bool isForbiddenTypeAllowed(Sema &S, Decl *D, const DelayedDiagnostic &diag, UnavailableAttr::ImplicitReason &reason) { + // SYCL: delay the diagnostic until we know that the function will be actually + // emitted + if (S.getLangOpts().SYCLIsDevice) { + reason = UnavailableAttr::IR_SYCLForbiddenType; + return true; + } + // Private ivars are always okay. Unfortunately, people don't // always properly make their ivars private, even in system headers. // Plus we need to make fields okay, too. Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -18024,6 +18024,11 @@ } Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { + // Due to SYCL functions can be template we check if they have appropriate + // attribute prior to checking if it is a template + if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelAttr>()) + return FunctionEmissionStatus::Emitted; + // Templates are emitted when they're instantiated. if (FD->isDependentContext()) return FunctionEmissionStatus::TemplateDiscarded; Index: clang/lib/Sema/SemaAvailability.cpp =================================================================== --- clang/lib/Sema/SemaAvailability.cpp +++ clang/lib/Sema/SemaAvailability.cpp @@ -474,6 +474,10 @@ flagARCError(); diag_available_here = diag::note_arc_field_with_ownership; break; + + case UnavailableAttr::IR_SYCLForbiddenType: + diag_available_here = diag::err_type_unsupported; + break; } } } @@ -526,7 +530,10 @@ S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl << FixIts; + if (S.getLangOpts().SYCLIsDevice) + S.SYCLDiagIfDeviceCode(Loc, diag) << ReferringDecl; + else + S.Diag(Loc, diag) << ReferringDecl << FixIts; if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; @@ -535,8 +542,12 @@ S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - S.Diag(NoteLocation, diag_available_here) - << OffendingDecl << available_here_select_kind; + if (S.getLangOpts().SYCLIsDevice) + S.SYCLDiagIfDeviceCode(NoteLocation, diag_available_here) + << cast<ValueDecl>(OffendingDecl)->getType(); + else + S.Diag(NoteLocation, diag_available_here) + << OffendingDecl << available_here_select_kind; } void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) { Index: clang/lib/Sema/CMakeLists.txt =================================================================== --- clang/lib/Sema/CMakeLists.txt +++ clang/lib/Sema/CMakeLists.txt @@ -59,6 +59,7 @@ SemaStmt.cpp SemaStmtAsm.cpp SemaStmtAttr.cpp + SemaSYCL.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp SemaTemplateInstantiate.cpp Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -12227,6 +12227,40 @@ ConstructorDestructor, BuiltinFunction }; + /// 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: + /// + /// Diagnose __float128 type usage only from SYCL device code if the current + /// target doesn't support it + /// if (!S.Context.getTargetInfo().hasFloat128Type() && + /// S.getLangOpts().SYCLIsDevice) + /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; + DeviceDiagBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); + + /// Check whether we're allowed to call Callee from the current context. + /// + /// - If the call is never allowed in a semantically-correct program + /// emits an error and returns false. + /// + /// - If the call is allowed in semantically-correct programs, but only if + /// it's never codegen'ed, creates a deferred diagnostic to be emitted if + /// and when the caller is codegen'ed, and returns true. + /// + /// - Otherwise, returns true without emitting any diagnostics. + /// + /// Adds Callee to DeviceCallGraph if we don't know if its caller will be + /// codegen'ed yet. + bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); }; /// RAII object that enters a new expression evaluation context. Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -2317,7 +2317,8 @@ "IR_ForbiddenWeak", "IR_ARCForbiddenConversion", "IR_ARCInitReturnsUnrelated", - "IR_ARCFieldWithOwnership"], 1, /*fake*/ 1>]; + "IR_ARCFieldWithOwnership", + "IR_SYCLForbiddenType"], 1, /*fake*/ 1>]; let Documentation = [Undocumented]; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits