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 <vic...@codeplay.com>
Date: Mon, 28 Apr 2025 16:20:09 +0100
Subject: [PATCH] [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@-1 {{too few arguments to function call, expected 2, have 
1}}
+  __builtin_spirv_generic_cast_to_ptr_explicit(p, 7, p);
+  // expected-error@-1 {{too many arguments to function call, expected 2, have 
3}}
+}
+
+void test_wrong_flag_value(int* p) {
+  __builtin_spirv_generic_cast_to_ptr_explicit(p, 14);
+  // expected-error@-1 {{invalid value for storage class argument}}
+}
+
+void test_wrong_address_space(__attribute__((opencl_local)) int* p) {
+  __builtin_spirv_generic_cast_to_ptr_explicit(p, 14);
+  // expected-error@-1 {{expecting a pointer argument to the generic address 
space}}
+}
+
+void test_not_a_pointer(int p) {
+  __builtin_spirv_generic_cast_to_ptr_explicit(p, 14);
+  // expected-error@-1 {{expecting a pointer argument to the generic address 
space}}
+}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to