[OpenCL] Add support of OpenCL C 3.0 __opencl_c_fp64

There already exists cl_khr_fp64 extension. So OpenCL C 3.0
and higher should use the feature, earlier versions still
use the extension. OpenCL C 3.0 API spec states that extension
will be not described in the option string if corresponding
optional functionality is not supported (see 4.2. Querying Devices).
Due to that fact the usage of features for OpenCL C 3.0 must
be as follows:

```
$ clang -Xclang -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 ...

$ clang -Xclang -cl-ext=-cl_khr_fp64,-__opencl_c_fp64 ...
```

e.g. the feature and the equivalent extension (if exists)
must be set to the same values

Reviewed By: Anastasia

Differential Revision: https://reviews.llvm.org/D96524
This commit is contained in:
Anton Zabaznov 2021-05-21 14:07:23 +03:00
parent 469833f418
commit 826905787a
12 changed files with 80 additions and 14 deletions

View File

@ -339,7 +339,24 @@ Missing features or with limited support
.. _opencl_300:
OpenCL 3.0 Implementation Status
OpenCL C 3.0 Usage
================================
OpenCL C 3.0 language standard makes most OpenCL C 2.0 features optional. Optional
functionality in OpenCL C 3.0 is indicated with the presence of feature-test macros
(list of feature-test macros is `here <https://www.khronos.org/registry/OpenCL/specs/3.0-unified/html/OpenCL_C.html#features>`_).
Command-line flag :ref:`-cl-ext <opencl_cl_ext>` can be used to override features supported by a target.
For cases when there is an associated extension for a specific feature (fp64 and 3d image writes)
user should specify both (extension and feature) in command-line flag:
.. code-block:: console
$ clang -cc1 -cl-std=CL3.0 -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 ...
$ clang -cc1 -cl-std=CL3.0 -cl-ext=-cl_khr_fp64,-__opencl_c_fp64 ...
OpenCL C 3.0 Implementation Status
================================
The following table provides an overview of features in OpenCL C 3.0 and their

View File

@ -364,4 +364,7 @@ def warn_poison_system_directories : Warning <
def warn_opencl_unsupported_core_feature : Warning<
"%0 is a core feature in %select{OpenCL C|C++ for OpenCL}1 version %2 but not supported on this target">,
InGroup<OpenCLCoreFeaturesDiagGroup>, DefaultIgnore;
def err_opencl_extension_and_feature_differs : Error<
"options %0 and %1 are set to different values">;
}

View File

@ -118,7 +118,8 @@ def warn_float_underflow : Warning<
"magnitude of floating-point constant too small for type %0; minimum is %1">,
InGroup<LiteralRange>;
def warn_double_const_requires_fp64 : Warning<
"double precision constant requires cl_khr_fp64, casting to single precision">;
"double precision constant requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0, "
"casting to single precision">;
def err_half_const_requires_fp16 : Error<
"half precision constant requires cl_khr_fp16">;
@ -10027,6 +10028,8 @@ def err_opencl_requires_extension : Error<
def ext_opencl_double_without_pragma : Extension<
"Clang permits use of type 'double' regardless pragma if 'cl_khr_fp64' is"
" supported">;
def err_opencl_double_requires_extension : Error<
"use of type 'double' requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0 support">;
def warn_opencl_generic_address_space_arg : Warning<
"passing non-generic address space pointer to %0"
" may cause dynamic conversion affecting performance">,

View File

@ -743,7 +743,20 @@ bool TargetInfo::validateOpenCLTarget(const LangOptions &Opts,
diagnoseNotSupportedCore(#Ext, __VA_ARGS__);
#include "clang/Basic/OpenCLExtensions.def"
// For now assume that OpenCL target is always
// valid and just provide necessary diagnostics
// Validate that feature macros are set properly for OpenCL C 3.0.
// In other cases assume that target is always valid.
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;
}

View File

@ -292,6 +292,7 @@ public:
bool IsAMDGCN = isAMDGCN(getTriple());
Opts["cl_khr_fp64"] = hasFP64();
Opts["__opencl_c_fp64"] = hasFP64();
if (IsAMDGCN || GPUKind >= llvm::AMDGPU::GK_CEDAR) {
Opts["cl_khr_byte_addressable_store"] = true;

View File

@ -138,6 +138,7 @@ public:
Opts["__cl_clang_non_portable_kernel_param_types"] = true;
Opts["cl_khr_fp64"] = true;
Opts["__opencl_c_fp64"] = true;
Opts["cl_khr_byte_addressable_store"] = true;
Opts["cl_khr_global_int32_base_atomics"] = true;
Opts["cl_khr_global_int32_extended_atomics"] = true;

View File

@ -135,8 +135,9 @@ bool CompilerInstance::createTarget() {
// We should do it here because target knows nothing about
// language options when it's being created.
if (getLangOpts().OpenCL)
getTarget().validateOpenCLTarget(getLangOpts(), getDiagnostics());
if (getLangOpts().OpenCL &&
!getTarget().validateOpenCLTarget(getLangOpts(), getDiagnostics()))
return false;
// Inform the target of the language options.
// FIXME: We shouldn't need to do this, the target should be immutable once

View File

@ -3843,7 +3843,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
} else if (getLangOpts().OpenCL && !getOpenCLOptions().isAvailableOption(
"cl_khr_fp64", getLangOpts())) {
// Impose single-precision float type when cl_khr_fp64 is not enabled.
Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64);
Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64)
<< (getLangOpts().OpenCLVersion >= 300);
Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get();
}
}

View File

@ -1526,8 +1526,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
case DeclSpec::TST_double:
if (S.getLangOpts().OpenCL) {
if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
<< 0 << Context.DoubleTy << "cl_khr_fp64";
S.Diag(DS.getTypeSpecTypeLoc(),
diag::err_opencl_double_requires_extension)
<< (S.getLangOpts().OpenCLVersion >= 300);
else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts()))
S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma);
}

View File

@ -1,10 +1,12 @@
// RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=-+cl_khr_fp64 -triple spir-unknown-unknown -disable-llvm-passes -emit-llvm -o - %s | FileCheck -check-prefixes=FP64,ALL %s
// RUN: %clang_cc1 -cl-std=CL1.2 -cl-ext=-cl_khr_fp64 -triple spir-unknown-unknown -disable-llvm-passes -emit-llvm -o - %s | FileCheck -check-prefixes=NOFP64,ALL %s
// RUN: %clang_cc1 -cl-std=CL3.0 -cl-ext=+__opencl_c_fp64,+cl_khr_fp64 -triple spir-unknown-unknown -disable-llvm-passes -emit-llvm -o - %s | FileCheck -check-prefixes=FP64,ALL %s
// RUN: %clang_cc1 -cl-std=CL3.0 -cl-ext=-__opencl_c_fp64,-cl_khr_fp64 -triple spir-unknown-unknown -disable-llvm-passes -emit-llvm -o - %s | FileCheck -check-prefixes=NOFP64,ALL %s
typedef __attribute__((ext_vector_type(2))) float float2;
typedef __attribute__((ext_vector_type(2))) half half2;
#ifdef cl_khr_fp64
#if defined(cl_khr_fp64) || defined(__opencl_c_fp64)
typedef __attribute__((ext_vector_type(2))) double double2;
#endif
@ -28,7 +30,7 @@ kernel void test_printf_half2(half2 arg) {
printf("%v2hf", arg);
}
#ifdef cl_khr_fp64
#if defined(cl_khr_fp64) || defined(__opencl_c_fp64)
// FP64-LABEL: @test_printf_double2(
// FP64: call spir_func i32 (i8 addrspace(2)*, ...) @printf(i8 addrspace(2)* getelementptr inbounds ([6 x i8], [6 x i8] addrspace(2)* @.str.2, i32 0, i32 0), <2 x double> %0)
kernel void test_printf_double2(double2 arg) {

View File

@ -0,0 +1,4 @@
// 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
// CHECK: error: options cl_khr_fp64 and __opencl_c_fp64 are set to different values

View File

@ -5,6 +5,7 @@
// Test with a target not supporting fp64.
// RUN: %clang_cc1 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -DNOFP64 -DNOFP16
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -DNOFP64 -DNOFP16
// Test with some extensions enabled or disabled by cmd-line args
//
@ -16,12 +17,18 @@
// RUN: %clang_cc1 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -cl-ext=+all
// RUN: %clang_cc1 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -cl-ext=+all,-cl_khr_fp64 -DNOFP64
// RUN: %clang_cc1 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -cl-ext=-all,+cl_khr_fp64 -DNOFP16
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-all -DNOFP64 -DNOFP16
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -cl-ext=+all -DFP64
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple r600-unknown-unknown -target-cpu r600 -verify -pedantic -fsyntax-only -cl-ext=+all,-__opencl_c_fp64,-cl_khr_fp64 -DNOFP64
//
// Concatenating
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-cl_khr_fp64 -cl-ext=+cl_khr_fp64
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-cl_khr_fp64,+cl_khr_fp64
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-all -cl-ext=+cl_khr_fp64 -cl-ext=+cl_khr_fp16 -cl-ext=-cl_khr_fp64 -DNOFP64
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-all -cl-ext=+cl_khr_fp64,-cl_khr_fp64,+cl_khr_fp16 -DNOFP64
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-__opencl_c_fp64,-cl_khr_fp64 -cl-ext=+__opencl_c_fp64,+cl_khr_fp64 -DFP64
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-__opencl_c_fp64,+__opencl_c_fp64,+cl_khr_fp64 -DFP64
// RUN: %clang_cc1 -cl-std=CL3.0 %s -triple spir-unknown-unknown -verify -pedantic -fsyntax-only -cl-ext=-__opencl_c_fp64,-cl_khr_fp64 -DNOFP64
// Test with -finclude-default-header, which includes opencl-c.h. opencl-c.h
// disables all extensions by default, but supported core extensions for a
@ -85,18 +92,30 @@ int isfinite(float x) {
void f2(void) {
double d;
#ifdef NOFP64
// expected-error@-2{{use of type 'double' requires cl_khr_fp64 support}}
#if (defined(__OPENCL_C_VERSION__) && __OPENCL_C_VERSION__ >= 300)
// expected-error@-3{{use of type 'double' requires cl_khr_fp64 and __opencl_c_fp64 support}}
#else
// expected-error@-5{{use of type 'double' requires cl_khr_fp64 support}}
#endif
#endif
typedef double double4 __attribute__((ext_vector_type(4)));
double4 d4 = {0.0f, 2.0f, 3.0f, 1.0f};
#ifdef NOFP64
// expected-error@-3 {{use of type 'double' requires cl_khr_fp64 support}}
#if (defined(__OPENCL_C_VERSION__) && __OPENCL_C_VERSION__ >= 300)
// expected-error@-4 {{use of type 'double' requires cl_khr_fp64 and __opencl_c_fp64 support}}
#else
// expected-error@-6 {{use of type 'double' requires cl_khr_fp64 support}}
#endif
#endif
(void) 1.0;
#ifdef NOFP64
// expected-warning@-2{{double precision constant requires cl_khr_fp64, casting to single precision}}
#if (defined(__OPENCL_C_VERSION__) && __OPENCL_C_VERSION__ >= 300)
// expected-warning@-3{{double precision constant requires cl_khr_fp64 and __opencl_c_fp64, casting to single precision}}
#else
// expected-warning@-5{{double precision constant requires cl_khr_fp64, casting to single precision}}
#endif
#endif
}