[clang] [clang][SPIRV] Add builtin for OpGenericCastToPtrExplicit and its SPIR-V friendly binding (PR #137805)
Victor Lomuller via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 30 02:48:04 PDT 2025
https://github.com/Naghasan updated https://github.com/llvm/llvm-project/pull/137805
>From 020a804188b13ef881dcf1cbd81a5e11e4803d62 Mon Sep 17 00:00:00 2001
From: Victor Lomuller <victor at codeplay.com>
Date: Mon, 28 Apr 2025 16:20:09 +0100
Subject: [PATCH 1/2] [clang][SPIRV] Add builtin for OpGenericCastToPtrExplicit
and its SPIR-V friendly binding
The patch introduce __builtin_spirv_generic_cast_to_ptr_explicit which is lowered to
the llvm.spv.generic.cast.to.ptr.explicit intrinsic.
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.
---
clang/include/clang/Basic/BuiltinsSPIRV.td | 9 +
.../clang/Basic/DiagnosticSemaKinds.td | 10 +-
clang/lib/AST/ASTContext.cpp | 5 +
clang/lib/Basic/Targets/SPIR.cpp | 2 +-
clang/lib/Basic/Targets/SPIR.h | 4 +-
clang/lib/CodeGen/CGBuiltin.cpp | 4 +-
clang/lib/CodeGen/TargetBuiltins/SPIR.cpp | 14 ++
clang/lib/Headers/CMakeLists.txt | 16 ++
clang/lib/Headers/__clang_spirv_builtins.h | 179 ++++++++++++++++++
clang/lib/Sema/SemaChecking.cpp | 6 +-
clang/lib/Sema/SemaDeclAttr.cpp | 4 +-
clang/lib/Sema/SemaSPIRV.cpp | 108 +++++++++++
.../Builtins/generic_cast_to_ptr_explicit.c | 33 ++++
clang/test/Headers/spirv_functions.cpp | 25 +++
.../BuiltIns/generic_cast_to_ptr_explicit.c | 25 +++
15 files changed, 436 insertions(+), 8 deletions(-)
create mode 100644 clang/lib/Headers/__clang_spirv_builtins.h
create mode 100644 clang/test/CodeGenSPIRV/Builtins/generic_cast_to_ptr_explicit.c
create mode 100644 clang/test/Headers/spirv_functions.cpp
create mode 100644 clang/test/SemaSPIRV/BuiltIns/generic_cast_to_ptr_explicit.c
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
index cc0c2f960f8d2..bbb2abba2e256 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRV.td
@@ -8,6 +8,12 @@
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);
+}
+
def SPIRVDistance : Builtin {
let Spellings = ["__builtin_spirv_distance"];
let Attributes = [NoThrow, Const];
@@ -37,3 +43,6 @@ def SPIRVFaceForward : Builtin {
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Prototype = "void(...)";
}
+
+def generic_cast_to_ptr_explicit
+ : SPIRVBuiltin<"void*(void*, int)", [NoThrow, Const, CustomTypeChecking]>;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4c96142e28134..8f088d4d0d0f8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4609,7 +4609,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<
@@ -12740,6 +12740,14 @@ 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_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/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index c95e733f30494..51438c22f52fe 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -10054,6 +10054,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..fe13e4ee25a36 100644
--- a/clang/lib/Basic/Targets/SPIR.cpp
+++ b/clang/lib/Basic/Targets/SPIR.cpp
@@ -35,7 +35,7 @@ static constexpr Builtin::Info BuiltinInfos[] = {
static_assert(std::size(BuiltinInfos) == NumBuiltins);
llvm::SmallVector<Builtin::InfosShard>
-SPIRVTargetInfo::getTargetBuiltins() const {
+BaseSPIRVTargetInfo::getTargetBuiltins() const {
return {{&BuiltinStrings, BuiltinInfos}};
}
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..0176bf223a3aa 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 1e4e055e04afd..85309186b2e9a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -97,10 +97,10 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::riscv64:
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
case llvm::Triple::spirv:
- return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E);
+ case llvm::Triple::spirv32:
case llvm::Triple::spirv64:
if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
- return nullptr;
+ return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E);
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 acf49e40c447e..556b076abbfbf 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -129,6 +129,10 @@ set(riscv_files
sifive_vector.h
)
+set(spirv_files
+ __clang_spirv_builtins.h
+ )
+
set(systemz_files
s390intrin.h
vecintrin.h
@@ -316,6 +320,7 @@ set(files
${ppc_files}
${ppc_htm_files}
${riscv_files}
+ ${spirv_files}
${systemz_files}
${ve_files}
${x86_files}
@@ -526,6 +531,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"
@@ -559,6 +565,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})
@@ -764,6 +771,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}
@@ -833,6 +846,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 2811fd3a04377..fb0f2d2c0d57b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1983,7 +1983,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(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 413999b95b998..28128d21e53cf 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"
@@ -5837,12 +5838,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..d5b37e0b8aff6 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -12,6 +12,18 @@
#include "clang/Basic/TargetBuiltins.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,6 +45,99 @@ static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
return false;
}
+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(unsigned BuiltinID,
CallExpr *TheCall) {
switch (BuiltinID) {
@@ -160,6 +265,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 at -1 {{too few arguments to function call, expected 2, have 1}}
+ __builtin_spirv_generic_cast_to_ptr_explicit(p, 7, p);
+ // expected-error at -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 at -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 at -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 at -1 {{expecting a pointer argument to the generic address space}}
+}
>From 1615b6b52ddf84b957a01c90398e251aa567d553 Mon Sep 17 00:00:00 2001
From: Victor Lomuller <victor at codeplay.com>
Date: Tue, 29 Apr 2025 22:39:40 +0100
Subject: [PATCH 2/2] Address feedback: split common, vk and ocl builtins
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.
---
clang/include/clang/Basic/BuiltinsSPIRV.td | 48 -------------------
.../include/clang/Basic/BuiltinsSPIRVBase.td | 15 ++++++
clang/include/clang/Basic/BuiltinsSPIRVCL.td | 12 +++++
.../clang/Basic/BuiltinsSPIRVCommon.td | 13 +++++
clang/include/clang/Basic/BuiltinsSPIRVVK.td | 13 +++++
clang/include/clang/Basic/CMakeLists.txt | 14 ++++--
.../clang/Basic/DiagnosticSemaKinds.td | 2 +
clang/include/clang/Basic/TargetBuiltins.h | 12 ++++-
clang/include/clang/Sema/SemaSPIRV.h | 3 +-
clang/lib/Basic/Targets/SPIR.cpp | 37 ++++++++++++--
clang/lib/CodeGen/CGBuiltin.cpp | 9 ++--
clang/lib/Sema/SemaChecking.cpp | 2 +-
clang/lib/Sema/SemaSPIRV.cpp | 16 ++++++-
.../SemaSPIRV/BuiltIns/invalid_target_cl.c | 15 ++++++
.../SemaSPIRV/BuiltIns/invalid_target_vk.c | 15 ++++++
15 files changed, 163 insertions(+), 63 deletions(-)
delete mode 100644 clang/include/clang/Basic/BuiltinsSPIRV.td
create mode 100644 clang/include/clang/Basic/BuiltinsSPIRVBase.td
create mode 100644 clang/include/clang/Basic/BuiltinsSPIRVCL.td
create mode 100644 clang/include/clang/Basic/BuiltinsSPIRVCommon.td
create mode 100644 clang/include/clang/Basic/BuiltinsSPIRVVK.td
create mode 100644 clang/test/SemaSPIRV/BuiltIns/invalid_target_cl.c
create mode 100644 clang/test/SemaSPIRV/BuiltIns/invalid_target_vk.c
diff --git a/clang/include/clang/Basic/BuiltinsSPIRV.td b/clang/include/clang/Basic/BuiltinsSPIRV.td
deleted file mode 100644
index bbb2abba2e256..0000000000000
--- a/clang/include/clang/Basic/BuiltinsSPIRV.td
+++ /dev/null
@@ -1,48 +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"
-
-class SPIRVBuiltin<string prototype, list<Attribute> Attr> : Builtin {
- let Spellings = ["__builtin_spirv_"#NAME];
- let Prototype = prototype;
- let Attributes = !listconcat([NoThrow], Attr);
-}
-
-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(...)";
-}
-
-def generic_cast_to_ptr_explicit
- : SPIRVBuiltin<"void*(void*, int)", [NoThrow, Const, CustomTypeChecking]>;
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 265ea1fc06494..1e401f383c9f6 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -103,9 +103,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 8f088d4d0d0f8..4d7b739f23728 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12741,6 +12741,8 @@ 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<
diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h
index 4e490d87ee8d6..66bbe3cdc99a7 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/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp
index fe13e4ee25a36..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>
BaseSPIRVTargetInfo::getTargetBuiltins() const {
- return {{&BuiltinStrings, BuiltinInfos}};
+ return {{&BuiltinStrings, BuiltinInfos},
+ {&VK::BuiltinStrings, VK::BuiltinInfos},
+ {&CL::BuiltinStrings, CL::BuiltinInfos}};
}
void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 85309186b2e9a..9d2ffcf7a11a3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -96,12 +96,13 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF,
case llvm::Triple::riscv32:
case llvm::Triple::riscv64:
return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue);
- case llvm::Triple::spirv:
case llvm::Triple::spirv32:
case llvm::Triple::spirv64:
- if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
- return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E);
- return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E);
+ if (CGF->getTarget().getTriple().getOS() == llvm::Triple::OSType::AMDHSA)
+ return CGF->EmitAMDGPUBuiltinExpr(BuiltinID, E);
+ [[fallthrough]];
+ case llvm::Triple::spirv:
+ return CGF->EmitSPIRVBuiltinExpr(BuiltinID, E);
default:
return nullptr;
}
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index fb0f2d2c0d57b..c5985ba2a9993 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1986,7 +1986,7 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
case llvm::Triple::spirv32:
case llvm::Triple::spirv64:
if (TI.getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
- return SPIRV().CheckSPIRVBuiltinFunctionCall(BuiltinID, TheCall);
+ return SPIRV().CheckSPIRVBuiltinFunctionCall(TI, BuiltinID, TheCall);
return false;
case llvm::Triple::systemz:
return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall);
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index d5b37e0b8aff6..bd72194b905f5 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -10,6 +10,7 @@
#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
@@ -138,8 +139,21 @@ static bool checkGenericCastToPtr(Sema &SemaRef, CallExpr *Call) {
return false;
}
-bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(unsigned BuiltinID,
+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))
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 at -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 at -1 {{builtin requires spirv target}}
+}
+
+// no error
+float valid_builtin(float2 X) { return __builtin_spirv_length(X); }
More information about the cfe-commits
mailing list