diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -367,4 +367,6 @@ def err_opencl_extension_and_feature_differs : Error< "options %0 and %1 are set to different values">; +def err_opencl_feature_requires : Error< + "feature %0 requires support of %1 feature">; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10111,7 +10111,8 @@ def err_opencl_invalid_access_qualifier : Error< "access qualifier can only be used for pipe and image type">; def err_opencl_invalid_read_write : Error< - "access qualifier %0 can not be used for %1 %select{|prior to OpenCL version 2.0}2">; + "access qualifier %0 can not be used for %1 %select{|prior to OpenCL C version 2.0 or in version 3.0 " + "and without __opencl_c_read_write_images feature}2">; def err_opencl_multiple_access_qualifiers : Error< "multiple access qualifiers">; def note_opencl_typedef_access_qualifier : Note< diff --git a/clang/include/clang/Basic/OpenCLOptions.h b/clang/include/clang/Basic/OpenCLOptions.h --- a/clang/include/clang/Basic/OpenCLOptions.h +++ b/clang/include/clang/Basic/OpenCLOptions.h @@ -19,6 +19,9 @@ namespace clang { +class DiagnosticsEngine; +class TargetInfo; + namespace { // This enum maps OpenCL version(s) into value. These values are used as // a mask to indicate in which OpenCL version(s) extension is a core or @@ -179,6 +182,16 @@ return OpenCLOptionInfo(std::forward(args)...).isAvailableIn(LO); } + // Diagnose feature dependencies for OpenCL C 3.0. Return false if target + // doesn't follow these requirements. + static bool diagnoseUnsupportedFeatureDependencies(const TargetInfo &TI, + DiagnosticsEngine &Diags); + + // Diagnose that features and equivalent extension are set to same values. + // Return false if target doesn't follow these requirements. + static bool diagnoseFeatureExtensionDifferences(const TargetInfo &TI, + DiagnosticsEngine &Diags); + private: // Option is enabled via pragma bool isEnabled(llvm::StringRef Ext) const; diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp --- a/clang/lib/Basic/OpenCLOptions.cpp +++ b/clang/lib/Basic/OpenCLOptions.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/OpenCLOptions.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/TargetInfo.h" namespace clang { @@ -104,4 +106,43 @@ Opt.getValue().Enabled = false; } +bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies( + const TargetInfo &TI, DiagnosticsEngine &Diags) { + // Feature pairs. First feature in a pair requires the second one to be + // supported. + static const llvm::StringMap DependentFeaturesMap = { + {"__opencl_c_read_write_images", "__opencl_c_images"}}; + + auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); + + bool IsValid = true; + for (auto &FeaturePair : DependentFeaturesMap) + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getKey()) && + !TI.hasFeatureEnabled(OpenCLFeaturesMap, FeaturePair.getValue())) { + IsValid = false; + Diags.Report(diag::err_opencl_feature_requires) + << FeaturePair.getKey() << FeaturePair.getValue(); + } + return IsValid; +} + +bool OpenCLOptions::diagnoseFeatureExtensionDifferences( + const TargetInfo &TI, DiagnosticsEngine &Diags) { + // Extensions and equivalent feature pairs. + static const llvm::StringMap FeatureExtensionMap = { + {"cl_khr_fp64", "__opencl_c_fp64"}}; + + auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); + + bool IsValid = true; + for (auto &ExtAndFeat : FeatureExtensionMap) + if (TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getKey()) != + TI.hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.getValue())) { + IsValid = false; + Diags.Report(diag::err_opencl_extension_and_feature_differs) + << ExtAndFeat.getKey() << ExtAndFeat.getValue(); + } + return IsValid; +} + } // end namespace clang diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -748,15 +748,6 @@ if (Opts.OpenCLCPlusPlus || Opts.OpenCLVersion < 300) return true; - // Feature and corresponding equivalent extension must be set - // simultaneously to the same value. - for (auto &ExtAndFeat : {std::make_pair("cl_khr_fp64", "__opencl_c_fp64")}) - if (hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.first) != - hasFeatureEnabled(OpenCLFeaturesMap, ExtAndFeat.second)) { - Diags.Report(diag::err_opencl_extension_and_feature_differs) - << ExtAndFeat.first << ExtAndFeat.second; - return false; - } - - return true; + return OpenCLOptions::diagnoseUnsupportedFeatureDependencies(*this, Diags) && + OpenCLOptions::diagnoseFeatureExtensionDifferences(*this, Diags); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7395,16 +7395,21 @@ } } - // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an - // image object can be read and written. - // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe - // object. Using the read_write (or __read_write) qualifier with the pipe - // qualifier is a compilation error. + // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that + // an image object can be read and written. OpenCL v2.0 s6.13.6 - A kernel + // cannot read from and write to the same pipe object. Using the read_write + // (or __read_write) qualifier with the pipe qualifier is a compilation error. + // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the + // __opencl_c_read_write_images feature, image objects specified as arguments + // to a kernel can additionally be declared to be read-write. if (const auto *PDecl = dyn_cast(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) { if ((!S.getLangOpts().OpenCLCPlusPlus && - S.getLangOpts().OpenCLVersion < 200) || + (S.getLangOpts().OpenCLVersion < 200) || + (S.getLangOpts().OpenCLVersion == 300 && + !S.getOpenCLOptions().isSupported("__opencl_c_read_write_images", + S.getLangOpts()))) || DeclTy->isPipeType()) { S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) << AL << PDecl->getType() << DeclTy->isImageType(); diff --git a/clang/test/Misc/opencl-c-3.0.incorrect_options.cl b/clang/test/Misc/opencl-c-3.0.incorrect_options.cl --- a/clang/test/Misc/opencl-c-3.0.incorrect_options.cl +++ b/clang/test/Misc/opencl-c-3.0.incorrect_options.cl @@ -1,4 +1,6 @@ -// RUN: not %clang_cc1 -cl-std=CL3.0 -triple spir-unknown-unknown -cl-ext=-__opencl_c_fp64,+cl_khr_fp64 %s 2>&1 | FileCheck %s -// RUN: not %clang_cc1 -cl-std=CL3.0 -triple spir-unknown-unknown -cl-ext=+__opencl_c_fp64,-cl_khr_fp64 %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -cl-std=CL3.0 -triple spir-unknown-unknown -cl-ext=-__opencl_c_fp64,+cl_khr_fp64 %s 2>&1 | FileCheck -check-prefix=CHECK-FP64 %s +// RUN: not %clang_cc1 -cl-std=CL3.0 -triple spir-unknown-unknown -cl-ext=+__opencl_c_fp64,-cl_khr_fp64 %s 2>&1 | FileCheck -check-prefix=CHECK-FP64 %s +// RUN: not %clang_cc1 -cl-std=CL3.0 -triple spir-unknown-unknown -cl-ext=+__opencl_c_read_write_images,-__opencl_c_images %s 2>&1 | FileCheck -check-prefix=CHECK-READ-WRITE-IMAGES %s -// CHECK: error: options cl_khr_fp64 and __opencl_c_fp64 are set to different values +// CHECK-FP64: error: options cl_khr_fp64 and __opencl_c_fp64 are set to different values +// CHECK-READ-WRITE-IMAGES: error: feature __opencl_c_read_write_images requires support of __opencl_c_images feature diff --git a/clang/test/SemaOpenCL/access-qualifier.cl b/clang/test/SemaOpenCL/access-qualifier.cl --- a/clang/test/SemaOpenCL/access-qualifier.cl +++ b/clang/test/SemaOpenCL/access-qualifier.cl @@ -1,12 +1,14 @@ -// RUN: %clang_cc1 -verify -pedantic -fsyntax-only -cl-std=CL1.2 %s -cl-ext=-cl_khr_3d_image_writes -// RUN: %clang_cc1 -verify -pedantic -fsyntax-only -cl-std=CL2.0 %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL1.2 %s -cl-ext=-cl_khr_3d_image_writes +// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL2.0 %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL3.0 %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-std=CL3.0 %s -cl-ext=-__opencl_c_read_write_images typedef image1d_t img1d_ro_default; // expected-note {{previously declared 'read_only' here}} typedef write_only image1d_t img1d_wo; // expected-note {{previously declared 'write_only' here}} typedef read_only image1d_t img1d_ro; -#if __OPENCL_C_VERSION__ >= 200 +#if (__OPENCL_C_VERSION__ == 200) || (__OPENCL_C_VERSION__ == 300 && defined(__opencl_c_read_write_images)) typedef read_write image1d_t img1d_rw; #endif @@ -17,10 +19,10 @@ void myWrite(write_only image1d_t); // expected-note {{passing argument to parameter here}} expected-note {{passing argument to parameter here}} void myRead(read_only image1d_t); // expected-note {{passing argument to parameter here}} -#if __OPENCL_C_VERSION__ >= 200 +#if (__OPENCL_C_VERSION__ == 200) || (__OPENCL_C_VERSION__ == 300 && defined(__opencl_c_read_write_images)) void myReadWrite(read_write image1d_t); #else -void myReadWrite(read_write image1d_t); // expected-error {{access qualifier 'read_write' can not be used for '__read_write image1d_t' prior to OpenCL version 2.0}} +void myReadWrite(read_write image1d_t); // expected-error {{access qualifier 'read_write' can not be used for '__read_write image1d_t' prior to OpenCL C version 2.0 or in version 3.0 and without __opencl_c_read_write_images feature}} #endif @@ -36,7 +38,7 @@ myWrite(img); } -#if __OPENCL_C_VERSION__ >= 200 +#if (__OPENCL_C_VERSION__ == 200) || (__OPENCL_C_VERSION__ == 300 && defined(__opencl_c_read_write_images)) kernel void k4(img1d_rw img) { myReadWrite(img); } @@ -62,26 +64,26 @@ kernel void k12(read_only read_only image1d_t i){} // expected-warning {{duplicate 'read_only' declaration specifier}} -#if __OPENCL_C_VERSION__ >= 200 +#if (__OPENCL_C_VERSION__ == 200) || (__OPENCL_C_VERSION__ == 300 && defined(__opencl_c_read_write_images)) kernel void k13(read_write pipe int i){} // expected-error{{access qualifier 'read_write' can not be used for 'read_only pipe int'}} #else -kernel void k13(__read_write image1d_t i){} // expected-error{{access qualifier '__read_write' can not be used for '__read_write image1d_t' prior to OpenCL version 2.0}} -#endif - -#if __OPENCL_C_VERSION__ >= 200 -void myPipeWrite(write_only pipe int); // expected-note {{passing argument to parameter here}} -kernel void k14(read_only pipe int p) { - myPipeWrite(p); // expected-error {{passing '__private read_only pipe int' to parameter of incompatible type 'write_only pipe int'}} -} +kernel void k13(__read_write image1d_t i){} // expected-error{{access qualifier '__read_write' can not be used for '__read_write image1d_t' prior to OpenCL C version 2.0 or in version 3.0 and without __opencl_c_read_write_images feature}} #endif #if __OPENCL_C_VERSION__ < 200 kernel void test_image3d_wo(write_only image3d_t img) {} // expected-error {{use of type '__write_only image3d_t' requires cl_khr_3d_image_writes support}} #endif -#if __OPENCL_C_VERSION__ >= 200 +#if (__OPENCL_C_VERSION__ == 200) || (__OPENCL_C_VERSION__ == 300 && defined(__opencl_c_read_write_images)) kernel void read_write_twice_typedef(read_write img1d_rw i){} // expected-warning {{duplicate 'read_write' declaration specifier}} -// expected-note@-74 {{previously declared 'read_write' here}} +// expected-note@-67 {{previously declared 'read_write' here}} +#endif + +#if OPENCL_C_VERSION__ >= 200 +void myPipeWrite(write_only pipe int); // expected-note {{passing argument to parameter here}} +kernel void k14(read_only pipe int p) { + myPipeWrite(p); // expected-error {{passing '__private read_only pipe int' to parameter of incompatible type 'write_only pipe int'}} +} kernel void pipe_ro_twice(read_only read_only pipe int i){} // expected-warning{{duplicate 'read_only' declaration specifier}} // Conflicting access qualifiers @@ -94,7 +96,7 @@ kernel void pass_ro_typedef_to_wo(ROPipeInt p) { myPipeWrite(p); // expected-error {{passing '__private ROPipeInt' (aka '__private read_only pipe int') to parameter of incompatible type 'write_only pipe int'}} - // expected-note@-25 {{passing argument to parameter here}} + // expected-note@-16 {{passing argument to parameter here}} } #endif diff --git a/clang/test/SemaOpenCL/unsupported-image.cl b/clang/test/SemaOpenCL/unsupported-image.cl --- a/clang/test/SemaOpenCL/unsupported-image.cl +++ b/clang/test/SemaOpenCL/unsupported-image.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -cl-std=CL3.0 -cl-ext=-__opencl_c_images %s +// RUN: %clang_cc1 -triple spir-unknown-unknown -verify -cl-std=CL3.0 -cl-ext=-__opencl_c_images,-__opencl_c_read_write_images %s // RUN: %clang_cc1 -triple spir-unknown-unknown -verify -cl-std=CL3.0 -cl-ext=+__opencl_c_images %s #ifdef __opencl_c_images