[clang] [clang][SPIR-V] Use the C calling convention as the target default (PR #210882)
Arseniy Obolenskiy via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 11 21:58:05 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/210882
>From 17a63a34403b3cd2620454adf7f898f775301d0f Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 21 Jul 2026 07:54:07 +0200
Subject: [PATCH 1/6] [clang][HIP] Normalize __cdecl on abstract function types
to the device default CC on amdgcnspirv
On amdgcnspirv, __cdecl has no device-side equivalent, so it needs to be normalized to the device default CC to match plain function type
---
clang/lib/Sema/SemaType.cpp | 13 +++++++
...mdgcnspirv-host-cconv-in-abstract-type.hip | 35 +++++++++++++++++++
2 files changed, 48 insertions(+)
create mode 100644 clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index f7789b7475e8e..b994080a58bb4 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8349,6 +8349,19 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
const FunctionType *fn = unwrapped.get();
+
+ // On amdgcnspirv, __cdecl on an abstract function type has no device-side
+ // equivalent, so normalize it to the device default CC to match an
+ // unadorned function type. Skip named decls and variadic types.
+ if (CC == CC_C && S.getLangOpts().CUDAIsDevice &&
+ S.Context.getTargetInfo().getTriple().isSPIRV() &&
+ state.getDeclarator().mayOmitIdentifier()) {
+ const auto *FnP = dyn_cast<FunctionProtoType>(fn);
+ if (!FnP || !FnP->isVariadic())
+ CC = S.Context.getDefaultCallingConvention(/*IsVariadic=*/false,
+ /*IsCXXMethod=*/false);
+ }
+
CallingConv CCOld = fn->getCallConv();
Attr *CCAttr = getCCTypeAttr(S.Context, attr);
diff --git a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
new file mode 100644
index 0000000000000..a624edc1bf564
--- /dev/null
+++ b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv32 -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
+// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
+// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
+
+// __cdecl on an abstract function type must normalize to the device default
+// so std::function<void()> matches the library specialization keyed on
+// __cdecl on amdgcnspirv Windows.
+
+// expected-no-diagnostics
+
+template <class T> struct classify_fn {
+ static constexpr int value = 0;
+};
+template <class R, class... A> struct classify_fn<R __cdecl(A...)> {
+ static constexpr int value = 1;
+};
+template <class R, class... A> struct classify_fn<R __vectorcall(A...)> {
+ static constexpr int value = 2;
+};
+template <class R> struct classify_fn<R __cdecl(int, ...)> {
+ static constexpr int value = 3;
+};
+
+// Unadorned function types resolve to the __cdecl specialization.
+static_assert(classify_fn<void()>::value == 1, "void() must match __cdecl");
+static_assert(classify_fn<int(double, char)>::value == 1,
+ "int(double,char) must match __cdecl");
+
+// Variadic __cdecl keeps its own specialization, not the device default.
+static_assert(classify_fn<int __cdecl(int, ...)>::value == 3,
+ "variadic __cdecl must match its own specialization");
+
+// __vectorcall must not be folded into the device default alongside __cdecl.
+static_assert(classify_fn<void __vectorcall()>::value == 2,
+ "__vectorcall must match its own specialization, not __cdecl");
>From 505fb719f26338dfbf50267947ba62e0e86481de Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 5 Aug 2026 09:01:02 +0200
Subject: [PATCH 2/6] prototype
---
clang/include/clang/Basic/TargetInfo.h | 9 +++++++++
clang/lib/Basic/Targets/SPIR.h | 10 ++++++++--
clang/lib/CodeGen/CGCall.cpp | 7 +++++++
clang/lib/Sema/SemaDecl.cpp | 2 +-
clang/lib/Sema/SemaType.cpp | 17 +++--------------
.../CodeGenHLSL/builtins/ConstantBuffer.hlsl | 8 ++++----
.../CodeGenHLSL/resources/ConstantBufferT.hlsl | 8 ++++----
.../resources/NonUniformResourceIndex.hlsl | 6 +++---
.../StructuredBuffers-constructors.hlsl | 18 +++++++++---------
.../resources/Textures-GetDimensions.hlsl | 16 ++++++++--------
.../resources/Textures-Subscript.hlsl | 12 ++++++------
.../resources/TypedBuffers-constructor.hlsl | 18 +++++++++---------
.../resources/res-array-global-multi-dim.hlsl | 8 ++++----
.../resources/res-array-global-unbounded.hlsl | 8 ++++----
.../resources/res-array-global.hlsl | 10 +++++-----
.../resources/res-array-rw-counter.hlsl | 8 ++++----
...amdgcnspirv-host-cconv-in-abstract-type.hip | 13 ++++---------
clang/test/SemaSYCL/sycl-cconv.cpp | 7 ++++---
18 files changed, 96 insertions(+), 89 deletions(-)
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 3aba4d261a651..9e89179ddfe18 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1787,6 +1787,15 @@ class TargetInfo : public TransferrableTargetInfo,
}
}
+ /// Determines whether a call using the given calling convention may be
+ /// variadic on this target. Unlike the target-agnostic
+ /// supportsVariadicCall(), this allows a target to reject its own default
+ /// calling convention (e.g. when that default is only nominally CC_C but
+ /// lowers to an ABI that cannot support variadic calls).
+ virtual bool supportsCallingConvVariadic(CallingConv CC) const {
+ return supportsVariadicCall(CC);
+ }
+
enum CallingConvKind {
CCK_Default,
CCK_ClangABI4OrPS4,
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 0547c9702ffd4..46eaf5f2131e2 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -200,8 +200,14 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
: CCCR_Warning;
}
- CallingConv getDefaultCallingConv() const override {
- return CC_SpirFunction;
+ CallingConv getDefaultCallingConv() const override { return CC_C; }
+
+ bool supportsCallingConvVariadic(CallingConv CC) const override {
+ // CC_C is the AST-level default calling convention on this target, but it
+ // still lowers to spir_func, which cannot support variadic calls.
+ if (CC == CC_C)
+ return false;
+ return TargetInfo::supportsCallingConvVariadic(CC);
}
void setAddressSpaceMap(bool DefaultIsGeneric) {
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 08cb9860f2f92..b53cdcb1cbf05 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -61,6 +61,13 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
switch (CC) {
default:
return llvm::CallingConv::C;
+ case CC_C:
+ // On SPIR/SPIR-V, CC_C is the AST-level default calling convention, but
+ // it still needs to lower to spir_func so IR consumers can rely on the
+ // calling convention to distinguish device functions.
+ if (Target.getTriple().isSPIROrSPIRV())
+ return llvm::CallingConv::SPIR_FUNC;
+ return llvm::CallingConv::C;
case CC_X86StdCall:
return llvm::CallingConv::X86_StdCall;
case CC_X86FastCall:
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7de5542e72559..d43e340641b2f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10782,7 +10782,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
const FunctionType *FT = NewFD->getType()->castAs<FunctionType>();
if (isa<FunctionNoProtoType>(FT) && !D.isFunctionDefinition()) {
CallingConv CC = FT->getExtInfo().getCC();
- if (!supportsVariadicCall(CC)) {
+ if (!Context.getTargetInfo().supportsCallingConvVariadic(CC)) {
// Windows system headers sometimes accidentally use stdcall without
// (void) parameters, so we relax this to a warning.
int DiagID =
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index b994080a58bb4..b6094e62d014a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3772,7 +3772,8 @@ static CallingConv getCCForDeclaratorChunk(
CallingConv CC;
if (!S.CheckCallingConvAttr(AL, CC, /*FunctionDecl=*/nullptr,
S.CUDA().IdentifyTarget(D.getAttributes())) &&
- (!FTI.isVariadic || supportsVariadicCall(CC))) {
+ (!FTI.isVariadic ||
+ S.Context.getTargetInfo().supportsCallingConvVariadic(CC))) {
return CC;
}
break;
@@ -8350,18 +8351,6 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
const FunctionType *fn = unwrapped.get();
- // On amdgcnspirv, __cdecl on an abstract function type has no device-side
- // equivalent, so normalize it to the device default CC to match an
- // unadorned function type. Skip named decls and variadic types.
- if (CC == CC_C && S.getLangOpts().CUDAIsDevice &&
- S.Context.getTargetInfo().getTriple().isSPIRV() &&
- state.getDeclarator().mayOmitIdentifier()) {
- const auto *FnP = dyn_cast<FunctionProtoType>(fn);
- if (!FnP || !FnP->isVariadic())
- CC = S.Context.getDefaultCallingConvention(/*IsVariadic=*/false,
- /*IsCXXMethod=*/false);
- }
-
CallingConv CCOld = fn->getCallConv();
Attr *CCAttr = getCCTypeAttr(S.Context, attr);
@@ -8385,7 +8374,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// prototype that way. And apparently we also "delay" warning about
// unprototyped function types in general, despite not necessarily having
// much ability to diagnose it later.
- if (!supportsVariadicCall(CC)) {
+ if (!S.Context.getTargetInfo().supportsCallingConvVariadic(CC)) {
const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
if (FnP && FnP->isVariadic()) {
// stdcall and fastcall are ignored with a warning for GCC and MS
diff --git a/clang/test/CodeGenHLSL/builtins/ConstantBuffer.hlsl b/clang/test/CodeGenHLSL/builtins/ConstantBuffer.hlsl
index a9e17527e6fcc..132ccdb735643 100644
--- a/clang/test/CodeGenHLSL/builtins/ConstantBuffer.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/ConstantBuffer.hlsl
@@ -15,7 +15,7 @@ ConstantBuffer<S> cb;
// CHECK-DXIL: [[GEP_A:%.*]] = getelementptr inbounds nuw %S, ptr addrspace(2) [[CB_CONV]], i32 0, i32 0
// CHECK-DXIL: [[LOAD_A:%.*]] = load float, ptr addrspace(2) [[GEP_A]], align 4
-// CHECK-SPIRV: [[CB_CONV:%.*]] = call noundef {{.*}} ptr addrspace(12) @_ZNK4hlsl14ConstantBufferI1SEcvRU4AS12KS1_Ev(ptr noundef nonnull align 8 dereferenceable(8) @_ZL2cb)
+// CHECK-SPIRV: [[CB_CONV:%.*]] = call spir_func noundef {{.*}} ptr addrspace(12) @_ZNK4hlsl14ConstantBufferI1SEcvRU4AS12KS1_Ev(ptr noundef nonnull align 8 dereferenceable(8) @_ZL2cb)
// CHECK-SPIRV: [[GEP_A:%.*]] = getelementptr inbounds nuw %S, ptr addrspace(12) [[CB_CONV]], i32 0, i32 0
// CHECK-SPIRV: [[LOAD_A:%.*]] = load float, ptr addrspace(12) [[GEP_A]], align 4
@@ -43,8 +43,8 @@ void foo() {
// CHECK-DXIL: [[LOAD_A2:%.*]] = load float, ptr addrspace(2) [[GEP_A2]], align 4
// CHECK-SPIRV: [[TMP_CB:%.*]] = alloca %"class.hlsl::ConstantBuffer.0", align 8
- // CHECK-SPIRV: call void @_ZN4hlsl14ConstantBufferI6NestedE27__createFromImplicitBindingEjjijPKc(ptr dead_on_unwind writable sret(%"class.hlsl::ConstantBuffer.0") align 8 [[TMP_CB]], i32 noundef 1, i32 noundef 0, i32 noundef 2, i32 noundef 1, ptr noundef @cb_nested.str)
- // CHECK-SPIRV: [[CB_CONV:%.*]] = call noundef {{.*}} ptr addrspace(12) @_ZNK4hlsl14ConstantBufferI6NestedEcvRU4AS12KS1_Ev(ptr noundef nonnull align 8 dereferenceable(8) [[TMP_CB]])
+ // CHECK-SPIRV: call spir_func void @_ZN4hlsl14ConstantBufferI6NestedE27__createFromImplicitBindingEjjijPKc(ptr dead_on_unwind writable sret(%"class.hlsl::ConstantBuffer.0") align 8 [[TMP_CB]], i32 noundef 1, i32 noundef 0, i32 noundef 2, i32 noundef 1, ptr noundef @cb_nested.str)
+ // CHECK-SPIRV: [[CB_CONV:%.*]] = call spir_func noundef {{.*}} ptr addrspace(12) @_ZNK4hlsl14ConstantBufferI6NestedEcvRU4AS12KS1_Ev(ptr noundef nonnull align 8 dereferenceable(8) [[TMP_CB]])
// CHECK-SPIRV: [[GEP_S:%.*]] = getelementptr inbounds nuw %Nested, ptr addrspace(12) [[CB_CONV]], i32 0, i32 0
// CHECK-SPIRV: [[GEP_A2:%.*]] = getelementptr inbounds nuw %S, ptr addrspace(12) [[GEP_S]], i32 0, i32 0
// CHECK-SPIRV: [[LOAD_A2:%.*]] = load float, ptr addrspace(12) [[GEP_A2]], align 4
@@ -58,7 +58,7 @@ void takes_cb(ConstantBuffer<S> c) {}
[numthreads(1,1,1)]
void test_params() {
// CHECK-LABEL: define {{.*}} void @_Z11test_paramsv()
- // CHECK: call void @_ZN4hlsl14ConstantBufferI1SEC1ERKS2_(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %agg.tmp, ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @_ZL2cb)
+ // CHECK: call {{(spir_func )?}}void @_ZN4hlsl14ConstantBufferI1SEC1ERKS2_(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %agg.tmp, ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @_ZL2cb)
// CHECK-DXIL: call void @_Z8takes_cbN4hlsl14ConstantBufferI1SEE(ptr noundef align 4 dead_on_return %agg.tmp)
// CHECK-SPIRV: call {{.*}} void @_Z8takes_cbN4hlsl14ConstantBufferI1SEE(ptr noundef align 8 dead_on_return %agg.tmp)
takes_cb(cb);
diff --git a/clang/test/CodeGenHLSL/resources/ConstantBufferT.hlsl b/clang/test/CodeGenHLSL/resources/ConstantBufferT.hlsl
index 30c2c9bb5c2f6..41e8669d7a505 100644
--- a/clang/test/CodeGenHLSL/resources/ConstantBufferT.hlsl
+++ b/clang/test/CodeGenHLSL/resources/ConstantBufferT.hlsl
@@ -40,11 +40,11 @@ ConstantBuffer<S> CBArray[2];
// CB initialization
//
// CHECK-LABEL: __cxx_global_var_init
-// CHECK: call void @hlsl::ConstantBuffer<MyConstants>::__createFromImplicitBinding({{[^)]+}})
+// CHECK: call {{(spir_func )?}}void @hlsl::ConstantBuffer<MyConstants>::__createFromImplicitBinding({{[^)]+}})
// CHECK-SAME: (ptr dead_on_unwind writable sret(%"class.hlsl::ConstantBuffer") align {{(4|8)}} @CB,
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 1, i32 noundef 0, ptr noundef [[CBStr]])
-// CHECK: define linkonce_odr hidden void @hlsl::ConstantBuffer<MyConstants>::__createFromImplicitBinding(
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::ConstantBuffer<MyConstants>::__createFromImplicitBinding(
// CHECK-DXIL: call target("dx.CBuffer", %MyConstants) @llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_s_MyConstantsst
// CHECK-SPV: call target("spirv.VulkanBuffer", %MyConstants, 2, 0) @llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s_MyConstantss_2_0t(
@@ -121,7 +121,7 @@ void TestArrayAccess() {
// CHECK: [[TMP0:%.*]] = alloca %"class.hlsl::ConstantBuffer.0", align {{(4|8)}}
// CHECK: [[TMP1:%.*]] = alloca %"class.hlsl::ConstantBuffer.0", align {{(4|8)}}
-// CHECK: call void @hlsl::ConstantBuffer<S>::__createFromImplicitBinding({{.*}})(ptr {{.*}} sret(%"class.hlsl::ConstantBuffer.0") align {{(4|8)}} [[TMP0]],
+// CHECK: call {{(spir_func )?}}void @hlsl::ConstantBuffer<S>::__createFromImplicitBinding({{.*}})(ptr {{.*}} sret(%"class.hlsl::ConstantBuffer.0") align {{(4|8)}} [[TMP0]],
// CHECK-SAME: i32 noundef 1, i32 noundef 0, i32 noundef 2, i32 noundef 1, ptr noundef [[CBArrayStr]])
// CHECK-NEXT: [[CB_1_PTR:%.*]] = call {{.*}} ptr addrspace([[CONST_ADDR_SPACE]]) @hlsl::ConstantBuffer<S>::operator S const AS[[CONST_ADDR_SPACE]]&() const(ptr{{.*}} [[TMP0]])
// CHECK-NEXT: [[CB_1_F3_PTR:%.*]] = getelementptr inbounds nuw %S, ptr addrspace([[CONST_ADDR_SPACE]]) [[CB_1_PTR]], i32 0, i32 0
@@ -129,7 +129,7 @@ void TestArrayAccess() {
// CHECK-NEXT: store <3 x float> [[CB_1_F3]], ptr %f3, align 4
float3 f3 = CBArray[1].f3;
-// CHECK: call void @hlsl::ConstantBuffer<S>::__createFromImplicitBinding({{.*}})(ptr {{.*}} sret(%"class.hlsl::ConstantBuffer.0") align {{(4|8)}} [[TMP1]],
+// CHECK: call {{(spir_func )?}}void @hlsl::ConstantBuffer<S>::__createFromImplicitBinding({{.*}})(ptr {{.*}} sret(%"class.hlsl::ConstantBuffer.0") align {{(4|8)}} [[TMP1]],
// CHECK-SAME: i32 noundef 1, i32 noundef 0, i32 noundef 2, i32 noundef 0, ptr noundef [[CBArrayStr]])
// CHECK-NEXT: [[CB_0_PTR:%.*]] = call {{.*}} ptr addrspace([[CONST_ADDR_SPACE]]) @hlsl::ConstantBuffer<S>::operator S const AS[[CONST_ADDR_SPACE]]&() const(ptr{{.*}} [[TMP1]])
// CHECK-NEXT: [[CB_0_A_PTR:%.*]] = getelementptr inbounds nuw %S, ptr addrspace([[CONST_ADDR_SPACE]]) [[CB_0_PTR]], i32 0, i32 1
diff --git a/clang/test/CodeGenHLSL/resources/NonUniformResourceIndex.hlsl b/clang/test/CodeGenHLSL/resources/NonUniformResourceIndex.hlsl
index b2712561dceaf..2b68c931f010c 100644
--- a/clang/test/CodeGenHLSL/resources/NonUniformResourceIndex.hlsl
+++ b/clang/test/CodeGenHLSL/resources/NonUniformResourceIndex.hlsl
@@ -9,7 +9,7 @@ RWBuffer<float> A[10];
void main(uint GI : SV_GroupID) {
// CHECK: %[[GI:.*]] = load i32, ptr %GI.addr
// CHECK: %[[NURI_1:.*]] = call i32 @llvm.[[TARGET]].resource.nonuniformindex(i32 %[[GI]])
- // CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[NURI_1]], ptr noundef @A.str)
float a = A[NonUniformResourceIndex(GI)][0];
@@ -17,7 +17,7 @@ void main(uint GI : SV_GroupID) {
// CHECK: %[[ADD:.*]] = add i32 %[[GI]], 1
// CHECK: %[[NURI_2:.*]] = call i32 @llvm.[[TARGET]].resource.nonuniformindex(i32 %[[ADD]])
// CHECK: %[[MOD:.*]] = urem i32 %[[NURI_2]], 10
- // CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[MOD]], ptr noundef @A.str)
float b = A[NonUniformResourceIndex(GI + 1) % 10][0];
@@ -25,7 +25,7 @@ void main(uint GI : SV_GroupID) {
// CHECK: %[[NURI_3:.*]] = call i32 @llvm.[[TARGET]].resource.nonuniformindex(i32 %[[GI]])
// CHECK: %[[MUL:.*]] = mul i32 3, %[[NURI_3]]
// CHECK: %[[ADD2:.*]] = add i32 10, %[[MUL]]
- // CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[ADD2]], ptr noundef @A.str)
float c = A[10 + 3 * NonUniformResourceIndex(GI)][0];
A[0][0] = a + b + c;
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
index cd0d2ec0c4c2a..801e734de7cb5 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
@@ -32,7 +32,7 @@ export void foo() {
// with explicit binding
// CHECK: define internal {{.*}}void @__cxx_global_var_init()
// CHECK-NEXT: entry:
-// CHECK: call void @hlsl::StructuredBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK: call {{(spir_func )?}}void @hlsl::StructuredBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} @Buf1, i32 noundef 10, i32 noundef 2, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]])
// Buf1 initialization part 2 - body of StructuredBuffer<float>::::__createFromBinding
@@ -45,16 +45,16 @@ export void foo() {
// CHECK-DXIL-SAME: @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::StructuredBuffer", ptr %[[Tmp1]], i32 0, i32 0
// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) %[[Handle1]], ptr %__handle, align 4
-// CHECK: call void @hlsl::StructuredBuffer<float>::StructuredBuffer(hlsl::StructuredBuffer<float> const&)(ptr {{.*}} %[[RetValue1]], ptr {{.*}} %[[Tmp1]])
+// CHECK: call {{(spir_func )?}}void @hlsl::StructuredBuffer<float>::StructuredBuffer(hlsl::StructuredBuffer<float> const&)(ptr {{.*}} %[[RetValue1]], ptr {{.*}} %[[Tmp1]])
// Buf2 initialization part 1 - global init function that calls RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter
// CHECK: define internal {{.*}}void @__cxx_global_var_init.1()
// CHECK-NEXT: entry:
-// CHECK: call void @hlsl::RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter(unsigned int, unsigned int, int, unsigned int, char const*, unsigned int)
+// CHECK: call {{(spir_func )?}}void @hlsl::RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter(unsigned int, unsigned int, int, unsigned int, char const*, unsigned int)
// CHECK-SAME: (ptr {{.*}} @Buf2, i32 noundef 0, i32 noundef 0, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf2Str]], i32 noundef 1)
// Buf2 initialization part 2 - body of RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter
-// CHECK: define linkonce_odr hidden void @hlsl::RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter(unsigned int, unsigned int, int, unsigned int, char const*, unsigned int)
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter(unsigned int, unsigned int, int, unsigned int, char const*, unsigned int)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWStructuredBuffer") align {{(4|8)}} %[[RetValue2:.*]], i32 noundef %orderId,
// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name, i32 noundef %counterOrderId)
// CHECK-SPV: %[[ConvTok:.*]] = call token @llvm.experimental.convergence.entry()
@@ -77,23 +77,23 @@ export void foo() {
// CHECK-SPV-SAME: [ "convergencectrl"(token %[[ConvTok]]) ]
// CHECK-SPV: %[[CounterHandlePtr:.*]] = getelementptr inbounds nuw %"class.hlsl::RWStructuredBuffer", ptr %[[Tmp2]], i32 0, i32 1
// CHECK-SPV-NEXT: store target("spirv.VulkanBuffer", i32, 12, 1) %[[CounterHandle]], ptr %[[CounterHandlePtr]], align 8
-// CHECK: call void @hlsl::RWStructuredBuffer<float>::RWStructuredBuffer(hlsl::RWStructuredBuffer<float> const&)(ptr {{.*}} %[[RetValue2]], ptr {{.*}} %[[Tmp2]])
+// CHECK: call {{(spir_func )?}}void @hlsl::RWStructuredBuffer<float>::RWStructuredBuffer(hlsl::RWStructuredBuffer<float> const&)(ptr {{.*}} %[[RetValue2]], ptr {{.*}} %[[Tmp2]])
// Buf3 initialization part 1 - local variable declared in function foo() is initialized by
// AppendStructuredBuffer<float> C1 default constructor
// CHECK: define {{.*}}void @foo()
// CHECK-NEXT: entry:
// CHECK: %Buf3 = alloca %"class.hlsl::AppendStructuredBuffer", align {{4|8}}
-// CHECK-NEXT: call void @hlsl::AppendStructuredBuffer<float>::AppendStructuredBuffer()(ptr {{.*}} %Buf3)
+// CHECK-NEXT: call {{(spir_func )?}}void @hlsl::AppendStructuredBuffer<float>::AppendStructuredBuffer()(ptr {{.*}} %Buf3)
// Buf3 initialization part 2 - body of AppendStructuredBuffer<float> default C1 constructor that calls
// the default C2 constructor
-// CHECK: define linkonce_odr hidden void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this)
-// CHECK: call void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this1)
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this)
+// CHECK: call {{(spir_func )?}}void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this1)
// Buf3 initialization part 3 - body of AppendStructuredBuffer<float> default C2 constructor that
// initializes handle to poison
-// CHECK: define linkonce_odr hidden void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this)
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::StructuredBuffer<float>::StructuredBuffer()(ptr {{.*}} %this)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::AppendStructuredBuffer", ptr %{{.*}}, i32 0, i32 0
// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) poison, ptr %__handle, align 4
diff --git a/clang/test/CodeGenHLSL/resources/Textures-GetDimensions.hlsl b/clang/test/CodeGenHLSL/resources/Textures-GetDimensions.hlsl
index 38ee3f8679701..303dcc4145ab0 100644
--- a/clang/test/CodeGenHLSL/resources/Textures-GetDimensions.hlsl
+++ b/clang/test/CodeGenHLSL/resources/Textures-GetDimensions.hlsl
@@ -17,13 +17,13 @@
TEXTURE<float4> Tex;
// CHECK: define {{.*}} void @test_uint_dims{{(\(\))?}}()
-// CHECK: call void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} @Tex, ptr {{.*}}, ptr {{.*}})
+// CHECK: call {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} @Tex, ptr {{.*}}, ptr {{.*}})
void test_uint_dims() {
uint w, h;
Tex.GetDimensions(w, h);
}
-// CHECK: define linkonce_odr hidden void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} %[[THIS:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int&, unsigned int&)(ptr {{.*}} %[[THIS:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]])
// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS]]
// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::[[TEXTURE]]", ptr %[[THIS_VAL]], i32 0, i32 0
// DXIL: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, [[RW]], 0, 0, [[DXIL_TY]]), ptr %[[HANDLE_GEP]]
@@ -38,13 +38,13 @@ void test_uint_dims() {
// CHECK: store i32 %[[H_VAL]], ptr %[[H_PTR]]
// CHECK: define {{.*}} void @test_uint_levels_dims{{.*}}(i32 noundef %{{.*}})
-// CHECK: call void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, unsigned int&, unsigned int&, unsigned int&)(ptr {{.*}} @Tex, i32 noundef %{{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}})
+// CHECK: call {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, unsigned int&, unsigned int&, unsigned int&)(ptr {{.*}} @Tex, i32 noundef %{{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}})
void test_uint_levels_dims(uint mipLevel) {
uint w, h, l;
Tex.GetDimensions(mipLevel, w, h, l);
}
-// CHECK: define linkonce_odr hidden void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, unsigned int&, unsigned int&, unsigned int&)(ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[MIP:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]], ptr {{.*}} %[[LEVELS:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, unsigned int&, unsigned int&, unsigned int&)(ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[MIP:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]], ptr {{.*}} %[[LEVELS:.*]])
// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS]]
// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::[[TEXTURE]]", ptr %[[THIS_VAL]], i32 0, i32 0
// DXIL: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, [[RW]], 0, 0, [[DXIL_TY]]), ptr %[[HANDLE_GEP]]
@@ -63,13 +63,13 @@ void test_uint_levels_dims(uint mipLevel) {
// CHECK: store i32 %[[L_VAL]], ptr %[[L_PTR]]
// CHECK: define {{.*}} void @test_float_dims{{(\(\))?}}()
-// CHECK: call void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(float&, float&)(ptr {{.*}} @Tex, ptr {{.*}}, ptr {{.*}})
+// CHECK: call {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(float&, float&)(ptr {{.*}} @Tex, ptr {{.*}}, ptr {{.*}})
void test_float_dims() {
float w, h;
Tex.GetDimensions(w, h);
}
-// CHECK: define linkonce_odr hidden void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(float&, float&)(ptr {{.*}} %[[THIS:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(float&, float&)(ptr {{.*}} %[[THIS:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]])
// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS]]
// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::[[TEXTURE]]", ptr %[[THIS_VAL]], i32 0, i32 0
// DXIL: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, [[RW]], 0, 0, [[DXIL_TY]]), ptr %[[HANDLE_GEP]]
@@ -86,13 +86,13 @@ void test_float_dims() {
// CHECK: store float %[[H_F]], ptr %[[H_PTR]]
// CHECK: define {{.*}} void @test_float_levels_dims{{.*}}(i32 noundef %{{.*}})
-// CHECK: call void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, float&, float&, float&)(ptr {{.*}} @Tex, i32 noundef %{{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}})
+// CHECK: call {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, float&, float&, float&)(ptr {{.*}} @Tex, i32 noundef %{{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}})
void test_float_levels_dims(uint mipLevel) {
float w, h, l;
Tex.GetDimensions(mipLevel, w, h, l);
}
-// CHECK: define linkonce_odr hidden void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, float&, float&, float&)(ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[MIP:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]], ptr {{.*}} %[[LEVELS:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::[[TEXTURE]]<float vector[4]>::GetDimensions(unsigned int, float&, float&, float&)(ptr {{.*}} %[[THIS:.*]], i32 {{.*}} %[[MIP:.*]], ptr {{.*}} %[[WIDTH:.*]], ptr {{.*}} %[[HEIGHT:.*]], ptr {{.*}} %[[LEVELS:.*]])
// CHECK: %[[THIS_VAL:.*]] = load ptr, ptr %[[THIS]]
// CHECK: %[[HANDLE_GEP:.*]] = getelementptr inbounds nuw %"class.hlsl::[[TEXTURE]]", ptr %[[THIS_VAL]], i32 0, i32 0
// DXIL: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, [[RW]], 0, 0, [[DXIL_TY]]), ptr %[[HANDLE_GEP]]
diff --git a/clang/test/CodeGenHLSL/resources/Textures-Subscript.hlsl b/clang/test/CodeGenHLSL/resources/Textures-Subscript.hlsl
index 1d765ee9cd0a1..9eb34591678b7 100644
--- a/clang/test/CodeGenHLSL/resources/Textures-Subscript.hlsl
+++ b/clang/test/CodeGenHLSL/resources/Textures-Subscript.hlsl
@@ -21,19 +21,19 @@ void main(COORD_TYPE DTid : SV_DispatchThreadID) {
// CHECK: %[[VAL3:.*]] = alloca <3 x i32>
// CHECK: store <[[COORD_DIM]] x i32> %[[DTID]], ptr %[[DTID_ADDR]]
// CHECK: %[[DTID_VAL:.*]] = load <[[COORD_DIM]] x i32>, ptr %[[DTID_ADDR]]
-// CHECK: %[[CALL1:.*]] = call noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float vector[4]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL]])
+// CHECK: %[[CALL1:.*]] = call {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float vector[4]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL]])
// CHECK: %[[LOAD_VAL:.*]] = load <4 x float>, ptr{{.*}} %[[CALL1]]
// CHECK: store <4 x float> %[[LOAD_VAL]], ptr %[[VAL]]
// CHECK: %[[DTID_VAL2:.*]] = load <[[COORD_DIM]] x i32>, ptr %[[DTID_ADDR]]
-// CHECK: %[[CALL2:.*]] = call noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex2, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL2]])
+// CHECK: %[[CALL2:.*]] = call {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex2, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL2]])
// CHECK: %[[LOAD_VAL2:.*]] = load float, ptr{{.*}} %[[CALL2]]
// CHECK: store float %[[LOAD_VAL2]], ptr %[[VAL2]]
// CHECK: %[[DTID_VAL3:.*]] = load <[[COORD_DIM]] x i32>, ptr %[[DTID_ADDR]]
-// CHECK: %[[CALL3:.*]] = call noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<int vector[3]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex3, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL3]])
+// CHECK: %[[CALL3:.*]] = call {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<int vector[3]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) @Tex3, <[[COORD_DIM]] x i32> noundef %[[DTID_VAL3]])
// CHECK: %[[LOAD_VAL3:.*]] = load <3 x i32>, ptr{{.*}} %[[CALL3]]
// CHECK: store <3 x i32> %[[LOAD_VAL3]], ptr %[[VAL3]]
-// CHECK: define linkonce_odr hidden noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float vector[4]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float vector[4]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
// CHECK: %[[INDEX_ADDR:.*]] = alloca <[[COORD_DIM]] x i32>
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
@@ -47,7 +47,7 @@ void main(COORD_TYPE DTid : SV_DispatchThreadID) {
// SPIRV: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.{{.*}}(target("spirv.Image", float, 1, 2, [[ARRAYED]], 0, [[SAMPLED]], [[IMG_FMT]]) %[[HANDLE]], <[[COORD_DIM]] x i32> %[[INDEX_VAL]])
// CHECK: ret ptr {{.*}}%[[PTR]]
-// CHECK: define linkonce_odr hidden noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<float>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
// CHECK: %[[INDEX_ADDR:.*]] = alloca <[[COORD_DIM]] x i32>
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
@@ -61,7 +61,7 @@ void main(COORD_TYPE DTid : SV_DispatchThreadID) {
// SPIRV: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.{{.*}}(target("spirv.Image", float, 1, 2, [[ARRAYED]], 0, [[SAMPLED]], [[IMG_FMT]]) %[[HANDLE]], <[[COORD_DIM]] x i32> %[[INDEX_VAL]])
// CHECK: ret ptr {{.*}}%[[PTR]]
-// CHECK: define linkonce_odr hidden noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<int vector[3]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}noundef {{.*}}ptr{{.*}} @hlsl::[[TEXTURE]]<int vector[3]>::operator[](unsigned int vector[[[COORD_DIM]]]) const(ptr noundef nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) %[[THIS:.*]], <[[COORD_DIM]] x i32> noundef %[[INDEX:.*]])
// CHECK: %[[THIS_ADDR:.*]] = alloca ptr
// CHECK: %[[INDEX_ADDR:.*]] = alloca <[[COORD_DIM]] x i32>
// CHECK: store ptr %[[THIS]], ptr %[[THIS_ADDR]]
diff --git a/clang/test/CodeGenHLSL/resources/TypedBuffers-constructor.hlsl b/clang/test/CodeGenHLSL/resources/TypedBuffers-constructor.hlsl
index 037d71d45e67e..da2f923146d31 100644
--- a/clang/test/CodeGenHLSL/resources/TypedBuffers-constructor.hlsl
+++ b/clang/test/CodeGenHLSL/resources/TypedBuffers-constructor.hlsl
@@ -39,7 +39,7 @@ export void foo() {
// CHECK-SPIRV: define internal spir_func void @__cxx_global_var_init()
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
-// CHECK-NEXT: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 @Buf1, i32 noundef 5, i32 noundef 3, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]])
// CHECK-SPIRV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 8 @Buf1, i32 noundef 5, i32 noundef 3, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf1Str]])
@@ -57,18 +57,18 @@ export void foo() {
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer", ptr %[[Tmp1]], i32 0, i32 0
// CHECK-DXIL: store target("dx.TypedBuffer", float, 1, 0, 0) %[[Handle1]], ptr %__handle, align 4
// CHECK-SPIRV: store target("spirv.Image", float, 5, 2, 0, 0, 2, 3) %[[Handle1]], ptr %__handle, align 8
-// CHECK: call void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> const&)(ptr {{.*}} %[[RetValue1]], ptr {{.*}} %[[Tmp1]])
+// CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::RWBuffer(hlsl::RWBuffer<float> const&)(ptr {{.*}} %[[RetValue1]], ptr {{.*}} %[[Tmp1]])
// Buf2 initialization part 1 - global init function that RWBuffer<float>::__createFromImplicitBinding
// CHECK-DXIL: define internal void @__cxx_global_var_init.1()
// CHECK-SPIRV: define internal spir_func void @__cxx_global_var_init.1()
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
-// CHECK-NEXT: call void @hlsl::Buffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK-NEXT: call {{(spir_func )?}}void @hlsl::Buffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} @Buf2, i32 noundef 0, i32 noundef 0, i32 noundef 1, i32 noundef 0, ptr noundef @[[Buf2Str]])
// Buf2 initialization part 2 - body of Buffer<double>::__createFromImplicitBinding call
-// CHECK: define linkonce_odr hidden void @hlsl::Buffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::Buffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::Buffer") align 4 %[[RetValue2:.*]], i32 noundef %orderId,
// CHECK-SPIRV-SAME: (ptr {{.*}} sret(%"class.hlsl::Buffer") align 8 %[[RetValue2:.*]], i32 noundef %orderId,
// CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, ptr noundef %name)
@@ -81,7 +81,7 @@ export void foo() {
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::Buffer", ptr %[[Tmp2]], i32 0, i32 0
// CHECK-DXIL: store target("dx.TypedBuffer", double, 0, 0, 0) %[[Handle2]], ptr %__handle, align 4
// CHECK-SPIRV: store target("spirv.Image", double, 5, 2, 0, 0, 1, 0) %[[Handle2]], ptr %__handle, align 8
-// CHECK: call void @hlsl::Buffer<double>::Buffer(hlsl::Buffer<double> const&)(ptr {{.*}} %[[RetValue2]], ptr {{.*}} %[[Tmp2]])
+// CHECK: call {{(spir_func )?}}void @hlsl::Buffer<double>::Buffer(hlsl::Buffer<double> const&)(ptr {{.*}} %[[RetValue2]], ptr {{.*}} %[[Tmp2]])
// Buf3 initialization part 1 - local variable declared in function foo() is initialized by RWBuffer<int> C1 default constructor
// CHECK-DXIL: define void @foo()
@@ -90,14 +90,14 @@ export void foo() {
// CHECK-NEXT: %[[#C_ENTRY:]] = call token @llvm.experimental.convergence.entry()
// CHECK-DXIL-NEXT: %Buf3 = alloca %"class.hlsl::RWBuffer.0", align 4
// CHECK-SPIRV-NEXT: %Buf3 = alloca %"class.hlsl::RWBuffer.0", align 8
-// CHECK-NEXT: call void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %Buf3)
+// CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %Buf3)
// Buf3 initialization part 2 - body of RWBuffer<int> default C1 constructor that calls the default C2 constructor
-// CHECK: define linkonce_odr hidden void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %this)
-// CHECK: call void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %{{.*}})
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %this)
+// CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %{{.*}})
// Buf3 initialization part 3 - body of RWBuffer<int> default C2 constructor that initializes handle to poison
-// CHECK: define linkonce_odr hidden void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %this)
+// CHECK: define linkonce_odr hidden {{(spir_func )?}}void @hlsl::RWBuffer<int>::RWBuffer()(ptr {{.*}} %this)
// CHECK: %__handle = getelementptr inbounds nuw %"class.hlsl::RWBuffer.0", ptr %{{.*}}, i32 0, i32 0
// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", i32, 1, 0, 1) poison, ptr %__handle, align 4
// CHECK-SPIRV-NEXT: store target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) poison, ptr %__handle, align 8
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
index 1a05897b9e70b..8264649bbaa8d 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-multi-dim.hlsl
@@ -24,22 +24,22 @@ void main() {
// CHECK: %[[Tmp3:.*]] = alloca %"class.hlsl::RWBuffer
// Make sure that B[3][2] is translated to a RWBuffer<float>::__createFromBinding call (u2, space0) with range 16 and index 14
- // CHECK: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Tmp0]],
// CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]])
// Make sure that C[1][0][3] is translated to a RWBuffer<int>::__createFromBinding call (u10, space1) with range 20 and index 13
- // CHECK: call void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align {{(4|8)}} %[[Tmp1]],
// CHECK-SAME: i32 noundef 10, i32 noundef 1, i32 noundef 20, i32 noundef 13, ptr noundef @[[BufC]])
// Make sure that D[9][2] is translated to a RWBuffer<uint>::__createFromImplicitBinding call with range 50 and index 47
- // CHECK: call void @hlsl::RWBuffer<unsigned int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<unsigned int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align {{(4|8)}} %[[Tmp2]],
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 50, i32 noundef 47, ptr noundef @[[BufD]])
// Make sure that the second B[3][2] is translated to the same RWBuffer<float>::__createFromBinding call as the first B[3][2] subscript
- // CHECK: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK: call {{(spir_func )?}}void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} writable sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Tmp3]],
// CHECK-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 16, i32 noundef 14, ptr noundef @[[BufB]])
Out[0] = B[3][2][0] + (float)C[1][0][3][0] + (float)D[9][2][0] + B[3][2][1];
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl
index b123e31a2bbe1..5e0e086492815 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global-unbounded.hlsl
@@ -43,22 +43,22 @@ void main(uint GI : SV_GroupIndex) {
// as 2 * 5 * 4 + 3 * 4 = 52 and the following indices are sequential.
// CHECK-NEXT: %[[Ptr_Tmp2_0:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 0
- // CHECK-NEXT: call void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_0]],
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 0, i32 noundef 52, ptr noundef @[[BufB]])
// CHECK-NEXT: %[[Ptr_Tmp2_1:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 1
- // CHECK-NEXT: call void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_1]],
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 0, i32 noundef 53, ptr noundef @[[BufB]])
// CHECK-NEXT: %[[Ptr_Tmp2_2:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 2
- // CHECK-NEXT: call void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_2]],
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 0, i32 noundef 54, ptr noundef @[[BufB]])
// CHECK-NEXT: %[[Ptr_Tmp2_3:.*]] = getelementptr [4 x %"class.hlsl::RWBuffer"], ptr %[[Tmp2]], i32 0, i32 3
- // CHECK-NEXT: call void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // CHECK-NEXT: call {{(spir_func )?}}void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align {{(4|8)}} %[[Ptr_Tmp2_3]],
// CHECK-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 0, i32 noundef 55, ptr noundef @[[BufB]])
diff --git a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
index f728c6b627b68..bc1f7f06ce652 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-global.hlsl
@@ -43,7 +43,7 @@ void main() {
// DXIL: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 4 %[[Tmp0]],
// DXIL-SAME: i32 noundef 10, i32 noundef 1, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
- // SPV: call void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // SPV: call spir_func void @hlsl::RWBuffer<float>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer") align 8 %[[Tmp0]],
// SPV-SAME: i32 noundef 12, i32 noundef 2, i32 noundef 4, i32 noundef 2, ptr noundef @[[BufA]])
@@ -53,7 +53,7 @@ void main() {
// DXIL: call void @hlsl::RWBuffer<int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 4 %[[Tmp1]],
// DXIL-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]])
- // SPV: call void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // SPV: call spir_func void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 8 %[[Tmp1]],
// SPV-SAME: i32 noundef 13, i32 noundef 0, i32 noundef 5, i32 noundef 3, ptr noundef @[[BufB]])
@@ -63,7 +63,7 @@ void main() {
// DXIL: call void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 4 %[[Tmp2]],
// DXIL-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
- // SPV: call void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // SPV: call spir_func void @hlsl::RWBuffer<int>::__createFromBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.0") align 8 %[[Tmp2]],
// SPV-SAME: i32 noundef 2, i32 noundef 0, i32 noundef 3, i32 noundef 1, ptr noundef @[[BufC]])
@@ -72,7 +72,7 @@ void main() {
// DXIL: call void @hlsl::RWBuffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align 4 %[[Tmp3]],
// DXIL-SAME: i32 noundef 1, i32 noundef 0, i32 noundef 10, i32 noundef 7, ptr noundef @D.str)
- // SPV: call void @hlsl::RWBuffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // SPV: call spir_func void @hlsl::RWBuffer<double>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.1") align 8 %[[Tmp3]],
// SPV-SAME: i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef 7, ptr noundef @[[BufD]])
@@ -81,7 +81,7 @@ void main() {
// DXIL: call void @hlsl::RWBuffer<unsigned int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// DXIL-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.2") align 4 %[[Tmp4]],
// DXIL-SAME: i32 noundef 2, i32 noundef 2, i32 noundef 15, i32 noundef 5, ptr noundef @[[BufE]])
- // SPV: call void @hlsl::RWBuffer<unsigned int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
+ // SPV: call spir_func void @hlsl::RWBuffer<unsigned int>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// SPV-SAME: (ptr {{.*}} sret(%"class.hlsl::RWBuffer.2") align 8 %[[Tmp4]],
// SPV-SAME: i32 noundef 1, i32 noundef 2, i32 noundef 15, i32 noundef 5, ptr noundef @[[BufE]])
Out[0] = A[2][0] + (float)B[3][0] + (float)C[1][0] + (float)D[7][0] + (float)E[5][0];
diff --git a/clang/test/CodeGenHLSL/resources/res-array-rw-counter.hlsl b/clang/test/CodeGenHLSL/resources/res-array-rw-counter.hlsl
index c3d5784184fca..783e5383c60a5 100644
--- a/clang/test/CodeGenHLSL/resources/res-array-rw-counter.hlsl
+++ b/clang/test/CodeGenHLSL/resources/res-array-rw-counter.hlsl
@@ -19,8 +19,8 @@ export void foo(int idx) {
// CHECK: [[TMP_INC:%.*]] = alloca %"class.hlsl::RWStructuredBuffer"
// CHECK: [[TMP_DEC:%.*]] = alloca %"class.hlsl::RWStructuredBuffer"
// CHECK: store i32 %[[IDX_ARG]], ptr %[[IDX_ADDR]]
-// CHECK: call void @_ZN4hlsl18RWStructuredBufferIfE46__createFromImplicitBindingWithImplicitCounterEjjijPKcj(ptr {{.*}} [[TMP_INC]], i32 noundef 0, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef @[[BufArrayStr]], i32 noundef 1)
-// CHECK: call noundef i32 @_ZN4hlsl18RWStructuredBufferIfE16IncrementCounterEv(ptr {{.*}} [[TMP_INC]])
+// CHECK: call {{(spir_func )?}}void @_ZN4hlsl18RWStructuredBufferIfE46__createFromImplicitBindingWithImplicitCounterEjjijPKcj(ptr {{.*}} [[TMP_INC]], i32 noundef 0, i32 noundef 0, i32 noundef 4, i32 noundef 0, ptr noundef @[[BufArrayStr]], i32 noundef 1)
+// CHECK: call {{(spir_func )?}}noundef i32 @_ZN4hlsl18RWStructuredBufferIfE16IncrementCounterEv(ptr {{.*}} [[TMP_INC]])
// CHECK: %[[IDX_LOADED:.*]] = load i32, ptr %[[IDX_ADDR]]
-// CHECK: call void @_ZN4hlsl18RWStructuredBufferIfE46__createFromImplicitBindingWithImplicitCounterEjjijPKcj(ptr {{.*}} [[TMP_DEC]], i32 noundef 0, i32 noundef 0, i32 noundef 4, i32 noundef %[[IDX_LOADED]], ptr noundef @[[BufArrayStr]], i32 noundef 1)
-// CHECK: call noundef i32 @_ZN4hlsl18RWStructuredBufferIfE16DecrementCounterEv(ptr {{.*}} [[TMP_DEC]])
\ No newline at end of file
+// CHECK: call {{(spir_func )?}}void @_ZN4hlsl18RWStructuredBufferIfE46__createFromImplicitBindingWithImplicitCounterEjjijPKcj(ptr {{.*}} [[TMP_DEC]], i32 noundef 0, i32 noundef 0, i32 noundef 4, i32 noundef %[[IDX_LOADED]], ptr noundef @[[BufArrayStr]], i32 noundef 1)
+// CHECK: call {{(spir_func )?}}noundef i32 @_ZN4hlsl18RWStructuredBufferIfE16DecrementCounterEv(ptr {{.*}} [[TMP_DEC]])
\ No newline at end of file
diff --git a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
index a624edc1bf564..704ffef4d5384 100644
--- a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
+++ b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
@@ -6,8 +6,6 @@
// so std::function<void()> matches the library specialization keyed on
// __cdecl on amdgcnspirv Windows.
-// expected-no-diagnostics
-
template <class T> struct classify_fn {
static constexpr int value = 0;
};
@@ -17,19 +15,16 @@ template <class R, class... A> struct classify_fn<R __cdecl(A...)> {
template <class R, class... A> struct classify_fn<R __vectorcall(A...)> {
static constexpr int value = 2;
};
-template <class R> struct classify_fn<R __cdecl(int, ...)> {
- static constexpr int value = 3;
-};
// Unadorned function types resolve to the __cdecl specialization.
static_assert(classify_fn<void()>::value == 1, "void() must match __cdecl");
static_assert(classify_fn<int(double, char)>::value == 1,
"int(double,char) must match __cdecl");
-// Variadic __cdecl keeps its own specialization, not the device default.
-static_assert(classify_fn<int __cdecl(int, ...)>::value == 3,
- "variadic __cdecl must match its own specialization");
-
// __vectorcall must not be folded into the device default alongside __cdecl.
static_assert(classify_fn<void __vectorcall()>::value == 2,
"__vectorcall must match its own specialization, not __cdecl");
+
+// Variadic __cdecl has no device-side equivalent, since the device default
+// calling convention cannot support variadic calls.
+using VariadicCdecl = int __cdecl(int, ...); // expected-error {{variadic function cannot use cdecl calling convention}}
diff --git a/clang/test/SemaSYCL/sycl-cconv.cpp b/clang/test/SemaSYCL/sycl-cconv.cpp
index 664a4dbf37c49..3ce5dd040f77f 100644
--- a/clang/test/SemaSYCL/sycl-cconv.cpp
+++ b/clang/test/SemaSYCL/sycl-cconv.cpp
@@ -1,11 +1,12 @@
// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fsyntax-only -verify %s
// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -fsyntax-only -verify=expected,no-aux %s
-// Check that there is no error/warning emitted for cdecl functions compiled for
-// SYCL device. Make sure variadic calls from within device code are diagnosed.
+// Check that there is no error/warning emitted for non-variadic cdecl functions
+// compiled for SYCL device. Make sure variadic cdecl functions and variadic
+// calls from within device code are diagnosed.
// no-aux-warning at +2 {{'__cdecl' calling convention is not supported for this target}}
-// no-aux-error at +1 {{variadic function cannot use spir_function calling convention}}
+// expected-error at +1 {{variadic function cannot use cdecl calling convention}}
__inline __cdecl int printf(char const* const _Format, ...) { return 0; }
// FIXME: that should be diagnosed.
>From a860c89794608ce14b1bf189ee1c8c0da03b6330 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 5 Aug 2026 09:59:10 +0200
Subject: [PATCH 3/6] ci fix
---
clang/lib/CodeGen/CGCall.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index b53cdcb1cbf05..4368ae4f51b48 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -59,8 +59,6 @@ using namespace CodeGen;
unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
switch (CC) {
- default:
- return llvm::CallingConv::C;
case CC_C:
// On SPIR/SPIR-V, CC_C is the AST-level default calling convention, but
// it still needs to lower to spir_func so IR consumers can rely on the
>From 68f4c32f48764feb1cc4789714287513b68ad1f9 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 7 Aug 2026 13:52:47 +0200
Subject: [PATCH 4/6] empty line
---
clang/lib/Sema/SemaType.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index b6094e62d014a..a45d102128e4c 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8350,7 +8350,6 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
const FunctionType *fn = unwrapped.get();
-
CallingConv CCOld = fn->getCallConv();
Attr *CCAttr = getCCTypeAttr(S.Context, attr);
>From 1d75ffe9b678c93235c89e24d0ef9ce5710c1911 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 10 Aug 2026 06:29:57 +0200
Subject: [PATCH 5/6] Address remarks
---
clang/include/clang/Basic/TargetInfo.h | 9 -------
clang/lib/Basic/Targets/SPIR.h | 15 +++---------
clang/lib/CodeGen/CGDebugInfo.cpp | 24 ++++++++++++-------
clang/lib/Sema/SemaDecl.cpp | 2 +-
clang/lib/Sema/SemaType.cpp | 5 ++--
...mdgcnspirv-host-cconv-in-abstract-type.hip | 17 ++++++-------
clang/test/SemaSYCL/sycl-cconv.cpp | 9 ++-----
7 files changed, 33 insertions(+), 48 deletions(-)
diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 9e89179ddfe18..3aba4d261a651 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1787,15 +1787,6 @@ class TargetInfo : public TransferrableTargetInfo,
}
}
- /// Determines whether a call using the given calling convention may be
- /// variadic on this target. Unlike the target-agnostic
- /// supportsVariadicCall(), this allows a target to reject its own default
- /// calling convention (e.g. when that default is only nominally CC_C but
- /// lowers to an ABI that cannot support variadic calls).
- virtual bool supportsCallingConvVariadic(CallingConv CC) const {
- return supportsVariadicCall(CC);
- }
-
enum CallingConvKind {
CCK_Default,
CCK_ClangABI4OrPS4,
diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h
index 46eaf5f2131e2..fd7dfef118fb9 100644
--- a/clang/lib/Basic/Targets/SPIR.h
+++ b/clang/lib/Basic/Targets/SPIR.h
@@ -196,18 +196,9 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo {
}
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
- return (CC == CC_SpirFunction || CC == CC_DeviceKernel) ? CCCR_OK
- : CCCR_Warning;
- }
-
- CallingConv getDefaultCallingConv() const override { return CC_C; }
-
- bool supportsCallingConvVariadic(CallingConv CC) const override {
- // CC_C is the AST-level default calling convention on this target, but it
- // still lowers to spir_func, which cannot support variadic calls.
- if (CC == CC_C)
- return false;
- return TargetInfo::supportsCallingConvVariadic(CC);
+ return (CC == CC_C || CC == CC_SpirFunction || CC == CC_DeviceKernel)
+ ? CCCR_OK
+ : CCCR_Warning;
}
void setAddressSpaceMap(bool DefaultIsGeneric) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 084cfdb85c6b7..db07ac1c02aee 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -1789,9 +1789,13 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty,
Flags, Annotations);
}
-static unsigned getDwarfCC(CallingConv CC) {
+static unsigned getDwarfCC(CallingConv CC, const llvm::Triple &T) {
switch (CC) {
case CC_C:
+ // On SPIR/SPIR-V, CC_C is the target default calling convention and lowers
+ // to spir_func, so describe it that way.
+ if (T.isSPIROrSPIRV())
+ return llvm::dwarf::DW_CC_LLVM_SpirFunction;
// Avoid emitting DW_AT_calling_convention if the C convention was used.
return 0;
@@ -1895,7 +1899,8 @@ llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty,
llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
llvm::DIType *F = DBuilder.createSubroutineType(
- EltTypeArray, Flags, getDwarfCC(Ty->getCallConv()));
+ EltTypeArray, Flags,
+ getDwarfCC(Ty->getCallConv(), CGM.getTarget().getTriple()));
return F;
}
@@ -2380,8 +2385,9 @@ CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr,
llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
- return DBuilder.createSubroutineType(EltTypeArray, OriginalFunc->getFlags(),
- getDwarfCC(Func->getCallConv()));
+ return DBuilder.createSubroutineType(
+ EltTypeArray, OriginalFunc->getFlags(),
+ getDwarfCC(Func->getCallConv(), CGM.getTarget().getTriple()));
}
/// isFunctionLocalClass - Return true if CXXRecordDecl is defined
@@ -4896,8 +4902,9 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
Elts.push_back(DBuilder.createUnspecifiedParameter());
llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts);
- return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
- getDwarfCC(CC));
+ return DBuilder.createSubroutineType(
+ EltTypeArray, llvm::DINode::FlagZero,
+ getDwarfCC(CC, CGM.getTarget().getTriple()));
}
// Handle variadic function types; they need an additional
@@ -4911,8 +4918,9 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
EltTys.push_back(getOrCreateType(ParamType, F));
EltTys.push_back(DBuilder.createUnspecifiedParameter());
llvm::DITypeArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys);
- return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero,
- getDwarfCC(CC));
+ return DBuilder.createSubroutineType(
+ EltTypeArray, llvm::DINode::FlagZero,
+ getDwarfCC(CC, CGM.getTarget().getTriple()));
}
return cast<llvm::DISubroutineType>(getOrCreateType(FnType, F));
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index d43e340641b2f..7de5542e72559 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10782,7 +10782,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
const FunctionType *FT = NewFD->getType()->castAs<FunctionType>();
if (isa<FunctionNoProtoType>(FT) && !D.isFunctionDefinition()) {
CallingConv CC = FT->getExtInfo().getCC();
- if (!Context.getTargetInfo().supportsCallingConvVariadic(CC)) {
+ if (!supportsVariadicCall(CC)) {
// Windows system headers sometimes accidentally use stdcall without
// (void) parameters, so we relax this to a warning.
int DiagID =
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index a45d102128e4c..f7789b7475e8e 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3772,8 +3772,7 @@ static CallingConv getCCForDeclaratorChunk(
CallingConv CC;
if (!S.CheckCallingConvAttr(AL, CC, /*FunctionDecl=*/nullptr,
S.CUDA().IdentifyTarget(D.getAttributes())) &&
- (!FTI.isVariadic ||
- S.Context.getTargetInfo().supportsCallingConvVariadic(CC))) {
+ (!FTI.isVariadic || supportsVariadicCall(CC))) {
return CC;
}
break;
@@ -8373,7 +8372,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// prototype that way. And apparently we also "delay" warning about
// unprototyped function types in general, despite not necessarily having
// much ability to diagnose it later.
- if (!S.Context.getTargetInfo().supportsCallingConvVariadic(CC)) {
+ if (!supportsVariadicCall(CC)) {
const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
if (FnP && FnP->isVariadic()) {
// stdcall and fastcall are ignored with a warning for GCC and MS
diff --git a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
index 704ffef4d5384..de0f245a65b62 100644
--- a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
+++ b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
@@ -2,9 +2,10 @@
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
// RUN: %clang_cc1 %s -fcuda-is-device -std=c++17 -triple spirv64-amd-amdhsa -aux-triple x86_64-pc-windows-msvc -fms-extensions -verify
-// __cdecl on an abstract function type must normalize to the device default
-// so std::function<void()> matches the library specialization keyed on
-// __cdecl on amdgcnspirv Windows.
+// expected-no-diagnostics
+
+// __cdecl must be the device default calling convention so std::function<void()>
+// matches the library specialization keyed on __cdecl on amdgcnspirv Windows.
template <class T> struct classify_fn {
static constexpr int value = 0;
@@ -17,14 +18,14 @@ template <class R, class... A> struct classify_fn<R __vectorcall(A...)> {
};
// Unadorned function types resolve to the __cdecl specialization.
+static_assert(classify_fn<void()>::value == classify_fn<void __cdecl()>::value,
+ "The default and __cdecl calling conventions must match");
static_assert(classify_fn<void()>::value == 1, "void() must match __cdecl");
-static_assert(classify_fn<int(double, char)>::value == 1,
- "int(double,char) must match __cdecl");
// __vectorcall must not be folded into the device default alongside __cdecl.
static_assert(classify_fn<void __vectorcall()>::value == 2,
"__vectorcall must match its own specialization, not __cdecl");
-// Variadic __cdecl has no device-side equivalent, since the device default
-// calling convention cannot support variadic calls.
-using VariadicCdecl = int __cdecl(int, ...); // expected-error {{variadic function cannot use cdecl calling convention}}
+// Variadic __cdecl is accepted, as it is on the host, so that prevalent Windows
+// headers remain includable during device compilation.
+using VariadicCdecl = int __cdecl(int, ...);
diff --git a/clang/test/SemaSYCL/sycl-cconv.cpp b/clang/test/SemaSYCL/sycl-cconv.cpp
index 3ce5dd040f77f..1b250676cf478 100644
--- a/clang/test/SemaSYCL/sycl-cconv.cpp
+++ b/clang/test/SemaSYCL/sycl-cconv.cpp
@@ -1,18 +1,14 @@
// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -aux-triple x86_64-pc-windows-msvc -fsyntax-only -verify %s
// RUN: %clang_cc1 -isystem %S/Inputs/ -fsycl-is-device -triple spirv64 -fsyntax-only -verify=expected,no-aux %s
-// Check that there is no error/warning emitted for non-variadic cdecl functions
-// compiled for SYCL device. Make sure variadic cdecl functions and variadic
-// calls from within device code are diagnosed.
+// Check that there is no error/warning emitted for cdecl functions compiled for
+// SYCL device. Make sure variadic calls from within device code are diagnosed.
-// no-aux-warning at +2 {{'__cdecl' calling convention is not supported for this target}}
-// expected-error at +1 {{variadic function cannot use cdecl calling convention}}
__inline __cdecl int printf(char const* const _Format, ...) { return 0; }
// FIXME: that should be diagnosed.
[[clang::sycl_external]] int foo(int, ...) { return 0; }
-// no-aux-warning at +1 {{'__cdecl' calling convention is not supported for this target}}
__inline __cdecl int moo() { return 0; }
void bar() {
@@ -28,7 +24,6 @@ void sycl_kernel_launch(Args ...args) {}
template<typename KN, typename K>
[[clang::sycl_kernel_entry_point(KN)]]
-// no-aux-warning at +1 {{'__cdecl' calling convention is not supported for this target}}
__cdecl void sycl_entry_point(K k) {
k(); // expected-note {{called by}}
}
>From 9b8e8616fe70b5f42009e09680aadd0823a3116b Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Wed, 12 Aug 2026 06:57:48 +0200
Subject: [PATCH 6/6] Add test
---
.../SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
index de0f245a65b62..f6b4ed3d6c33e 100644
--- a/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
+++ b/clang/test/SemaHIP/amdgcnspirv-host-cconv-in-abstract-type.hip
@@ -29,3 +29,10 @@ static_assert(classify_fn<void __vectorcall()>::value == 2,
// Variadic __cdecl is accepted, as it is on the host, so that prevalent Windows
// headers remain includable during device compilation.
using VariadicCdecl = int __cdecl(int, ...);
+
+struct ThiscallBase {
+ virtual void __attribute__((thiscall)) boo();
+};
+struct ThiscallDerived : ThiscallBase {
+ void boo() override;
+};
More information about the cfe-commits
mailing list