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 @@ -364,4 +364,7 @@ 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, DefaultIgnore; + +def err_opencl_extension_and_feature_differs : Error< + "Options %0 and %1 are set to different values which is illegal in OpenCL C 3.0">; } 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 @@ -118,7 +118,8 @@ "magnitude of floating-point constant too small for type %0; minimum is %1">, InGroup; 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|__opencl_c_fp64}0, " + "casting to single precision">; def err_half_const_requires_fp16 : Error< "half precision constant requires cl_khr_fp16">; 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 @@ -743,7 +743,20 @@ 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; } diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -292,6 +292,7 @@ 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; diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -136,6 +136,7 @@ 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; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -135,8 +135,9 @@ // 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 diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -301,6 +301,11 @@ Context.getTargetInfo().getSupportedOpenCLOpts(), getLangOpts()); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); + + // Set conditionally to provide correct diagnostics for 'double' type + llvm::StringRef FP64Feature( + getLangOpts().OpenCLVersion >= 300 ? "__opencl_c_fp64" : "cl_khr_fp64"); + if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) { addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); addImplicitTypedef("queue_t", Context.OCLQueueTy); @@ -332,10 +337,10 @@ getLangOpts()) && getOpenCLOptions().isSupported("cl_khr_int64_extended_atomics", getLangOpts())) { - if (getOpenCLOptions().isSupported("cl_khr_fp64", getLangOpts())) { + if (getOpenCLOptions().isSupported(FP64Feature, getLangOpts())) { auto AtomicDoubleT = Context.getAtomicType(Context.DoubleTy); addImplicitTypedef("atomic_double", AtomicDoubleT); - setOpenCLExtensionForType(AtomicDoubleT, "cl_khr_fp64"); + setOpenCLExtensionForType(AtomicDoubleT, FP64Feature); Atomic64BitTypes.push_back(AtomicDoubleT); } auto AtomicLongT = Context.getAtomicType(Context.LongTy); @@ -366,7 +371,7 @@ "cl_khr_int64_base_atomics cl_khr_int64_extended_atomics"); } - setOpenCLExtensionForType(Context.DoubleTy, "cl_khr_fp64"); + setOpenCLExtensionForType(Context.DoubleTy, FP64Feature); #define GENERIC_IMAGE_TYPE_EXT(Type, Id, Ext) \ setOpenCLExtensionForType(Context.Id, Ext); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3830,7 +3830,8 @@ } 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(); } } diff --git a/clang/test/CodeGenOpenCL/printf.cl b/clang/test/CodeGenOpenCL/printf.cl --- a/clang/test/CodeGenOpenCL/printf.cl +++ b/clang/test/CodeGenOpenCL/printf.cl @@ -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 @@ 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) { diff --git a/clang/test/Misc/opencl-c-3.0.incorrect_options.cl b/clang/test/Misc/opencl-c-3.0.incorrect_options.cl new file mode 100644 --- /dev/null +++ b/clang/test/Misc/opencl-c-3.0.incorrect_options.cl @@ -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 which is illegal in OpenCL C 3.0 diff --git a/clang/test/SemaOpenCL/extensions.cl b/clang/test/SemaOpenCL/fp64-fp16-options.cl rename from clang/test/SemaOpenCL/extensions.cl rename to clang/test/SemaOpenCL/fp64-fp16-options.cl --- a/clang/test/SemaOpenCL/extensions.cl +++ b/clang/test/SemaOpenCL/fp64-fp16-options.cl @@ -4,6 +4,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 // @@ -15,12 +16,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 @@ -72,20 +79,33 @@ 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 __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}} -// expected-error@-3 {{use of type 'double4' (vector of 4 'double' values) requires cl_khr_fp64 support}} +#if (defined(__OPENCL_C_VERSION__) && __OPENCL_C_VERSION__ == 300) +// expected-error@-4 {{use of type 'double' requires __opencl_c_fp64 support}} +// expected-error@-4 {{use of type 'double4' (vector of 4 'double' values) requires __opencl_c_fp64 support}} +#else +// expected-error@-7 {{use of type 'double' requires cl_khr_fp64 support}} +// expected-error@-7 {{use of type 'double4' (vector of 4 'double' values) requires cl_khr_fp64 support}} +#endif #endif (void) 1.0; #ifdef NOFP64 -// expected-warning@-3{{double precision constant requires cl_khr_fp64, casting to single precision}} +#if (defined(__OPENCL_C_VERSION__) && __OPENCL_C_VERSION__ == 300) +// expected-warning@-4{{double precision constant requires __opencl_c_fp64, casting to single precision}} +#else +// expected-warning@-6{{double precision constant requires cl_khr_fp64, casting to single precision}} +#endif #endif }