[OpenCL] Add support of __opencl_c_read_write_images feature macro
authorAnton Zabaznov <anton.zabaznov@intel.com>
Tue, 13 Jul 2021 12:09:14 +0000 (15:09 +0300)
committerAnton Zabaznov <anton.zabaznov@intel.com>
Tue, 13 Jul 2021 12:38:23 +0000 (15:38 +0300)
This feature requires support of __opencl_c_images, so diagnostics for that is provided as well

Reviewed By: Anastasia

Differential Revision: https://reviews.llvm.org/D104915

clang/include/clang/Basic/DiagnosticCommonKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Basic/OpenCLOptions.h
clang/lib/Basic/OpenCLOptions.cpp
clang/lib/Basic/Targets.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/test/Misc/opencl-c-3.0.incorrect_options.cl
clang/test/SemaOpenCL/access-qualifier.cl
clang/test/SemaOpenCL/unsupported-image.cl

index 4dab3a3b39ac327a9beb4d66d8a61a05cb32d297..eea5d8eaa10a171429f84bfde09a784245be12a0 100644 (file)
@@ -367,4 +367,6 @@ def warn_opencl_unsupported_core_feature : Warning<
 
 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">;
 }
index 21b9ce2d9ff2af68fca84116f446e7fb9864949a..2d62163e3dcc00f887952f6b8b51c243699f59b1 100644 (file)
@@ -10111,7 +10111,8 @@ def err_opencl_builtin_pipe_invalid_access_modifier : Error<
 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<
index 44fda029411f190794ea1675fb4394f19a267f0b..41db6b712a631e5a61ddd5f411dabb827c3c1e13 100644 (file)
@@ -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 @@ public:
     return OpenCLOptionInfo(std::forward<Args>(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;
index 7a647f02b1bd0e0b7122e9b80917094326a8d80e..2e215b185f66211d41e5d5811346d1a29b96a865 100644 (file)
@@ -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 @@ void OpenCLOptions::disableAll() {
     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<llvm::StringRef> 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<llvm::StringRef> 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
index 0755a946921e8b1860a2dbb1b770f4263f075311..ba91d0439968c998a28d1bf234b4ccee46a3b909 100644 (file)
@@ -748,15 +748,6 @@ bool TargetInfo::validateOpenCLTarget(const LangOptions &Opts,
   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);
 }
index 5db74630de7997325be59925003216fed48f2da1..87e5531a770567bf9a859c4ca186a6e6c315fdca 100644 (file)
@@ -7395,16 +7395,21 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
     }
   }
 
-  // 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<ParmVarDecl>(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();
index 493c5fde105412b846305b47cea9711ee91df26a..07151d9a08c81f153d3bfe30fbb506e13281d098 100644 (file)
@@ -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
index 115944c9f3e7944457df72d4d71388824c474667..c538e73253ce0ffb51cda48a395abe79e79caf71 100644 (file)
@@ -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 @@ typedef read_only int IntRO; // expected-error {{access qualifier can only be us
 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 @@ kernel void k3(img1d_wo img) {
   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 k11(read_only write_only image1d_t i){} // expected-error{{multiple
 
 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 pipe_ro_twice_typedef(read_only ROPipeInt i){} // expected-warning{{
 
 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
 
index 3aed9c1f13199df4f480702c3cdb9c7799219a04..9ffbb1aef0c469984fc60309ce0e172cc855f3c8 100644 (file)
@@ -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