Skip to content

Commit 3142e3a

Browse files
[HLSL] Implement ddx and ddy HLSL intrinsics (#168887)
Implements the ddx and ddy HLSL intrinsics. The DXIL intrinsics call the ddx_coarse and ddy_builtins as they lower to the coarse variants. The SPIRV intrinsics lower to their own opcodes OpDPdx and OpDPdy. Tests are added to ensure the SPIRV builtins are not available outside of shaders stage. Closes #99096 Closes #99099
1 parent 4385737 commit 3142e3a

File tree

17 files changed

+534
-0
lines changed

17 files changed

+534
-0
lines changed

clang/include/clang/Basic/BuiltinsSPIRVVK.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ include "clang/Basic/BuiltinsSPIRVBase.td"
1212
def reflect : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
1313
def faceforward : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
1414
def refract : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
15+
def ddx : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
16+
def ddy : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
1517
def fwidth : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;

clang/lib/CodeGen/TargetBuiltins/SPIR.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
151151
Intrinsic::spv_global_offset,
152152
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr,
153153
"spv.global.offset");
154+
case SPIRV::BI__builtin_spirv_ddx:
155+
return Builder.CreateIntrinsic(
156+
/*ReturnType=*/getTypes().ConvertType(E->getType()), Intrinsic::spv_ddx,
157+
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr, "spv.ddx");
158+
case SPIRV::BI__builtin_spirv_ddy:
159+
return Builder.CreateIntrinsic(
160+
/*ReturnType=*/getTypes().ConvertType(E->getType()), Intrinsic::spv_ddy,
161+
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr, "spv.ddy");
154162
case SPIRV::BI__builtin_spirv_fwidth:
155163
return Builder.CreateIntrinsic(
156164
/*ReturnType=*/getTypes().ConvertType(E->getType()),

clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,22 @@ constexpr K firstbithigh_impl(T X) {
156156
return FBH;
157157
}
158158

159+
template <typename T> constexpr T ddx_impl(T input) {
160+
#if (__has_builtin(__builtin_spirv_ddx))
161+
return __builtin_spirv_ddx(input);
162+
#else
163+
return __builtin_hlsl_elementwise_ddx_coarse(input);
164+
#endif
165+
}
166+
167+
template <typename T> constexpr T ddy_impl(T input) {
168+
#if (__has_builtin(__builtin_spirv_ddy))
169+
return __builtin_spirv_ddy(input);
170+
#else
171+
return __builtin_hlsl_elementwise_ddy_coarse(input);
172+
#endif
173+
}
174+
159175
template <typename T> constexpr T fwidth_impl(T input) {
160176
#if (__has_builtin(__builtin_spirv_fwidth))
161177
return __builtin_spirv_fwidth(input);

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,86 @@ inline bool CheckAccessFullyMapped(uint Status) {
670670
return static_cast<bool>(Status);
671671
}
672672

673+
//===----------------------------------------------------------------------===//
674+
// ddx builtin
675+
//===----------------------------------------------------------------------===//
676+
677+
/// \fn T ddx(T x)
678+
/// \brief Computes the sum of the absolute values of the partial derivatives
679+
/// with regard to the x screen space coordinate.
680+
/// \param x [in] The floating-point scalar or vector to process.
681+
///
682+
/// The return value is a floating-point scalar or vector where each element
683+
/// holds the computation of the matching element in the input.
684+
685+
template <typename T>
686+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
687+
const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
688+
__detail::is_same<half, T>::value,
689+
T> ddx(T input) {
690+
return __detail::ddx_impl(input);
691+
}
692+
693+
template <typename T>
694+
const inline __detail::enable_if_t<
695+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
696+
ddx(T input) {
697+
return __detail::ddx_impl(input);
698+
}
699+
700+
template <int N>
701+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
702+
const inline __detail::HLSL_FIXED_VECTOR<half, N> ddx(
703+
__detail::HLSL_FIXED_VECTOR<half, N> input) {
704+
return __detail::ddx_impl(input);
705+
}
706+
707+
template <int N>
708+
const inline __detail::HLSL_FIXED_VECTOR<float, N>
709+
ddx(__detail::HLSL_FIXED_VECTOR<float, N> input) {
710+
return __detail::ddx_impl(input);
711+
}
712+
713+
//===----------------------------------------------------------------------===//
714+
// ddy builtin
715+
//===----------------------------------------------------------------------===//
716+
717+
/// \fn T ddy(T x)
718+
/// \brief Computes the sum of the absolute values of the partial derivatives
719+
/// with regard to the y screen space coordinate.
720+
/// \param x [in] The floating-point scalar or vector to process.
721+
///
722+
/// The return value is a floating-point scalar or vector where each element
723+
/// holds the computation of the matching element in the input.
724+
725+
template <typename T>
726+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
727+
const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
728+
__detail::is_same<half, T>::value,
729+
T> ddy(T input) {
730+
return __detail::ddy_impl(input);
731+
}
732+
733+
template <typename T>
734+
const inline __detail::enable_if_t<
735+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
736+
ddy(T input) {
737+
return __detail::ddy_impl(input);
738+
}
739+
740+
template <int N>
741+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
742+
const inline __detail::HLSL_FIXED_VECTOR<half, N> ddy(
743+
__detail::HLSL_FIXED_VECTOR<half, N> input) {
744+
return __detail::ddy_impl(input);
745+
}
746+
747+
template <int N>
748+
const inline __detail::HLSL_FIXED_VECTOR<float, N>
749+
ddy(__detail::HLSL_FIXED_VECTOR<float, N> input) {
750+
return __detail::ddy_impl(input);
751+
}
752+
673753
//===----------------------------------------------------------------------===//
674754
// fwidth builtin
675755
//===----------------------------------------------------------------------===//

clang/lib/Sema/SemaSPIRV.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
360360
case SPIRV::BI__builtin_spirv_generic_cast_to_ptr_explicit: {
361361
return checkGenericCastToPtr(SemaRef, TheCall);
362362
}
363+
case SPIRV::BI__builtin_spirv_ddx:
364+
case SPIRV::BI__builtin_spirv_ddy:
363365
case SPIRV::BI__builtin_spirv_fwidth: {
364366
if (SemaRef.checkArgCount(TheCall, 1))
365367
return true;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \
2+
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
3+
// RUN: FileCheck %s --check-prefixes=CHECK
4+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-pixel %s \
5+
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
6+
// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV
7+
8+
// CHECK-LABEL: define {{.*}} half @_ZN4hlsl8__detail8ddx_implIDhEET_S2_
9+
// CHECK: %hlsl.ddx.coarse = call {{.*}} half @llvm.dx.ddx.coarse.f16(half %{{.*}})
10+
// CHECK: ret half %hlsl.ddx.coarse
11+
// CHECK-LABEL-SPIRV: half @_ZN4hlsl8__detail8ddx_implIDhEET_S2_
12+
// CHECK-SPIRV: %spv.ddx = call {{.*}} half @llvm.spv.ddx.f16(half %{{.*}})
13+
// CHECK-SPIRV: ret half %spv.ddx
14+
half test_f16_ddx(half val) {
15+
return ddx(val);
16+
}
17+
18+
// CHECK-LABEL: define {{.*}} <2 x half> @_ZN4hlsl8__detail8ddx_implIDv2_DhEET_S3_
19+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x half> @llvm.dx.ddx.coarse.v2f16(<2 x half> %{{.*}})
20+
// CHECK: ret <2 x half> %hlsl.ddx.coarse
21+
// CHECK-LABEL-SPIRV: <2 x half> @_ZN4hlsl8__detail8ddx_implIDv2_DhEET_S3_
22+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <2 x half> @llvm.spv.ddx.v2f16(<2 x half> %{{.*}})
23+
// CHECK-SPIRV: ret <2 x half> %spv.ddx
24+
half2 test_f16_ddx2(half2 val) {
25+
return ddx(val);
26+
}
27+
28+
// CHECK-LABEL: define {{.*}} <3 x half> @_ZN4hlsl8__detail8ddx_implIDv3_DhEET_S3_
29+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x half> @llvm.dx.ddx.coarse.v3f16(<3 x half> %{{.*}})
30+
// CHECK: ret <3 x half> %hlsl.ddx.coarse
31+
// CHECK-LABEL-SPIRV: <3 x half> @_ZN4hlsl8__detail8ddx_implIDv3_DhEET_S3_
32+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <3 x half> @llvm.spv.ddx.v3f16(<3 x half> %{{.*}})
33+
// CHECK-SPIRV: ret <3 x half> %spv.ddx
34+
half3 test_f16_ddx3(half3 val) {
35+
return ddx(val);
36+
}
37+
38+
// CHECK-LABEL: define {{.*}} <4 x half> @_ZN4hlsl8__detail8ddx_implIDv4_DhEET_S3_
39+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x half> @llvm.dx.ddx.coarse.v4f16(<4 x half> %{{.*}})
40+
// CHECK: ret <4 x half> %hlsl.ddx.coarse
41+
// CHECK-LABEL-SPIRV: <4 x half> @_ZN4hlsl8__detail8ddx_implIDv4_DhEET_S3_
42+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <4 x half> @llvm.spv.ddx.v4f16(<4 x half> %{{.*}})
43+
// CHECK-SPIRV: ret <4 x half> %spv.ddx
44+
half4 test_f16_ddx4(half4 val) {
45+
return ddx(val);
46+
}
47+
48+
// CHECK-LABEL: define {{.*}} float @_ZN4hlsl8__detail8ddx_implIfEET_S2_
49+
// CHECK: %hlsl.ddx.coarse = call {{.*}} float @llvm.dx.ddx.coarse.f32(float %{{.*}})
50+
// CHECK: ret float %hlsl.ddx.coarse
51+
// CHECK-LABEL-SPIRV: float @_ZN4hlsl8__detail8ddx_implIfEET_S2_
52+
// CHECK-SPIRV: %spv.ddx = call {{.*}} float @llvm.spv.ddx.f32(float %{{.*}})
53+
// CHECK-SPIRV: ret float %spv.ddx
54+
float test_f32_ddx(float val) {
55+
return ddx(val);
56+
}
57+
58+
// CHECK-LABEL: define {{.*}} <2 x float> @_ZN4hlsl8__detail8ddx_implIDv2_fEET_S3_
59+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x float> @llvm.dx.ddx.coarse.v2f32(<2 x float> %{{.*}})
60+
// CHECK: ret <2 x float> %hlsl.ddx.coarse
61+
// CHECK-LABEL-SPIRV: <2 x float> @_ZN4hlsl8__detail8ddx_implIDv2_fEET_S3_
62+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <2 x float> @llvm.spv.ddx.v2f32(<2 x float> %{{.*}})
63+
// CHECK-SPIRV: ret <2 x float> %spv.ddx
64+
float2 test_f32_ddx2(float2 val) {
65+
return ddx(val);
66+
}
67+
68+
// CHECK-LABEL: define {{.*}} <3 x float> @_ZN4hlsl8__detail8ddx_implIDv3_fEET_S3_
69+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x float> @llvm.dx.ddx.coarse.v3f32(<3 x float> %{{.*}})
70+
// CHECK: ret <3 x float> %hlsl.ddx.coarse
71+
// CHECK-LABEL-SPIRV: <3 x float> @_ZN4hlsl8__detail8ddx_implIDv3_fEET_S3_
72+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <3 x float> @llvm.spv.ddx.v3f32(<3 x float> %{{.*}})
73+
// CHECK-SPIRV: ret <3 x float> %spv.ddx
74+
float3 test_f32_ddx3(float3 val) {
75+
return ddx(val);
76+
}
77+
78+
// CHECK-LABEL: define {{.*}} <4 x float> @_ZN4hlsl8__detail8ddx_implIDv4_fEET_S3_
79+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x float> @llvm.dx.ddx.coarse.v4f32(<4 x float> %{{.*}})
80+
// CHECK: ret <4 x float> %hlsl.ddx.coarse
81+
// CHECK-LABEL-SPIRV: <4 x float> @_ZN4hlsl8__detail8ddx_implIDv4_fEET_S3_
82+
// CHECK-SPIRV: %spv.ddx = call {{.*}} <4 x float> @llvm.spv.ddx.v4f32(<4 x float> %{{.*}})
83+
// CHECK-SPIRV: ret <4 x float> %spv.ddx
84+
float4 test_f32_ddx4(float4 val) {
85+
return ddx(val);
86+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \
2+
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
3+
// RUN: FileCheck %s --check-prefixes=CHECK
4+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-pixel %s \
5+
// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \
6+
// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV
7+
8+
// CHECK-LABEL: define {{.*}} half @_ZN4hlsl8__detail8ddy_implIDhEET_S2_
9+
// CHECK: %hlsl.ddy.coarse = call {{.*}} half @llvm.dx.ddy.coarse.f16(half %{{.*}})
10+
// CHECK: ret half %hlsl.ddy.coarse
11+
// CHECK-LABEL-SPIRV: half @_ZN4hlsl8__detail8ddy_implIDhEET_S2_
12+
// CHECK-SPIRV: %spv.ddy = call {{.*}} half @llvm.spv.ddy.f16(half %{{.*}})
13+
// CHECK-SPIRV: ret half %spv.ddy
14+
half test_f16_ddy(half val) {
15+
return ddy(val);
16+
}
17+
18+
// CHECK-LABEL: define {{.*}} <2 x half> @_ZN4hlsl8__detail8ddy_implIDv2_DhEET_S3_
19+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x half> @llvm.dx.ddy.coarse.v2f16(<2 x half> %{{.*}})
20+
// CHECK: ret <2 x half> %hlsl.ddy.coarse
21+
// CHECK-LABEL-SPIRV: <2 x half> @_ZN4hlsl8__detail8ddy_implIDv2_DhEET_S3_
22+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <2 x half> @llvm.spv.ddy.v2f16(<2 x half> %{{.*}})
23+
// CHECK-SPIRV: ret <2 x half> %spv.ddy
24+
half2 test_f16_ddy2(half2 val) {
25+
return ddy(val);
26+
}
27+
28+
// CHECK-LABEL: define {{.*}} <3 x half> @_ZN4hlsl8__detail8ddy_implIDv3_DhEET_S3_
29+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x half> @llvm.dx.ddy.coarse.v3f16(<3 x half> %{{.*}})
30+
// CHECK: ret <3 x half> %hlsl.ddy.coarse
31+
// CHECK-LABEL-SPIRV: <3 x half> @_ZN4hlsl8__detail8ddy_implIDv3_DhEET_S3_
32+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <3 x half> @llvm.spv.ddy.v3f16(<3 x half> %{{.*}})
33+
// CHECK-SPIRV: ret <3 x half> %spv.ddy
34+
half3 test_f16_ddy3(half3 val) {
35+
return ddy(val);
36+
}
37+
38+
// CHECK-LABEL: define {{.*}} <4 x half> @_ZN4hlsl8__detail8ddy_implIDv4_DhEET_S3_
39+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x half> @llvm.dx.ddy.coarse.v4f16(<4 x half> %{{.*}})
40+
// CHECK: ret <4 x half> %hlsl.ddy.coarse
41+
// CHECK-LABEL-SPIRV: <4 x half> @_ZN4hlsl8__detail8ddy_implIDv4_DhEET_S3_
42+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <4 x half> @llvm.spv.ddy.v4f16(<4 x half> %{{.*}})
43+
// CHECK-SPIRV: ret <4 x half> %spv.ddy
44+
half4 test_f16_ddy4(half4 val) {
45+
return ddy(val);
46+
}
47+
48+
// CHECK-LABEL: define {{.*}} float @_ZN4hlsl8__detail8ddy_implIfEET_S2_
49+
// CHECK: %hlsl.ddy.coarse = call {{.*}} float @llvm.dx.ddy.coarse.f32(float %{{.*}})
50+
// CHECK: ret float %hlsl.ddy.coarse
51+
// CHECK-LABEL-SPIRV: float @_ZN4hlsl8__detail8ddy_implIfEET_S2_
52+
// CHECK-SPIRV: %spv.ddy = call {{.*}} float @llvm.spv.ddy.f32(float %{{.*}})
53+
// CHECK-SPIRV: ret float %spv.ddy
54+
float test_f32_ddy(float val) {
55+
return ddy(val);
56+
}
57+
58+
// CHECK-LABEL: define {{.*}} <2 x float> @_ZN4hlsl8__detail8ddy_implIDv2_fEET_S3_
59+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x float> @llvm.dx.ddy.coarse.v2f32(<2 x float> %{{.*}})
60+
// CHECK: ret <2 x float> %hlsl.ddy.coarse
61+
// CHECK-LABEL-SPIRV: <2 x float> @_ZN4hlsl8__detail8ddy_implIDv2_fEET_S3_
62+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <2 x float> @llvm.spv.ddy.v2f32(<2 x float> %{{.*}})
63+
// CHECK-SPIRV: ret <2 x float> %spv.ddy
64+
float2 test_f32_ddy2(float2 val) {
65+
return ddy(val);
66+
}
67+
68+
// CHECK-LABEL: define {{.*}} <3 x float> @_ZN4hlsl8__detail8ddy_implIDv3_fEET_S3_
69+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x float> @llvm.dx.ddy.coarse.v3f32(<3 x float> %{{.*}})
70+
// CHECK: ret <3 x float> %hlsl.ddy.coarse
71+
// CHECK-LABEL-SPIRV: <3 x float> @_ZN4hlsl8__detail8ddy_implIDv3_fEET_S3_
72+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <3 x float> @llvm.spv.ddy.v3f32(<3 x float> %{{.*}})
73+
// CHECK-SPIRV: ret <3 x float> %spv.ddy
74+
float3 test_f32_ddy3(float3 val) {
75+
return ddy(val);
76+
}
77+
78+
// CHECK-LABEL: define {{.*}} <4 x float> @_ZN4hlsl8__detail8ddy_implIDv4_fEET_S3_
79+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x float> @llvm.dx.ddy.coarse.v4f32(<4 x float> %{{.*}})
80+
// CHECK: ret <4 x float> %hlsl.ddy.coarse
81+
// CHECK-LABEL-SPIRV: <4 x float> @_ZN4hlsl8__detail8ddy_implIDv4_fEET_S3_
82+
// CHECK-SPIRV: %spv.ddy = call {{.*}} <4 x float> @llvm.spv.ddy.v4f32(<4 x float> %{{.*}})
83+
// CHECK-SPIRV: ret <4 x float> %spv.ddy
84+
float4 test_f32_ddy4(float4 val) {
85+
return ddy(val);
86+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-pixel %s -emit-llvm -o - | FileCheck %s
2+
3+
typedef _Float16 half;
4+
typedef half half2 __attribute__((ext_vector_type(2)));
5+
typedef half half3 __attribute__((ext_vector_type(3)));
6+
typedef half half4 __attribute__((ext_vector_type(4)));
7+
typedef float float2 __attribute__((ext_vector_type(2)));
8+
typedef float float3 __attribute__((ext_vector_type(3)));
9+
typedef float float4 __attribute__((ext_vector_type(4)));
10+
11+
// CHECK: [[ddx0:%.*]] = tail call half @llvm.spv.ddx.f16(half {{%.*}})
12+
// CHECK: ret half [[ddx0]]
13+
half test_ddx_half(half X) { return __builtin_spirv_ddx(X); }
14+
15+
// CHECK: [[ddx0:%.*]] = tail call <2 x half> @llvm.spv.ddx.v2f16(<2 x half> {{%.*}})
16+
// CHECK: ret <2 x half> [[ddx0]]
17+
half2 test_ddx_half2(half2 X) { return __builtin_spirv_ddx(X); }
18+
19+
// CHECK: [[ddx0:%.*]] = tail call <3 x half> @llvm.spv.ddx.v3f16(<3 x half> {{%.*}})
20+
// CHECK: ret <3 x half> [[ddx0]]
21+
half3 test_ddx_half3(half3 X) { return __builtin_spirv_ddx(X); }
22+
23+
// CHECK: [[ddx0:%.*]] = tail call <4 x half> @llvm.spv.ddx.v4f16(<4 x half> {{%.*}})
24+
// CHECK: ret <4 x half> [[ddx0]]
25+
half4 test_ddx_half4(half4 X) { return __builtin_spirv_ddx(X); }
26+
27+
// CHECK: [[ddx0:%.*]] = tail call float @llvm.spv.ddx.f32(float {{%.*}})
28+
// CHECK: ret float [[ddx0]]
29+
float test_ddx_float(float X) { return __builtin_spirv_ddx(X); }
30+
31+
// CHECK: [[ddx1:%.*]] = tail call <2 x float> @llvm.spv.ddx.v2f32(<2 x float> {{%.*}})
32+
// CHECK: ret <2 x float> [[ddx1]]
33+
float2 test_ddx_float2(float2 X) { return __builtin_spirv_ddx(X); }
34+
35+
// CHECK: [[ddx2:%.*]] = tail call <3 x float> @llvm.spv.ddx.v3f32(<3 x float> {{%.*}})
36+
// CHECK: ret <3 x float> [[ddx2]]
37+
float3 test_ddx_float3(float3 X) { return __builtin_spirv_ddx(X); }
38+
39+
// CHECK: [[ddx3:%.*]] = tail call <4 x float> @llvm.spv.ddx.v4f32(<4 x float> {{%.*}})
40+
// CHECK: ret <4 x float> [[ddx3]]
41+
float4 test_ddx_float4(float4 X) { return __builtin_spirv_ddx(X); }
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-pixel %s -emit-llvm -o - | FileCheck %s
2+
3+
typedef _Float16 half;
4+
typedef half half2 __attribute__((ext_vector_type(2)));
5+
typedef half half3 __attribute__((ext_vector_type(3)));
6+
typedef half half4 __attribute__((ext_vector_type(4)));
7+
typedef float float2 __attribute__((ext_vector_type(2)));
8+
typedef float float3 __attribute__((ext_vector_type(3)));
9+
typedef float float4 __attribute__((ext_vector_type(4)));
10+
11+
// CHECK: [[ddy0:%.*]] = tail call half @llvm.spv.ddy.f16(half {{%.*}})
12+
// CHECK: ret half [[ddy0]]
13+
half test_ddy_half(half X) { return __builtin_spirv_ddy(X); }
14+
15+
// CHECK: [[ddy0:%.*]] = tail call <2 x half> @llvm.spv.ddy.v2f16(<2 x half> {{%.*}})
16+
// CHECK: ret <2 x half> [[ddy0]]
17+
half2 test_ddy_half2(half2 X) { return __builtin_spirv_ddy(X); }
18+
19+
// CHECK: [[ddy0:%.*]] = tail call <3 x half> @llvm.spv.ddy.v3f16(<3 x half> {{%.*}})
20+
// CHECK: ret <3 x half> [[ddy0]]
21+
half3 test_ddy_half3(half3 X) { return __builtin_spirv_ddy(X); }
22+
23+
// CHECK: [[ddy0:%.*]] = tail call <4 x half> @llvm.spv.ddy.v4f16(<4 x half> {{%.*}})
24+
// CHECK: ret <4 x half> [[ddy0]]
25+
half4 test_ddy_half4(half4 X) { return __builtin_spirv_ddy(X); }
26+
27+
// CHECK: [[ddy0:%.*]] = tail call float @llvm.spv.ddy.f32(float {{%.*}})
28+
// CHECK: ret float [[ddy0]]
29+
float test_ddy_float(float X) { return __builtin_spirv_ddy(X); }
30+
31+
// CHECK: [[ddy1:%.*]] = tail call <2 x float> @llvm.spv.ddy.v2f32(<2 x float> {{%.*}})
32+
// CHECK: ret <2 x float> [[ddy1]]
33+
float2 test_ddy_float2(float2 X) { return __builtin_spirv_ddy(X); }
34+
35+
// CHECK: [[ddy2:%.*]] = tail call <3 x float> @llvm.spv.ddy.v3f32(<3 x float> {{%.*}})
36+
// CHECK: ret <3 x float> [[ddy2]]
37+
float3 test_ddy_float3(float3 X) { return __builtin_spirv_ddy(X); }
38+
39+
// CHECK: [[ddy3:%.*]] = tail call <4 x float> @llvm.spv.ddy.v4f32(<4 x float> {{%.*}})
40+
// CHECK: ret <4 x float> [[ddy3]]
41+
float4 test_ddy_float4(float4 X) { return __builtin_spirv_ddy(X); }

0 commit comments

Comments
 (0)