Skip to content

Commit 76f1949

Browse files
[HLSL] Implement the fwidth intrinsic for DXIL and SPIR-V target (#161378)
Adds the fwidth intrinsic for HLSL. The DXIL path only requires modification to the hlsl headers. The SPIRV path implements the OpFwidth builtin in Clang and instruction selection for the OpFwidth instruction in LLVM. Also adds shader stage tests to the ddx_coarse and ddy_coarse instructions used by fwidth. Closes #99120 --------- Co-authored-by: Alexander Johnston <[email protected]>
1 parent 21c4c15 commit 76f1949

File tree

14 files changed

+365
-18
lines changed

14 files changed

+365
-18
lines changed

clang/include/clang/Basic/BuiltinsSPIRVVK.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ 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 fwidth : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;

clang/lib/CodeGen/TargetBuiltins/SPIR.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ 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_fwidth:
155+
return Builder.CreateIntrinsic(
156+
/*ReturnType=*/getTypes().ConvertType(E->getType()),
157+
Intrinsic::spv_fwidth, ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))},
158+
nullptr, "spv.fwidth");
154159
}
155160
return nullptr;
156161
}

clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ constexpr K firstbithigh_impl(T X) {
160160
return FBH;
161161
}
162162

163+
template <typename T> constexpr T fwidth_impl(T input) {
164+
#if (__has_builtin(__builtin_spirv_fwidth))
165+
return __builtin_spirv_fwidth(input);
166+
#else
167+
T derivCoarseX = ddx_coarse(input);
168+
derivCoarseX = abs(derivCoarseX);
169+
T derivCoarseY = ddy_coarse(input);
170+
derivCoarseY = abs(derivCoarseY);
171+
return derivCoarseX + derivCoarseY;
172+
#endif
173+
}
174+
163175
} // namespace __detail
164176
} // namespace hlsl
165177

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,5 +666,45 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
666666
return __detail::smoothstep_vec_impl(Min, Max, X);
667667
}
668668

669+
//===----------------------------------------------------------------------===//
670+
// fwidth builtin
671+
//===----------------------------------------------------------------------===//
672+
673+
/// \fn T fwidth(T x)
674+
/// \brief Computes the sum of the absolute values of the partial derivatives
675+
/// with regard to the x and y screen space coordinates.
676+
/// \param x [in] The floating-point scalar or vector to process.
677+
///
678+
/// The return value is a floating-point scalar or vector where each element
679+
/// holds the computation of the matching element in the input.
680+
681+
template <typename T>
682+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
683+
const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
684+
__detail::is_same<half, T>::value,
685+
T> fwidth(T input) {
686+
return __detail::fwidth_impl(input);
687+
}
688+
689+
template <typename T>
690+
const inline __detail::enable_if_t<
691+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
692+
fwidth(T input) {
693+
return __detail::fwidth_impl(input);
694+
}
695+
696+
template <int N>
697+
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
698+
const inline __detail::HLSL_FIXED_VECTOR<half, N> fwidth(
699+
__detail::HLSL_FIXED_VECTOR<half, N> input) {
700+
return __detail::fwidth_impl(input);
701+
}
702+
703+
template <int N>
704+
const inline __detail::HLSL_FIXED_VECTOR<float, N>
705+
fwidth(__detail::HLSL_FIXED_VECTOR<float, N> input) {
706+
return __detail::fwidth_impl(input);
707+
}
708+
669709
} // namespace hlsl
670710
#endif //_HLSL_HLSL_INTRINSICS_H_

clang/lib/Sema/SemaSPIRV.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,24 @@ 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_fwidth: {
364+
if (SemaRef.checkArgCount(TheCall, 1))
365+
return true;
366+
367+
// Check if first argument has floating representation
368+
ExprResult A = TheCall->getArg(0);
369+
QualType ArgTyA = A.get()->getType();
370+
if (!ArgTyA->hasFloatingRepresentation()) {
371+
SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
372+
<< /* ordinal */ 1 << /* scalar or vector */ 5 << /* no int */ 0
373+
<< /* fp */ 1 << ArgTyA;
374+
return true;
375+
}
376+
377+
QualType RetTy = ArgTyA;
378+
TheCall->setType(RetTy);
379+
break;
380+
}
363381
}
364382
return false;
365383
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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-unknown-vulkan1.3-library %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__detail11fwidth_implIDhEET_S2_
9+
// CHECK: %hlsl.ddx.coarse = call {{.*}} half @llvm.dx.ddx.coarse.f16(half %{{.*}})
10+
// CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}})
11+
// CHECK: %hlsl.ddy.coarse = call {{.*}} half @llvm.dx.ddy.coarse.f16(half %{{.*}})
12+
// CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}})
13+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
14+
// CHECK: ret half %{{.*}}
15+
// CHECK-LABEL-SPIRV: half @_Z15test_f16_fwidthDh
16+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} half @llvm.spv.fwidth.f16(half %{{.*}})
17+
// CHECK-SPIRV: ret half %spv.fwidth
18+
half test_f16_fwidth(half val) {
19+
return fwidth(val);
20+
}
21+
22+
// CHECK-LABEL: define {{.*}} <2 x half> @_ZN4hlsl8__detail11fwidth_implIDv2_DhEET_S3_
23+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x half> @llvm.dx.ddx.coarse.v2f16(<2 x half> %{{.*}})
24+
// CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}})
25+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x half> @llvm.dx.ddy.coarse.v2f16(<2 x half> %{{.*}})
26+
// CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}})
27+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
28+
// CHECK: ret <2 x half> %{{.*}}
29+
// CHECK-LABEL-SPIRV: <2 x half> @_Z16test_f16_fwidth2Dv2_Dh
30+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> %{{.*}})
31+
// CHECK-SPIRV: ret <2 x half> %spv.fwidth
32+
half2 test_f16_fwidth2(half2 val) {
33+
return fwidth(val);
34+
}
35+
36+
// CHECK-LABEL: define {{.*}} <3 x half> @_ZN4hlsl8__detail11fwidth_implIDv3_DhEET_S3_
37+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x half> @llvm.dx.ddx.coarse.v3f16(<3 x half> %{{.*}})
38+
// CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}})
39+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x half> @llvm.dx.ddy.coarse.v3f16(<3 x half> %{{.*}})
40+
// CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}})
41+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
42+
// CHECK: ret <3 x half> %{{.*}}
43+
// CHECK-LABEL-SPIRV: <3 x half> @_Z16test_f16_fwidth3Dv3_Dh
44+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> %{{.*}})
45+
// CHECK-SPIRV: ret <3 x half> %spv.fwidth
46+
half3 test_f16_fwidth3(half3 val) {
47+
return fwidth(val);
48+
}
49+
50+
// CHECK-LABEL: define {{.*}} <4 x half> @_ZN4hlsl8__detail11fwidth_implIDv4_DhEET_S3_
51+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x half> @llvm.dx.ddx.coarse.v4f16(<4 x half> %{{.*}})
52+
// CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}})
53+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x half> @llvm.dx.ddy.coarse.v4f16(<4 x half> %{{.*}})
54+
// CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}})
55+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
56+
// CHECK: ret <4 x half> %{{.*}}
57+
// CHECK-LABEL-SPIRV: <4 x half> @_Z16test_f16_fwidth4Dv4_Dh
58+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> %{{.*}})
59+
// CHECK-SPIRV: ret <4 x half> %spv.fwidth
60+
half4 test_f16_fwidth4(half4 val) {
61+
return fwidth(val);
62+
}
63+
64+
// CHECK-LABEL: define {{.*}} float @_ZN4hlsl8__detail11fwidth_implIfEET_S2_
65+
// CHECK: %hlsl.ddx.coarse = call {{.*}} float @llvm.dx.ddx.coarse.f32(float %{{.*}})
66+
// CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
67+
// CHECK: %hlsl.ddy.coarse = call {{.*}} float @llvm.dx.ddy.coarse.f32(float %{{.*}})
68+
// CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}})
69+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
70+
// CHECK: ret float %{{.*}}
71+
// CHECK-LABEL-SPIRV: float @_Z15test_f32_fwidthf
72+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} float @llvm.spv.fwidth.f32(float %{{.*}})
73+
// CHECK-SPIRV: ret float %spv.fwidth
74+
float test_f32_fwidth(float val) {
75+
return fwidth(val);
76+
}
77+
78+
// CHECK-LABEL: define {{.*}} <2 x float> @_ZN4hlsl8__detail11fwidth_implIDv2_fEET_S3_
79+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x float> @llvm.dx.ddx.coarse.v2f32(<2 x float> %{{.*}})
80+
// CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}})
81+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x float> @llvm.dx.ddy.coarse.v2f32(<2 x float> %{{.*}})
82+
// CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}})
83+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
84+
// CHECK: ret <2 x float> %{{.*}}
85+
// CHECK-LABEL-SPIRV: <2 x float> @_Z16test_f32_fwidth2Dv2_f
86+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> %{{.*}})
87+
// CHECK-SPIRV: ret <2 x float> %spv.fwidth
88+
float2 test_f32_fwidth2(float2 val) {
89+
return fwidth(val);
90+
}
91+
92+
// CHECK-LABEL: define {{.*}} <3 x float> @_ZN4hlsl8__detail11fwidth_implIDv3_fEET_S3_
93+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x float> @llvm.dx.ddx.coarse.v3f32(<3 x float> %{{.*}})
94+
// CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}})
95+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x float> @llvm.dx.ddy.coarse.v3f32(<3 x float> %{{.*}})
96+
// CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}})
97+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
98+
// CHECK: ret <3 x float> %{{.*}}
99+
// CHECK-LABEL-SPIRV: <3 x float> @_Z16test_f32_fwidth3Dv3_f
100+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> %{{.*}})
101+
// CHECK-SPIRV: ret <3 x float> %spv.fwidth
102+
float3 test_f32_fwidth3(float3 val) {
103+
return fwidth(val);
104+
}
105+
106+
// CHECK-LABEL: define {{.*}} <4 x float> @_ZN4hlsl8__detail11fwidth_implIDv4_fEET_S3_
107+
// CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x float> @llvm.dx.ddx.coarse.v4f32(<4 x float> %{{.*}})
108+
// CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
109+
// CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x float> @llvm.dx.ddy.coarse.v4f32(<4 x float> %{{.*}})
110+
// CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}})
111+
// CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}}
112+
// CHECK: ret <4 x float> %{{.*}}
113+
// CHECK-LABEL-SPIRV: <4 x float> @_Z16test_f32_fwidth4Dv4_f
114+
// CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> %{{.*}})
115+
// CHECK-SPIRV: ret <4 x float> %spv.fwidth
116+
float4 test_f32_fwidth4(float4 val) {
117+
return fwidth(val);
118+
}
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-compute %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: [[fwidth0:%.*]] = tail call half @llvm.spv.fwidth.f16(half {{%.*}})
12+
// CHECK: ret half [[fwidth0]]
13+
half test_fwidth_half(half X) { return __builtin_spirv_fwidth(X); }
14+
15+
// CHECK: [[fwidth0:%.*]] = tail call <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> {{%.*}})
16+
// CHECK: ret <2 x half> [[fwidth0]]
17+
half2 test_fwidth_half2(half2 X) { return __builtin_spirv_fwidth(X); }
18+
19+
// CHECK: [[fwidth0:%.*]] = tail call <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> {{%.*}})
20+
// CHECK: ret <3 x half> [[fwidth0]]
21+
half3 test_fwidth_half3(half3 X) { return __builtin_spirv_fwidth(X); }
22+
23+
// CHECK: [[fwidth0:%.*]] = tail call <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> {{%.*}})
24+
// CHECK: ret <4 x half> [[fwidth0]]
25+
half4 test_fwidth_half4(half4 X) { return __builtin_spirv_fwidth(X); }
26+
27+
// CHECK: [[fwidth0:%.*]] = tail call float @llvm.spv.fwidth.f32(float {{%.*}})
28+
// CHECK: ret float [[fwidth0]]
29+
float test_fwidth_float(float X) { return __builtin_spirv_fwidth(X); }
30+
31+
// CHECK: [[fwidth1:%.*]] = tail call <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> {{%.*}})
32+
// CHECK: ret <2 x float> [[fwidth1]]
33+
float2 test_fwidth_float2(float2 X) { return __builtin_spirv_fwidth(X); }
34+
35+
// CHECK: [[fwidth2:%.*]] = tail call <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> {{%.*}})
36+
// CHECK: ret <3 x float> [[fwidth2]]
37+
float3 test_fwidth_float3(float3 X) { return __builtin_spirv_fwidth(X); }
38+
39+
// CHECK: [[fwidth3:%.*]] = tail call <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> {{%.*}})
40+
// CHECK: ret <4 x float> [[fwidth3]]
41+
float4 test_fwidth_float4(float4 X) { return __builtin_spirv_fwidth(X); }
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify
2+
3+
typedef float float2 __attribute__((ext_vector_type(2)));
4+
5+
void test_too_few_arg()
6+
{
7+
return __builtin_spirv_fwidth();
8+
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
9+
}
10+
11+
float test_too_many_arg(float p0) {
12+
return __builtin_spirv_fwidth(p0, p0);
13+
// expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
14+
}
15+
16+
float test_int_scalar_inputs(int p0) {
17+
return __builtin_spirv_fwidth(p0);
18+
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}}
19+
}
20+
21+
float test_mismatched_return(float2 p0) {
22+
return __builtin_spirv_fwidth(p0);
23+
// expected-error@-1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}}
24+
}

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
136136
def int_spv_discard : DefaultAttrsIntrinsic<[], [], []>;
137137
def int_spv_ddx_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
138138
def int_spv_ddy_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
139+
def int_spv_fwidth : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
139140
def int_spv_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
140141
def int_spv_sclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
141142
def int_spv_nclamp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
328328
MachineInstr &I) const;
329329
bool selectFrexp(Register ResVReg, const SPIRVType *ResType,
330330
MachineInstr &I) const;
331-
bool selectDpdCoarse(Register ResVReg, const SPIRVType *ResType,
332-
MachineInstr &I, const unsigned DPdOpCode) const;
331+
bool selectDerivativeInst(Register ResVReg, const SPIRVType *ResType,
332+
MachineInstr &I, const unsigned DPdOpCode) const;
333333
// Utilities
334334
std::pair<Register, bool>
335335
buildI32Constant(uint32_t Val, MachineInstr &I,
@@ -3143,10 +3143,9 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
31433143
return Result;
31443144
}
31453145

3146-
bool SPIRVInstructionSelector::selectDpdCoarse(Register ResVReg,
3147-
const SPIRVType *ResType,
3148-
MachineInstr &I,
3149-
const unsigned DPdOpCode) const {
3146+
bool SPIRVInstructionSelector::selectDerivativeInst(
3147+
Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
3148+
const unsigned DPdOpCode) const {
31503149
// TODO: This should check specifically for Fragment Execution Model, but STI
31513150
// doesn't provide that information yet. See #167562
31523151
errorIfInstrOutsideShader(I);
@@ -3583,12 +3582,12 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
35833582
case Intrinsic::spv_unpackhalf2x16: {
35843583
return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16);
35853584
}
3586-
case Intrinsic::spv_ddx_coarse: {
3587-
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
3588-
}
3589-
case Intrinsic::spv_ddy_coarse: {
3590-
return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
3591-
}
3585+
case Intrinsic::spv_ddx_coarse:
3586+
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse);
3587+
case Intrinsic::spv_ddy_coarse:
3588+
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
3589+
case Intrinsic::spv_fwidth:
3590+
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
35923591
default: {
35933592
std::string DiagMsg;
35943593
raw_string_ostream OS(DiagMsg);

0 commit comments

Comments
 (0)