Author: Victor Lomuller Date: 2025-05-29T15:19:40+02:00 New Revision: c474f8f2404dfe5a902cdf93d678a0bfe8cc8f44
URL: https://github.com/llvm/llvm-project/commit/c474f8f2404dfe5a902cdf93d678a0bfe8cc8f44 DIFF: https://github.com/llvm/llvm-project/commit/c474f8f2404dfe5a902cdf93d678a0bfe8cc8f44.diff LOG: [clang][SPIRV] Add builtin for OpGenericCastToPtrExplicit and its SPIR-V friendly binding (#137805) The patch introduce __builtin_spirv_generic_cast_to_ptr_explicit which is lowered to the llvm.spv.generic.cast.to.ptr.explicit intrinsic. The SPIR-V builtins are now split into 3 differents file: BuiltinsSPIRVCore.td, BuiltinsSPIRVVK.td for Vulkan specific builtins, BuiltinsSPIRVCL.td for OpenCL specific builtins and BuiltinsSPIRVCommon.td for common ones. The patch also introduces a new header defining its SPIR-V friendly equivalent (__spirv_GenericCastToPtrExplicit_ToGlobal, __spirv_GenericCastToPtrExplicit_ToLocal and __spirv_GenericCastToPtrExplicit_ToPrivate). The functions are declared as aliases to the new builtin allowing C-like languages to have a definition to rely on as well as gaining proper front-end diagnostics. The motivation for the header is to provide a stable binding for applications or library (such as SYCL) and allows non SPIR-V targets to provide an implementation (via libclc or similar to how it is done for gpuintrin.h). Added: clang/include/clang/Basic/BuiltinsSPIRVBase.td clang/include/clang/Basic/BuiltinsSPIRVCL.td clang/include/clang/Basic/BuiltinsSPIRVCommon.td clang/include/clang/Basic/BuiltinsSPIRVVK.td clang/lib/Headers/__clang_spirv_builtins.h clang/test/CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c clang/test/Headers/spirv_functions.cpp clang/test/SemaSPIRV/BuiltIns/generic_cast_to_ptr_explicit.c clang/test/SemaSPIRV/BuiltIns/invalid_target_cl.c clang/test/SemaSPIRV/BuiltIns/invalid_target_vk.c Modified: clang/include/clang/Basic/CMakeLists.txt clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Basic/TargetBuiltins.h clang/include/clang/Sema/SemaSPIRV.h clang/lib/AST/ASTContext.cpp clang/lib/Basic/Targets/SPIR.cpp clang/lib/Basic/Targets/SPIR.h clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/TargetBuiltins/SPIR.cpp clang/lib/Headers/CMakeLists.txt clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/lib/Sema/SemaSPIRV.cpp Removed: clang/include/clang/Basic/BuiltinsSPIRV.td ################################################################################ diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td deleted file mode 100644 index cc0c2f960f8d2..0000000000000 --- a/clang/include/clang/Basic/BuiltinsSPIRV.td +++ /dev/null @@ -1,39 +0,0 @@ -//===--- BuiltinsSPIRV.td - SPIRV Builtin function database ---------*- C++ -*-===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -include "clang/Basic/BuiltinsBase.td" - -def SPIRVDistance : Builtin { - let Spellings = ["__builtin_spirv_distance"]; - let Attributes = [NoThrow, Const]; - let Prototype = "void(...)"; -} - -def SPIRVLength : Builtin { - let Spellings = ["__builtin_spirv_length"]; - let Attributes = [NoThrow, Const]; - let Prototype = "void(...)"; -} - -def SPIRVReflect : Builtin { - let Spellings = ["__builtin_spirv_reflect"]; - let Attributes = [NoThrow, Const]; - let Prototype = "void(...)"; -} - -def SPIRVSmoothStep : Builtin { - let Spellings = ["__builtin_spirv_smoothstep"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; - let Prototype = "void(...)"; -} - -def SPIRVFaceForward : Builtin { - let Spellings = ["__builtin_spirv_faceforward"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; - let Prototype = "void(...)"; -} diff --git a/clang/include/clang/Basic/BuiltinsSPIRVBase.td b/clang/include/clang/Basic/BuiltinsSPIRVBase.td new file mode 100644 index 0000000000000..10ba7b965558d --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsSPIRVBase.td @@ -0,0 +1,15 @@ +//===--- BuiltinsSPIRVBase.td - SPIRV Builtin function database -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +include "clang/Basic/BuiltinsBase.td" + +class SPIRVBuiltin<string prototype, list<Attribute> Attr> : Builtin { + let Spellings = ["__builtin_spirv_"#NAME]; + let Prototype = prototype; + let Attributes = !listconcat([NoThrow], Attr); +} diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCL.td b/clang/include/clang/Basic/BuiltinsSPIRVCL.td new file mode 100644 index 0000000000000..1103a0d088e8b --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsSPIRVCL.td @@ -0,0 +1,12 @@ +//===--- BuiltinsSPIRVCL.td - SPIRV Builtin function database ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +include "clang/Basic/BuiltinsSPIRVBase.td" + +def generic_cast_to_ptr_explicit + : SPIRVBuiltin<"void*(void*, int)", [NoThrow, Const, CustomTypeChecking]>; diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td new file mode 100644 index 0000000000000..17bcd0b9cb783 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td @@ -0,0 +1,13 @@ +//===- BuiltinsSPIRVCommon.td - SPIRV Builtin function database -*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +include "clang/Basic/BuiltinsSPIRVBase.td" + +def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>; +def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>; +def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>; diff --git a/clang/include/clang/Basic/BuiltinsSPIRVVK.td b/clang/include/clang/Basic/BuiltinsSPIRVVK.td new file mode 100644 index 0000000000000..61cc0343c415e --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsSPIRVVK.td @@ -0,0 +1,13 @@ +//===--- BuiltinsSPIRVVK.td - SPIRV Builtin function database ---*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +include "clang/Basic/BuiltinsSPIRVBase.td" + + +def reflect : SPIRVBuiltin<"void(...)", [NoThrow, Const]>; +def faceforward : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>; diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 1349372a8330b..0cf661a57dfa8 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -109,9 +109,17 @@ clang_tablegen(BuiltinsRISCV.inc -gen-clang-builtins SOURCE BuiltinsRISCV.td TARGET ClangBuiltinsRISCV) -clang_tablegen(BuiltinsSPIRV.inc -gen-clang-builtins - SOURCE BuiltinsSPIRV.td - TARGET ClangBuiltinsSPIRV) +clang_tablegen(BuiltinsSPIRVCommon.inc -gen-clang-builtins + SOURCE BuiltinsSPIRVCommon.td + TARGET ClangBuiltinsSPIRVCommon) + +clang_tablegen(BuiltinsSPIRVVK.inc -gen-clang-builtins + SOURCE BuiltinsSPIRVVK.td + TARGET ClangBuiltinsSPIRVVK) + +clang_tablegen(BuiltinsSPIRVCL.inc -gen-clang-builtins + SOURCE BuiltinsSPIRVCL.td + TARGET ClangBuiltinsSPIRVCL) clang_tablegen(BuiltinsX86.inc -gen-clang-builtins SOURCE BuiltinsX86.td diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 8a879f7ca5529..7652af1210ae5 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4679,7 +4679,7 @@ def err_attribute_preferred_name_arg_invalid : Error< "argument %0 to 'preferred_name' attribute is not a typedef for " "a specialization of %1">; def err_attribute_builtin_alias : Error< - "%0 attribute can only be applied to a ARM, HLSL or RISC-V builtin">; + "%0 attribute can only be applied to a ARM, HLSL, SPIR-V or RISC-V builtin">; // called-once attribute diagnostics. def err_called_once_attribute_wrong_type : Error< @@ -12878,6 +12878,16 @@ def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must " def err_bit_int_max_size : Error<"%select{signed|unsigned}0 _BitInt of bit " "sizes greater than %1 not supported">; +// SPIR-V builtins diagnostics +def err_spirv_invalid_target : Error< + "builtin requires %select{spirv|spirv32 or spirv64}0 target">; +def err_spirv_builtin_generic_cast_invalid_arg : Error< + "expecting a pointer argument to the generic address space">; +def err_spirv_enum_not_int : Error< + "%0{storage class} argument for SPIR-V builtin is not a 32-bits integer">; +def err_spirv_enum_not_valid : Error< + "invalid value for %select{storage class}0 argument">; + // errors of expect.with.probability def err_probability_not_constant_float : Error< "probability argument to __builtin_expect_with_probability must be constant " diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index fb09b20975346..9bd514349d31d 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -157,7 +157,17 @@ namespace clang { enum { LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, #define GET_BUILTIN_ENUMERATORS -#include "clang/Basic/BuiltinsSPIRV.inc" +#include "clang/Basic/BuiltinsSPIRVCommon.inc" +#undef GET_BUILTIN_ENUMERATORS + FirstVKBuiltin, + LastCoreBuiltin = FirstVKBuiltin - 1, +#define GET_BUILTIN_ENUMERATORS +#include "clang/Basic/BuiltinsSPIRVVK.inc" +#undef GET_BUILTIN_ENUMERATORS + FirstCLBuiltin, + LastVKBuiltin = FirstCLBuiltin - 1, +#define GET_BUILTIN_ENUMERATORS +#include "clang/Basic/BuiltinsSPIRVCL.inc" #undef GET_BUILTIN_ENUMERATORS LastTSBuiltin }; diff --git a/clang/include/clang/Sema/SemaSPIRV.h b/clang/include/clang/Sema/SemaSPIRV.h index b26b861a6f47b..2b80f3bff4b89 100644 --- a/clang/include/clang/Sema/SemaSPIRV.h +++ b/clang/include/clang/Sema/SemaSPIRV.h @@ -21,7 +21,8 @@ class SemaSPIRV : public SemaBase { public: SemaSPIRV(Sema &S); - bool CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall); }; } // namespace clang diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 04eb44dc9426e..e71928ec0dc1c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10165,6 +10165,11 @@ bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const { if (LangOpts.HLSL && FD->getBuiltinID() != Builtin::NotBuiltin && BuiltinInfo.hasCustomTypechecking(FD->getBuiltinID())) return true; + // Allow redecl custom type checking builtin for SPIR-V. + if (getTargetInfo().getTriple().isSPIROrSPIRV() && + BuiltinInfo.isTSBuiltin(FD->getBuiltinID()) && + BuiltinInfo.hasCustomTypechecking(FD->getBuiltinID())) + return true; return BuiltinInfo.canBeRedeclared(FD->getBuiltinID()); } diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index 5b5f47f9647a2..b8d964ff680e5 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -24,19 +24,48 @@ static constexpr int NumBuiltins = clang::SPIRV::LastTSBuiltin - Builtin::FirstTSBuiltin; #define GET_BUILTIN_STR_TABLE -#include "clang/Basic/BuiltinsSPIRV.inc" +#include "clang/Basic/BuiltinsSPIRVCommon.inc" #undef GET_BUILTIN_STR_TABLE static constexpr Builtin::Info BuiltinInfos[] = { #define GET_BUILTIN_INFOS -#include "clang/Basic/BuiltinsSPIRV.inc" +#include "clang/Basic/BuiltinsSPIRVCommon.inc" #undef GET_BUILTIN_INFOS }; -static_assert(std::size(BuiltinInfos) == NumBuiltins); + +namespace CL { +#define GET_BUILTIN_STR_TABLE +#include "clang/Basic/BuiltinsSPIRVCL.inc" +#undef GET_BUILTIN_STR_TABLE + +static constexpr Builtin::Info BuiltinInfos[] = { +#define GET_BUILTIN_INFOS +#include "clang/Basic/BuiltinsSPIRVCL.inc" +#undef GET_BUILTIN_INFOS +}; +} // namespace CL + +namespace VK { +#define GET_BUILTIN_STR_TABLE +#include "clang/Basic/BuiltinsSPIRVVK.inc" +#undef GET_BUILTIN_STR_TABLE + +static constexpr Builtin::Info BuiltinInfos[] = { +#define GET_BUILTIN_INFOS +#include "clang/Basic/BuiltinsSPIRVVK.inc" +#undef GET_BUILTIN_INFOS +}; +} // namespace VK + +static_assert(std::size(BuiltinInfos) + std::size(CL::BuiltinInfos) + + std::size(VK::BuiltinInfos) == + NumBuiltins); llvm::SmallVector<Builtin::InfosShard> -SPIRVTargetInfo::getTargetBuiltins() const { - return {{&BuiltinStrings, BuiltinInfos}}; +BaseSPIRVTargetInfo::getTargetBuiltins() const { + return {{&BuiltinStrings, BuiltinInfos}, + {&VK::BuiltinStrings, VK::BuiltinInfos}, + {&CL::BuiltinStrings, CL::BuiltinInfos}}; } void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index fcedce98c7067..ef511d045f576 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -293,6 +293,8 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRVTargetInfo : public BaseSPIRTargetInfo { assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V."); } + llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; + bool hasFeature(StringRef Feature) const override { return Feature == "spirv"; } @@ -321,8 +323,6 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRVTargetInfo { "v256:256-v512:512-v1024:1024-n8:16:32:64-G10"); } - llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override; - void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; }; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index be65fa438bb06..369cff35b1bbf 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -122,12 +122,13 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue); + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + if (CGF->getTarget().getTriple().getOS() == llvm::Triple::OSType::AMDHSA) + return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E); + [[fallthrough]]; case llvm::Triple::spirv: return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E); - case llvm::Triple::spirv64: - if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA) - return nullptr; - return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E); default: return nullptr; } diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp index 26f8eb1fd07f8..0687485cd3f80 100644 --- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp @@ -83,6 +83,20 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID, /*ReturnType=*/N->getType(), Intrinsic::spv_faceforward, ArrayRef<Value *>{N, I, Ng}, /*FMFSource=*/nullptr, "spv.faceforward"); } + case SPIRV::BI__builtin_spirv_generic_cast_to_ptr_explicit: { + Value *Ptr = EmitScalarExpr(E->getArg(0)); + assert(E->getArg(0)->getType()->hasPointerRepresentation() && + E->getArg(1)->getType()->hasIntegerRepresentation() && + "GenericCastToPtrExplicit takes a pointer and an int"); + llvm::Type *Res = getTypes().ConvertType(E->getType()); + assert(Res->isPointerTy() && + "GenericCastToPtrExplicit doesn't return a pointer"); + llvm::CallInst *Call = Builder.CreateIntrinsic( + /*ReturnType=*/Res, Intrinsic::spv_generic_cast_to_ptr_explicit, + ArrayRef<Value *>{Ptr}, nullptr, "spv.generic_cast"); + Call->addRetAttr(llvm::Attribute::AttrKind::NoUndef); + return Call; + } } return nullptr; } diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 24f5327b07dda..c1c9d2e8c7b79 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -132,6 +132,10 @@ set(riscv_files andes_vector.h ) +set(spirv_files + __clang_spirv_builtins.h + ) + set(systemz_files s390intrin.h vecintrin.h @@ -319,6 +323,7 @@ set(files ${ppc_files} ${ppc_htm_files} ${riscv_files} + ${spirv_files} ${systemz_files} ${ve_files} ${x86_files} @@ -529,6 +534,7 @@ add_dependencies("clang-resource-headers" "ppc-resource-headers" "ppc-htm-resource-headers" "riscv-resource-headers" + "spirv-resource-headers" "systemz-resource-headers" "ve-resource-headers" "webassembly-resource-headers" @@ -562,6 +568,7 @@ add_header_target("gpu-resource-headers" "${gpu_files}") # Other header groupings add_header_target("hlsl-resource-headers" ${hlsl_files}) +add_header_target("spirv-resource-headers" ${spirv_files}) add_header_target("opencl-resource-headers" ${opencl_files}) add_header_target("llvm-libc-resource-headers" ${llvm_libc_wrapper_files}) add_header_target("openmp-resource-headers" ${openmp_wrapper_files}) @@ -767,6 +774,12 @@ install( ${EXCLUDE_HLSL} COMPONENT hlsl-resource-headers) +install( + FILES ${spirv_files} + DESTINATION ${header_install_dir} + EXCLUDE_FROM_ALL + COMPONENT spirv-resource-headers) + install( FILES ${opencl_files} DESTINATION ${header_install_dir} @@ -836,6 +849,9 @@ if (NOT LLVM_ENABLE_IDE) add_llvm_install_targets(install-riscv-resource-headers DEPENDS riscv-resource-headers COMPONENT riscv-resource-headers) + add_llvm_install_targets(install-spirv-resource-headers + DEPENDS spirv-resource-headers + COMPONENT spirv-resource-headers) add_llvm_install_targets(install-systemz-resource-headers DEPENDS systemz-resource-headers COMPONENT systemz-resource-headers) diff --git a/clang/lib/Headers/__clang_spirv_builtins.h b/clang/lib/Headers/__clang_spirv_builtins.h new file mode 100644 index 0000000000000..e344ed52571a7 --- /dev/null +++ b/clang/lib/Headers/__clang_spirv_builtins.h @@ -0,0 +1,179 @@ +/*===---- spirv_builtin_vars.h - SPIR-V built-in ---------------------------=== + * + * 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 + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __SPIRV_BUILTIN_VARS_H +#define __SPIRV_BUILTIN_VARS_H + +#if __cplusplus >= 201103L +#define __SPIRV_NOEXCEPT noexcept +#else +#define __SPIRV_NOEXCEPT +#endif + +#define __SPIRV_overloadable __attribute__((overloadable)) +#define __SPIRV_convergent __attribute__((convergent)) +#define __SPIRV_inline __attribute__((always_inline)) + +#define __global __attribute__((opencl_global)) +#define __local __attribute__((opencl_local)) +#define __private __attribute__((opencl_private)) +#define __constant __attribute__((opencl_constant)) +#ifdef __SYCL_DEVICE_ONLY__ +#define __generic +#else +#define __generic __attribute__((opencl_generic)) +#endif + +// Check if SPIR-V builtins are supported. +// As the translator doesn't use the LLVM intrinsics (which would be emitted if +// we use the SPIR-V builtins) we can't rely on the SPIRV32/SPIRV64 etc macros +// to establish if we can use the builtin alias. We disable builtin altogether +// if we do not intent to use the backend. So instead of use target macros, rely +// on a __has_builtin test. +#if (__has_builtin(__builtin_spirv_generic_cast_to_ptr_explicit)) +#define __SPIRV_BUILTIN_ALIAS(builtin) \ + __attribute__((clang_builtin_alias(builtin))) +#else +#define __SPIRV_BUILTIN_ALIAS(builtin) +#endif + +// OpGenericCastToPtrExplicit + +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__global void *__spirv_GenericCastToPtrExplicit_ToGlobal(__generic void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__global const void * +__spirv_GenericCastToPtrExplicit_ToGlobal(__generic const void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__global volatile void * +__spirv_GenericCastToPtrExplicit_ToGlobal(__generic volatile void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__global const volatile void * +__spirv_GenericCastToPtrExplicit_ToGlobal(__generic const volatile void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__local void *__spirv_GenericCastToPtrExplicit_ToLocal(__generic void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__local const void * +__spirv_GenericCastToPtrExplicit_ToLocal(__generic const void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__local volatile void * +__spirv_GenericCastToPtrExplicit_ToLocal(__generic volatile void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__local const volatile void * +__spirv_GenericCastToPtrExplicit_ToLocal(__generic const volatile void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__private void * +__spirv_GenericCastToPtrExplicit_ToPrivate(__generic void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__private const void * +__spirv_GenericCastToPtrExplicit_ToPrivate(__generic const void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__private volatile void * +__spirv_GenericCastToPtrExplicit_ToPrivate(__generic volatile void *, + int) __SPIRV_NOEXCEPT; +extern __SPIRV_overloadable +__SPIRV_BUILTIN_ALIAS(__builtin_spirv_generic_cast_to_ptr_explicit) +__private const volatile void * +__spirv_GenericCastToPtrExplicit_ToPrivate(__generic const volatile void *, + int) __SPIRV_NOEXCEPT; + +// OpGenericCastToPtr + +static __SPIRV_overloadable __SPIRV_inline __global void * +__spirv_GenericCastToPtr_ToGlobal(__generic void *p, int) __SPIRV_NOEXCEPT { + return (__global void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __global const void * +__spirv_GenericCastToPtr_ToGlobal(__generic const void *p, + int) __SPIRV_NOEXCEPT { + return (__global const void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __global volatile void * +__spirv_GenericCastToPtr_ToGlobal(__generic volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__global volatile void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __global const volatile void * +__spirv_GenericCastToPtr_ToGlobal(__generic const volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__global const volatile void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __local void * +__spirv_GenericCastToPtr_ToLocal(__generic void *p, int) __SPIRV_NOEXCEPT { + return (__local void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __local const void * +__spirv_GenericCastToPtr_ToLocal(__generic const void *p, + int) __SPIRV_NOEXCEPT { + return (__local const void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __local volatile void * +__spirv_GenericCastToPtr_ToLocal(__generic volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__local volatile void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __local const volatile void * +__spirv_GenericCastToPtr_ToLocal(__generic const volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__local const volatile void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __private void * +__spirv_GenericCastToPtr_ToPrivate(__generic void *p, int) __SPIRV_NOEXCEPT { + return (__private void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __private const void * +__spirv_GenericCastToPtr_ToPrivate(__generic const void *p, + int) __SPIRV_NOEXCEPT { + return (__private const void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __private volatile void * +__spirv_GenericCastToPtr_ToPrivate(__generic volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__private volatile void *)p; +} +static __SPIRV_overloadable __SPIRV_inline __private const volatile void * +__spirv_GenericCastToPtr_ToPrivate(__generic const volatile void *p, + int) __SPIRV_NOEXCEPT { + return (__private const volatile void *)p; +} + +#undef __SPIRV_overloadable +#undef __SPIRV_convergent +#undef __SPIRV_inline + +#undef __global +#undef __local +#undef __constant +#undef __generic + +#undef __SPIRV_BUILTIN_ALIAS +#undef __SPIRV_NOEXCEPT + +#endif /* __SPIRV_BUILTIN_VARS_H */ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 930e9083365a1..ba2630e960e6f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2033,7 +2033,11 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::mips64el: return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); case llvm::Triple::spirv: - return SPIRV().CheckSPIRVBuiltinFunctionCall(BuiltinID, TheCall); + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + if (TI.getTriple().getOS() != llvm::Triple::OSType::AMDHSA) + return SPIRV().CheckSPIRVBuiltinFunctionCall(TI, BuiltinID, TheCall); + return false; case llvm::Triple::systemz: return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); case llvm::Triple::x86: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0adc04f06100e..5bc358ca5fca0 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -53,6 +53,7 @@ #include "clang/Sema/SemaOpenCL.h" #include "clang/Sema/SemaOpenMP.h" #include "clang/Sema/SemaRISCV.h" +#include "clang/Sema/SemaSPIRV.h" #include "clang/Sema/SemaSYCL.h" #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaWasm.h" @@ -5863,12 +5864,13 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64(); bool IsARM = S.Context.getTargetInfo().getTriple().isARM(); bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV(); + bool IsSPIRV = S.Context.getTargetInfo().getTriple().isSPIRV(); bool IsHLSL = S.Context.getLangOpts().HLSL; if ((IsAArch64 && !S.ARM().SveAliasValid(BuiltinID, AliasName)) || (IsARM && !S.ARM().MveAliasValid(BuiltinID, AliasName) && !S.ARM().CdeAliasValid(BuiltinID, AliasName)) || (IsRISCV && !S.RISCV().isAliasValid(BuiltinID, AliasName)) || - (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL)) { + (!IsAArch64 && !IsARM && !IsRISCV && !IsHLSL && !IsSPIRV)) { S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL; return; } diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp index 90888f1417a9d..bd72194b905f5 100644 --- a/clang/lib/Sema/SemaSPIRV.cpp +++ b/clang/lib/Sema/SemaSPIRV.cpp @@ -10,8 +10,21 @@ #include "clang/Sema/SemaSPIRV.h" #include "clang/Basic/TargetBuiltins.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Sema.h" +// SPIR-V enumerants. Enums have only the required entries, see SPIR-V specs for +// values. +// FIXME: either use the SPIRV-Headers or generate a custom header using the +// grammar (like done with MLIR). +namespace spirv { +enum class StorageClass : int { + Workgroup = 4, + CrossWorkgroup = 5, + Function = 7 +}; +} + namespace clang { SemaSPIRV::SemaSPIRV(Sema &S) : SemaBase(S) {} @@ -33,8 +46,114 @@ static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) { return false; } -bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, +static std::optional<int> +processConstant32BitIntArgument(Sema &SemaRef, CallExpr *Call, int Argument) { + ExprResult Arg = + SemaRef.DefaultFunctionArrayLvalueConversion(Call->getArg(Argument)); + if (Arg.isInvalid()) + return true; + Call->setArg(Argument, Arg.get()); + + const Expr *IntArg = Arg.get(); + SmallVector<PartialDiagnosticAt, 8> Notes; + Expr::EvalResult Eval; + Eval.Diag = &Notes; + if ((!IntArg->EvaluateAsConstantExpr(Eval, SemaRef.getASTContext())) || + !Eval.Val.isInt() || Eval.Val.getInt().getBitWidth() > 32) { + SemaRef.Diag(IntArg->getBeginLoc(), diag::err_spirv_enum_not_int) + << 0 << IntArg->getSourceRange(); + for (const PartialDiagnosticAt &PDiag : Notes) + SemaRef.Diag(PDiag.first, PDiag.second); + return true; + } + return {Eval.Val.getInt().getZExtValue()}; +} + +static bool checkGenericCastToPtr(Sema &SemaRef, CallExpr *Call) { + if (SemaRef.checkArgCount(Call, 2)) + return true; + + { + ExprResult Arg = + SemaRef.DefaultFunctionArrayLvalueConversion(Call->getArg(0)); + if (Arg.isInvalid()) + return true; + Call->setArg(0, Arg.get()); + + QualType Ty = Arg.get()->getType(); + const auto *PtrTy = Ty->getAs<PointerType>(); + auto AddressSpaceNotInGeneric = [&](LangAS AS) { + if (SemaRef.LangOpts.OpenCL) + return AS != LangAS::opencl_generic; + return AS != LangAS::Default; + }; + if (!PtrTy || + AddressSpaceNotInGeneric(PtrTy->getPointeeType().getAddressSpace())) { + SemaRef.Diag(Arg.get()->getBeginLoc(), + diag::err_spirv_builtin_generic_cast_invalid_arg) + << Call->getSourceRange(); + return true; + } + } + + spirv::StorageClass StorageClass; + if (std::optional<int> SCInt = + processConstant32BitIntArgument(SemaRef, Call, 1); + SCInt.has_value()) { + StorageClass = static_cast<spirv::StorageClass>(SCInt.value()); + if (StorageClass != spirv::StorageClass::CrossWorkgroup && + StorageClass != spirv::StorageClass::Workgroup && + StorageClass != spirv::StorageClass::Function) { + SemaRef.Diag(Call->getArg(1)->getBeginLoc(), + diag::err_spirv_enum_not_valid) + << 0 << Call->getArg(1)->getSourceRange(); + return true; + } + } else { + return true; + } + auto RT = Call->getArg(0)->getType(); + RT = RT->getPointeeType(); + auto Qual = RT.getQualifiers(); + LangAS AddrSpace; + switch (static_cast<spirv::StorageClass>(StorageClass)) { + case spirv::StorageClass::CrossWorkgroup: + AddrSpace = + SemaRef.LangOpts.isSYCL() ? LangAS::sycl_global : LangAS::opencl_global; + break; + case spirv::StorageClass::Workgroup: + AddrSpace = + SemaRef.LangOpts.isSYCL() ? LangAS::sycl_local : LangAS::opencl_local; + break; + case spirv::StorageClass::Function: + AddrSpace = SemaRef.LangOpts.isSYCL() ? LangAS::sycl_private + : LangAS::opencl_private; + break; + default: + llvm_unreachable("Invalid builtin function"); + } + Qual.setAddressSpace(AddrSpace); + Call->setType(SemaRef.getASTContext().getPointerType( + SemaRef.getASTContext().getQualifiedType(RT.getUnqualifiedType(), Qual))); + + return false; +} + +bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID >= SPIRV::FirstVKBuiltin && BuiltinID <= SPIRV::LastVKBuiltin && + TI.getTriple().getArch() != llvm::Triple::spirv) { + SemaRef.Diag(TheCall->getBeginLoc(), diag::err_spirv_invalid_target) << 0; + return true; + } + if (BuiltinID >= SPIRV::FirstCLBuiltin && BuiltinID <= SPIRV::LastTSBuiltin && + TI.getTriple().getArch() != llvm::Triple::spirv32 && + TI.getTriple().getArch() != llvm::Triple::spirv64) { + SemaRef.Diag(TheCall->getBeginLoc(), diag::err_spirv_invalid_target) << 1; + return true; + } + switch (BuiltinID) { case SPIRV::BI__builtin_spirv_distance: { if (SemaRef.checkArgCount(TheCall, 2)) @@ -160,6 +279,9 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID, TheCall->setType(RetTy); break; } + case SPIRV::BI__builtin_spirv_generic_cast_to_ptr_explicit: { + return checkGenericCastToPtr(SemaRef, TheCall); + } } return false; } diff --git a/clang/test/CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c b/clang/test/CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c new file mode 100644 index 0000000000000..8cfe650f4db10 --- /dev/null +++ b/clang/test/CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -O1 -triple spirv64 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -O1 -triple spirv32 -cl-std=CL3.0 -x cl %s -emit-llvm -o - | FileCheck %s + +// CHECK: spir_func noundef ptr @test_cast_to_private( +// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]] +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr @llvm.spv.generic.cast.to.ptr.explicit.p0(ptr addrspace(4) %p) +// CHECK-NEXT: ret ptr [[SPV_CAST]] +// +__attribute__((opencl_private)) int* test_cast_to_private(int* p) { + return __builtin_spirv_generic_cast_to_ptr_explicit(p, 7); +} + +// CHECK: spir_func noundef ptr addrspace(1) @test_cast_to_global( +// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]] +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr addrspace(1) @llvm.spv.generic.cast.to.ptr.explicit.p1(ptr addrspace(4) %p) +// CHECK-NEXT: ret ptr addrspace(1) [[SPV_CAST]] +// +__attribute__((opencl_global)) int* test_cast_to_global(int* p) { + return __builtin_spirv_generic_cast_to_ptr_explicit(p, 5); +} + +// CHECK: spir_func noundef ptr addrspace(3) @test_cast_to_local( +// CHECK-SAME: ptr addrspace(4) noundef readnone [[P:%.*]] +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SPV_CAST:%.*]] = tail call noundef ptr addrspace(3) @llvm.spv.generic.cast.to.ptr.explicit.p3(ptr addrspace(4) %p) +// CHECK-NEXT: ret ptr addrspace(3) [[SPV_CAST]] +// +__attribute__((opencl_local)) int* test_cast_to_local(int* p) { + return __builtin_spirv_generic_cast_to_ptr_explicit(p, 4); +} diff --git a/clang/test/Headers/spirv_functions.cpp b/clang/test/Headers/spirv_functions.cpp new file mode 100644 index 0000000000000..ff036b75faf02 --- /dev/null +++ b/clang/test/Headers/spirv_functions.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -Wno-unused-value -O0 -internal-isystem %S/../../lib/Headers -include __clang_spirv_builtins.h -triple spirv64 -emit-llvm %s -fsycl-is-device -o - | FileCheck %s -check-prefixes=SPV +// RUN: %clang_cc1 -Wno-unused-value -O0 -internal-isystem %S/../../lib/Headers -include __clang_spirv_builtins.h -triple nvptx64 -emit-llvm %s -fsycl-is-device -o - | FileCheck %s -check-prefixes=NV + + +// SPV: void @_Z9test_castPi +// SPV: call noundef ptr addrspace(1) @llvm.spv.generic.cast.to.ptr.explicit.p1 +// SPV: call noundef ptr addrspace(3) @llvm.spv.generic.cast.to.ptr.explicit.p3 +// SPV: call noundef ptr @llvm.spv.generic.cast.to.ptr.explicit.p0 +// SPV: addrspacecast ptr addrspace(4) %{{.*}} to ptr addrspace(1) +// SPV: addrspacecast ptr addrspace(4) %{{.*}} to ptr addrspace(3) +// SPV: addrspacecast ptr addrspace(4) %{{.*}} to ptr +// NV: void @_Z9test_castPi +// NV: call noundef ptr addrspace(1) @_Z41__spirv_GenericCastToPtrExplicit_ToGlobalPvi +// NV: call noundef ptr addrspace(3) @_Z40__spirv_GenericCastToPtrExplicit_ToLocalPvi +// NV: call noundef ptr @_Z42__spirv_GenericCastToPtrExplicit_ToPrivatePvi +// NV: addrspacecast ptr %{{.*}} to ptr addrspace(1) +// NV: addrspacecast ptr %{{.*}} to ptr addrspace(3) +void test_cast(int* p) { + __spirv_GenericCastToPtrExplicit_ToGlobal(p, 5); + __spirv_GenericCastToPtrExplicit_ToLocal(p, 4); + __spirv_GenericCastToPtrExplicit_ToPrivate(p, 7); + __spirv_GenericCastToPtr_ToGlobal(p, 5); + __spirv_GenericCastToPtr_ToLocal(p, 4); + __spirv_GenericCastToPtr_ToPrivate(p, 7); +} diff --git a/clang/test/SemaSPIRV/BuiltIns/generic_cast_to_ptr_explicit.c b/clang/test/SemaSPIRV/BuiltIns/generic_cast_to_ptr_explicit.c new file mode 100644 index 0000000000000..5a839961e20f5 --- /dev/null +++ b/clang/test/SemaSPIRV/BuiltIns/generic_cast_to_ptr_explicit.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -O1 -triple spirv64 -fsycl-is-device -verify %s -o - +// RUN: %clang_cc1 -O1 -triple spirv64 -verify %s -cl-std=CL3.0 -x cl -o - +// RUN: %clang_cc1 -O1 -triple spirv32 -verify %s -cl-std=CL3.0 -x cl -o - + +void test_missing_arguments(int* p) { + __builtin_spirv_generic_cast_to_ptr_explicit(p); + // expected-error@-1 {{too few arguments to function call, expected 2, have 1}} + __builtin_spirv_generic_cast_to_ptr_explicit(p, 7, p); + // expected-error@-1 {{too many arguments to function call, expected 2, have 3}} +} + +void test_wrong_flag_value(int* p) { + __builtin_spirv_generic_cast_to_ptr_explicit(p, 14); + // expected-error@-1 {{invalid value for storage class argument}} +} + +void test_wrong_address_space(__attribute__((opencl_local)) int* p) { + __builtin_spirv_generic_cast_to_ptr_explicit(p, 14); + // expected-error@-1 {{expecting a pointer argument to the generic address space}} +} + +void test_not_a_pointer(int p) { + __builtin_spirv_generic_cast_to_ptr_explicit(p, 14); + // expected-error@-1 {{expecting a pointer argument to the generic address space}} +} diff --git a/clang/test/SemaSPIRV/BuiltIns/invalid_target_cl.c b/clang/test/SemaSPIRV/BuiltIns/invalid_target_cl.c new file mode 100644 index 0000000000000..467d0a2844d6f --- /dev/null +++ b/clang/test/SemaSPIRV/BuiltIns/invalid_target_cl.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -Wno-unused-value -verify=invalid %s -o - +// RUN: %clang_cc1 -triple spirv32 -verify=valid -Wno-unused-value %s -cl-std=CL3.0 -x cl -o - +// RUN: %clang_cc1 -triple spirv64 -verify=valid -Wno-unused-value %s -cl-std=CL3.0 -x cl -o - + +typedef float float2 __attribute__((ext_vector_type(2))); + +// valid-no-diagnostics + +void invalid_builtin_for_target(int* p) { + __builtin_spirv_generic_cast_to_ptr_explicit(p, 7); + // invalid-error@-1 {{builtin requires spirv32 or spirv64 target}} +} + +// no error +float valid_builtin(float2 X) { return __builtin_spirv_length(X); } diff --git a/clang/test/SemaSPIRV/BuiltIns/invalid_target_vk.c b/clang/test/SemaSPIRV/BuiltIns/invalid_target_vk.c new file mode 100644 index 0000000000000..86c1a9e44edb4 --- /dev/null +++ b/clang/test/SemaSPIRV/BuiltIns/invalid_target_vk.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple spirv-pc-vulkan-compute -Wno-unused-value -verify=valid %s -o - +// RUN: %clang_cc1 -triple spirv32 -verify=invalid -Wno-unused-value %s -cl-std=CL3.0 -x cl -o - +// RUN: %clang_cc1 -triple spirv64 -verify=invalid -Wno-unused-value %s -cl-std=CL3.0 -x cl -o - + +typedef float float2 __attribute__((ext_vector_type(2))); + +// valid-no-diagnostics + +void call(float2 X, float2 Y) { + __builtin_spirv_reflect(X, Y); + // invalid-error@-1 {{builtin requires spirv target}} +} + +// no error +float valid_builtin(float2 X) { return __builtin_spirv_length(X); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits