-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang][SPIRV] Add builtin for OpGenericCastToPtrExplicit and its SPIR-V friendly binding #137805
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-backend-spir-v @llvm/pr-subscribers-clang Author: Victor Lomuller (Naghasan) ChangesThe 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. 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). Patch is 28.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137805.diff 15 Files Affected:
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..d742ae8ff044d 100644
--- a/clang/lib/Basic/Targets/SPIR.cpp
+++ b/clang/lib/Basic/Targets/SPIR.cpp
@@ -35,8 +35,10 @@ static constexpr Builtin::Info BuiltinInfos[] = {
static_assert(std::size(BuiltinInfos) == NumBuiltins);
llvm::SmallVector<Builtin::InfosShard>
-SPIRVTargetInfo::getTargetBuiltins() const {
- return {{&BuiltinStrings, BuiltinInfos}};
+BaseSPIRTargetInfo::getTargetBuiltins() const {
+ if (getTriple().isSPIRV())
+ return {{&BuiltinStrings, BuiltinInfos}};
+ return {};
}
void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..c6c31884db34d 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -164,9 +164,7 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
// memcpy as per section 3 of the SPIR spec.
bool useFP16ConversionIntrinsics() const override { return false; }
- llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
- return {};
- }
+ llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
std::string_view getClobbers() const override { return ""; }
@@ -321,8 +319,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..e526e0b62cf16 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;
+ if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
+ 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..0b23fc87b4511
--- /dev/null
+++ b/clang/lib/Headers/__clang_spirv_builtins.h
@@ -0,0 +1,176 @@
+/*===---- 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..9282d02bcb8f5 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,96 @@ 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->EvaluateA...
[truncated]
|
@llvm/pr-subscribers-clang-codegen Author: Victor Lomuller (Naghasan) ChangesThe 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. 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). Patch is 28.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137805.diff 15 Files Affected:
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..d742ae8ff044d 100644
--- a/clang/lib/Basic/Targets/SPIR.cpp
+++ b/clang/lib/Basic/Targets/SPIR.cpp
@@ -35,8 +35,10 @@ static constexpr Builtin::Info BuiltinInfos[] = {
static_assert(std::size(BuiltinInfos) == NumBuiltins);
llvm::SmallVector<Builtin::InfosShard>
-SPIRVTargetInfo::getTargetBuiltins() const {
- return {{&BuiltinStrings, BuiltinInfos}};
+BaseSPIRTargetInfo::getTargetBuiltins() const {
+ if (getTriple().isSPIRV())
+ return {{&BuiltinStrings, BuiltinInfos}};
+ return {};
}
void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..c6c31884db34d 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -164,9 +164,7 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
// memcpy as per section 3 of the SPIR spec.
bool useFP16ConversionIntrinsics() const override { return false; }
- llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
- return {};
- }
+ llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
std::string_view getClobbers() const override { return ""; }
@@ -321,8 +319,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..e526e0b62cf16 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;
+ if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
+ 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..0b23fc87b4511
--- /dev/null
+++ b/clang/lib/Headers/__clang_spirv_builtins.h
@@ -0,0 +1,176 @@
+/*===---- 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..9282d02bcb8f5 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,96 @@ 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->EvaluateA...
[truncated]
|
@llvm/pr-subscribers-backend-x86 Author: Victor Lomuller (Naghasan) ChangesThe 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. 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). Patch is 28.23 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137805.diff 15 Files Affected:
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..d742ae8ff044d 100644
--- a/clang/lib/Basic/Targets/SPIR.cpp
+++ b/clang/lib/Basic/Targets/SPIR.cpp
@@ -35,8 +35,10 @@ static constexpr Builtin::Info BuiltinInfos[] = {
static_assert(std::size(BuiltinInfos) == NumBuiltins);
llvm::SmallVector<Builtin::InfosShard>
-SPIRVTargetInfo::getTargetBuiltins() const {
- return {{&BuiltinStrings, BuiltinInfos}};
+BaseSPIRTargetInfo::getTargetBuiltins() const {
+ if (getTriple().isSPIRV())
+ return {{&BuiltinStrings, BuiltinInfos}};
+ return {};
}
void SPIRTargetInfo::getTargetDefines(const LangOptions &Opts,
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index bf249e271a870..c6c31884db34d 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -164,9 +164,7 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
// memcpy as per section 3 of the SPIR spec.
bool useFP16ConversionIntrinsics() const override { return false; }
- llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override {
- return {};
- }
+ llvm::SmallVector<Builtin::InfosShard> getTargetBuiltins() const override;
std::string_view getClobbers() const override { return ""; }
@@ -321,8 +319,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..e526e0b62cf16 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;
+ if (CGF->getTarget().getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
+ 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..0b23fc87b4511
--- /dev/null
+++ b/clang/lib/Headers/__clang_spirv_builtins.h
@@ -0,0 +1,176 @@
+/*===---- 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..9282d02bcb8f5 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,96 @@ 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->EvaluateA...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Sorry I can't assign reviewers, @JonChesterfield @jhuber6 as you are involved in gpuintrin.h, I'd welcome feedbacks here (feel free to ping other relevant persons) For the SPIR-V side of thing @VyacheslavLevytskyy @farzonl I appreciate your feedbacks as well :) FYI @tahonermann |
c01ab8c
to
90725e8
Compare
clang/lib/Basic/Targets/SPIR.cpp
Outdated
return {{&BuiltinStrings, BuiltinInfos}}; | ||
BaseSPIRTargetInfo::getTargetBuiltins() const { | ||
if (getTriple().isSPIRV()) | ||
return {{&BuiltinStrings, BuiltinInfos}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this change (in SPIR.cpp and SPIR.h) is necessesary. The existing code accomplished the same thing with method overriding. The original code also had some defensive programming safety to me. We went from a compile time enforcement of SPIRVTargetInfo== BuiltinsSPIRV.td to now a runtime enforcement. The problem with that is the next guy that comes along and makes a change might assume the builtins so far are SPIRV and thats why you are checking the triple, then add a new SPIR flavor builtin that would not be valid for SPIRV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's a left over of my initial prototype in intel/llvm sorry. For historical reasons spir
/ spir64
is also used there, so had to hack a bit to allow proper testing there. The change should be moving it to BaseSPIRVTargetInfo
to only enable spirv
, spirv32
and spirv64
. I updated the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok we might have a hierarchy problem then how do we say a builtin is valid for spirv
but not spirv32
or spriv64
and vice versa. How do we say which ones are valid across all targets? See #137805 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a few thought about this, but there is a bit more to it:
- Vulkan vs OpenCL environment (and for which target version)
- Enabled vs disabled extensions
- SPIR-V version
each will have an impact on the set of enabled builtins. A split between common, Vk env (spirv
) and OpenCL env (spirv32
/ spirv64
) builtins is probably a good step towards answering (1) by construction. What I don't like though is you'll end up with an "unknown builtin" rather than a clear message.
For the rest, I wanted to create an RFC to suggest the use of target features as there is plenty of existing infrastructure for this job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we had a BuiltinsSPIRVCore.td
BuiltinsSPIRVVK.td
and a BuiltinsSPIRVCL.td
The stuff shared between CL and VK could live in Core and the VK and CL builtins will include the Core one. That should let us have seperate SPIRVTargetInfo
and SPIRV64TargetInfo
/SPIRV32TargetInfo
. You won't have an unknown builtin if we do it this way because we would never expose the builtins that aren't valid for the target.
It could complicate codegen though forcing seperate emitters for spriv and spirv32/64 so not a silver bullet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll consider this issue resolved though if you plan to address it via an RFC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we had a BuiltinsSPIRVCore.td BuiltinsSPIRVVK.td and a BuiltinsSPIRVCL.td
I was looking into doing this.
You won't have an unknown builtin if we do it this way because we would never expose the builtins that aren't valid for the target.
You will if you use a VK one when targeting spirv64
rather than a clear message. But it is nitpicking and I only have a weak preference on the matter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@farzonl Apply the suggestion, although you can't really split into 2 distinct set cleanly (common + vk and common + cl) due to the ID assignment (part is done dynamically). So I went for a unique set and diagnose when vk builtins are used with spirv32 or spirv32 or when cl builtins are used with spirv.
clang/lib/Basic/Targets/SPIR.cpp
Outdated
SPIRVTargetInfo::getTargetBuiltins() const { | ||
return {{&BuiltinStrings, BuiltinInfos}}; | ||
BaseSPIRTargetInfo::getTargetBuiltins() const { | ||
if (getTriple().isSPIRV()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you are using this to extend the builtins to spirv32/spirv64 I have concerns that not all builtins will be valid for those targets. For example __builtin_spirv_reflect
is only valid when targeting spirv because thats the target that enables GLSL extentions. It is not valid for spirv32/64 because there is no equivalent opencl extention. To expose across all targets without exposing builtins that break could be tricky and might require special codegen to emulate the behavior of other targets. It might be simpler to just do a new tablegen file for spirv32/spriv64.
…R-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.
90725e8
to
020a804
Compare
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)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not affecting HLSL in any way here.
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.
05e0d73
to
1615b6b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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).