Skip to content

Commit a141971

Browse files
author
Alexander Johnston
committed
[HLSL] Implement the fwidth intrinsic
Closes #99120
1 parent 1553b3d commit a141971

File tree

20 files changed

+370
-1
lines changed

20 files changed

+370
-1
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5204,6 +5204,18 @@ def HLSLGetSpirvSpecConstant : LangBuiltin<"HLSL_LANG">, HLSLScalarTemplate {
52045204
let Prototype = "T(unsigned int, T)";
52055205
}
52065206

5207+
def HLSLDerivCoarseX: LangBuiltin<"HLSL_LANG"> {
5208+
let Spellings = ["__builtin_hlsl_elementwise_deriv_coarse_x"];
5209+
let Attributes = [NoThrow, Const, CustomTypeChecking];
5210+
let Prototype = "void(...)";
5211+
}
5212+
5213+
def HLSLDerivCoarseY: LangBuiltin<"HLSL_LANG"> {
5214+
let Spellings = ["__builtin_hlsl_elementwise_deriv_coarse_y"];
5215+
let Attributes = [NoThrow, Const, CustomTypeChecking];
5216+
let Prototype = "void(...)";
5217+
}
5218+
52075219
// Builtins for XRay.
52085220
def XRayCustomEvent : Builtin {
52095221
let Spellings = ["__xray_customevent"];

clang/include/clang/Basic/BuiltinsSPIRVCommon.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
2121
def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
2222
def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
2323
def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
24+
def fwidth : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
532532
/*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(),
533533
ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac");
534534
}
535+
case Builtin::BI__builtin_hlsl_elementwise_deriv_coarse_x: {
536+
Value *Op0 = EmitScalarExpr(E->getArg(0));
537+
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
538+
llvm_unreachable(
539+
"deriv coarse x operand must have a float representation");
540+
return Builder.CreateIntrinsic(
541+
/*ReturnType=*/Op0->getType(), llvm::Intrinsic::dx_deriv_coarse_x,
542+
ArrayRef<Value *>{Op0}, nullptr, "hlsl.deriv.coarse.x");
543+
}
544+
case Builtin::BI__builtin_hlsl_elementwise_deriv_coarse_y: {
545+
Value *Op0 = EmitScalarExpr(E->getArg(0));
546+
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
547+
llvm_unreachable(
548+
"deriv coarse x operand must have a float representation");
549+
return Builder.CreateIntrinsic(
550+
/*ReturnType=*/Op0->getType(), llvm::Intrinsic::dx_deriv_coarse_y,
551+
ArrayRef<Value *>{Op0}, nullptr, "hlsl.deriv.coarse.y");
552+
}
535553
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
536554
Value *Op0 = EmitScalarExpr(E->getArg(0));
537555
llvm::Type *Xty = Op0->getType();

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: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,31 @@ template <typename T> constexpr T ldexp_impl(T X, T Exp) {
148148
return exp2(Exp) * X;
149149
}
150150

151+
template <typename T> constexpr T fwidth_impl(T input) {
152+
#if (__has_builtin(__builtin_spirv_fwidth))
153+
return __builtin_spirv_fwidth(input);
154+
#else
155+
T derivCoarseX = __builtin_hlsl_elementwise_deriv_coarse_x(input);
156+
derivCoarseX = abs(derivCoarseX);
157+
T derivCoarseY = __builtin_hlsl_elementwise_deriv_coarse_y(input);
158+
derivCoarseY = abs(derivCoarseY);
159+
return derivCoarseX + derivCoarseY;
160+
#endif
161+
}
162+
163+
template <typename T, int N>
164+
constexpr vector<T, N> fwidth_vec_impl(vector<T, N> input) {
165+
#if (__has_builtin(__builtin_spirv_fwidth))
166+
return __builtin_spirv_fwidth(input);
167+
#else
168+
vector<T, N> derivCoarseX = __builtin_hlsl_elementwise_deriv_coarse_x(input);
169+
derivCoarseX = abs(derivCoarseX);
170+
vector<T, N> derivCoarseY = __builtin_hlsl_elementwise_deriv_coarse_y(input);
171+
derivCoarseY = abs(derivCoarseY);
172+
return derivCoarseX + derivCoarseY;
173+
#endif
174+
}
175+
151176
} // namespace __detail
152177
} // namespace hlsl
153178

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,5 +605,30 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
605605
return __detail::smoothstep_vec_impl(Min, Max, X);
606606
}
607607

608+
//===----------------------------------------------------------------------===//
609+
// fwidth builtin
610+
//===----------------------------------------------------------------------===//
611+
612+
/// \fn T fwidth(T x)
613+
/// \brief Computes the sum of the absolute values of the partial derivatives
614+
/// with regard to the x and y screen space coordinates.
615+
/// \param x [in] The floating-point scalar or vector to process.
616+
///
617+
/// The return value is a floating-point scalar or vector where each element
618+
/// holds the computation of the matching element in the input.
619+
620+
template <typename T>
621+
const inline __detail::enable_if_t<
622+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
623+
fwidth(T input) {
624+
return __detail::fwidth_impl(input);
625+
}
626+
627+
template <int N>
628+
const inline __detail::HLSL_FIXED_VECTOR<float, N>
629+
fwidth(__detail::HLSL_FIXED_VECTOR<float, N> input) {
630+
return __detail::fwidth_vec_impl(input);
631+
}
632+
608633
} // namespace hlsl
609634
#endif //_HLSL_HLSL_INTRINSICS_H_

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3080,7 +3080,9 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
30803080
case Builtin::BI__builtin_hlsl_elementwise_degrees:
30813081
case Builtin::BI__builtin_hlsl_elementwise_radians:
30823082
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
3083-
case Builtin::BI__builtin_hlsl_elementwise_frac: {
3083+
case Builtin::BI__builtin_hlsl_elementwise_frac:
3084+
case Builtin::BI__builtin_hlsl_elementwise_deriv_coarse_x:
3085+
case Builtin::BI__builtin_hlsl_elementwise_deriv_coarse_y: {
30843086
if (SemaRef.checkArgCount(TheCall, 1))
30853087
return true;
30863088
if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,

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: 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+
}

0 commit comments

Comments
 (0)