Skip to content

Commit ddbdf52

Browse files
author
Alexander Johnston
committed
[HLSL] Implement ddx/ddy_coarse intrinsics
1 parent c5f1c69 commit ddbdf52

28 files changed

+661
-1
lines changed

clang/include/clang/Basic/Builtins.td

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

5232+
def HLSLDdxCoarse : LangBuiltin<"HLSL_LANG"> {
5233+
let Spellings = ["__builtin_hlsl_elementwise_ddx_coarse"];
5234+
let Attributes = [NoThrow, Const, CustomTypeChecking];
5235+
let Prototype = "void(...)";
5236+
}
5237+
5238+
def HLSLDdyCoarse : LangBuiltin<"HLSL_LANG"> {
5239+
let Spellings = ["__builtin_hlsl_elementwise_ddy_coarse"];
5240+
let Attributes = [NoThrow, Const, CustomTypeChecking];
5241+
let Prototype = "void(...)";
5242+
}
5243+
52325244
// Builtins for XRay.
52335245
def XRayCustomEvent : Builtin {
52345246
let Spellings = ["__xray_customevent"];

clang/include/clang/Basic/BuiltinsSPIRVVK.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ 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_coarse : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
16+
def ddy_coarse : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
840840
return EmitRuntimeCall(
841841
Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
842842
}
843+
case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse: {
844+
Value *Op0 = EmitScalarExpr(E->getArg(0));
845+
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
846+
llvm_unreachable(
847+
"ddx_coarse operand must have a float representation");
848+
Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxCoarseIntrinsic();
849+
return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
850+
ArrayRef<Value *>{Op0}, nullptr, "hlsl.ddx.coarse");
851+
}
852+
case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: {
853+
Value *Op0 = EmitScalarExpr(E->getArg(0));
854+
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
855+
llvm_unreachable(
856+
"ddy_coarse operand must have a float representation");
857+
Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyCoarseIntrinsic();
858+
return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
859+
ArrayRef<Value *>{Op0}, nullptr, "hlsl.ddy.coarse");
860+
}
843861
case Builtin::BI__builtin_get_spirv_spec_constant_bool:
844862
case Builtin::BI__builtin_get_spirv_spec_constant_short:
845863
case Builtin::BI__builtin_get_spirv_spec_constant_ushort:

clang/lib/CodeGen/CGHLSLRuntime.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ class CGHLSLRuntime {
136136
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,
137137
group_memory_barrier_with_group_sync)
138138
GENERATE_HLSL_INTRINSIC_FUNCTION(GetDimensionsX, resource_getdimensions_x)
139+
GENERATE_HLSL_INTRINSIC_FUNCTION(DdxCoarse, ddx_coarse)
140+
GENERATE_HLSL_INTRINSIC_FUNCTION(DdyCoarse, ddy_coarse)
139141

140142
//===----------------------------------------------------------------------===//
141143
// End of reserved area for HLSL intrinsic getters.

clang/lib/CodeGen/TargetBuiltins/SPIR.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,18 @@ 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_coarse:
155+
return Builder.CreateIntrinsic(
156+
/*ReturnType=*/getTypes().ConvertType(E->getType()),
157+
Intrinsic::spv_ddx_coarse,
158+
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr,
159+
"spv.ddx.coarse");
160+
case SPIRV::BI__builtin_spirv_ddy_coarse:
161+
return Builder.CreateIntrinsic(
162+
/*ReturnType=*/getTypes().ConvertType(E->getType()),
163+
Intrinsic::spv_ddy_coarse,
164+
ArrayRef<Value *>{EmitScalarExpr(E->getArg(0))}, nullptr,
165+
"spv.ddy.coarse");
154166
}
155167
return nullptr;
156168
}

clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,22 @@ template <typename T> constexpr T ldexp_impl(T X, T Exp) {
148148
return exp2(Exp) * X;
149149
}
150150

151+
template <typename T> constexpr T ddx_coarse_impl(T value) {
152+
#if (__has_builtin(__builtin_spirv_ddx_coarse))
153+
return __builtin_spirv_ddx_coarse(value);
154+
#else
155+
return __builtin_hlsl_elementwise_ddx_coarse(value);
156+
#endif
157+
}
158+
159+
template <typename T> constexpr T ddy_coarse_impl(T value) {
160+
#if (__has_builtin(__builtin_spirv_ddy_coarse))
161+
return __builtin_spirv_ddy_coarse(value);
162+
#else
163+
return __builtin_hlsl_elementwise_ddy_coarse(value);
164+
#endif
165+
}
166+
151167
} // namespace __detail
152168
} // namespace hlsl
153169

clang/lib/Headers/hlsl/hlsl_intrinsics.h

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

608+
//===----------------------------------------------------------------------===//
609+
// ddx_coarse builtin
610+
//===----------------------------------------------------------------------===//
611+
612+
/// \fn T ddx_coarse(T value)
613+
/// \brief Computes a low precision partial derivative with respect to the
614+
/// screen-space x-coordinate.
615+
/// \param value The input value.
616+
///
617+
/// The return value is a floating point scalar or vector containing the low
618+
/// prevision partial derivative of the input value.
619+
620+
template <typename T>
621+
const inline __detail::enable_if_t<
622+
__detail::is_arithmetic<T>::Value && __detail::is_same<half, T>::value, T>
623+
ddx_coarse(T value) {
624+
return __detail::ddx_coarse_impl(value);
625+
}
626+
627+
template <typename T>
628+
const inline __detail::enable_if_t<
629+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
630+
ddx_coarse(T value) {
631+
return __detail::ddx_coarse_impl(value);
632+
}
633+
634+
template <int L>
635+
const inline __detail::HLSL_FIXED_VECTOR<half, L>
636+
ddx_coarse(__detail::HLSL_FIXED_VECTOR<half, L> value) {
637+
return __detail::ddx_coarse_impl(value);
638+
}
639+
640+
template <int L>
641+
const inline __detail::HLSL_FIXED_VECTOR<float, L>
642+
ddx_coarse(__detail::HLSL_FIXED_VECTOR<float, L> value) {
643+
return __detail::ddx_coarse_impl(value);
644+
}
645+
646+
//===----------------------------------------------------------------------===//
647+
// ddy_coarse builtin
648+
//===----------------------------------------------------------------------===//
649+
650+
/// \fn T ddy_coarse(T value)
651+
/// \brief Computes a low precision partial derivative with respect to the
652+
/// screen-space y-coordinate.
653+
/// \param value The input value.
654+
///
655+
/// The return value is a floating point scalar or vector containing the low
656+
/// prevision partial derivative of the input value.
657+
658+
template <typename T>
659+
const inline __detail::enable_if_t<
660+
__detail::is_arithmetic<T>::Value && __detail::is_same<half, T>::value, T>
661+
ddy_coarse(T value) {
662+
return __detail::ddy_coarse_impl(value);
663+
}
664+
665+
template <typename T>
666+
const inline __detail::enable_if_t<
667+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
668+
ddy_coarse(T value) {
669+
return __detail::ddy_coarse_impl(value);
670+
}
671+
672+
template <int L>
673+
const inline __detail::HLSL_FIXED_VECTOR<half, L>
674+
ddy_coarse(__detail::HLSL_FIXED_VECTOR<half, L> value) {
675+
return __detail::ddy_coarse_impl(value);
676+
}
677+
678+
template <int L>
679+
const inline __detail::HLSL_FIXED_VECTOR<float, L>
680+
ddy_coarse(__detail::HLSL_FIXED_VECTOR<float, L> value) {
681+
return __detail::ddy_coarse_impl(value);
682+
}
683+
608684
} // namespace hlsl
609685
#endif //_HLSL_HLSL_INTRINSICS_H_

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3202,7 +3202,9 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
32023202
case Builtin::BI__builtin_hlsl_elementwise_degrees:
32033203
case Builtin::BI__builtin_hlsl_elementwise_radians:
32043204
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
3205-
case Builtin::BI__builtin_hlsl_elementwise_frac: {
3205+
case Builtin::BI__builtin_hlsl_elementwise_frac:
3206+
case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse:
3207+
case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: {
32063208
if (SemaRef.checkArgCount(TheCall, 1))
32073209
return true;
32083210
if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,

clang/lib/Sema/SemaSPIRV.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ static bool CheckAllArgsHaveSameType(Sema *S, CallExpr *TheCall) {
4646
return false;
4747
}
4848

49+
static bool CheckAllArgTypesAreCorrect(
50+
Sema *S, CallExpr *TheCall,
51+
llvm::function_ref<bool(Sema *S, SourceLocation Loc, int ArgOrdinal,
52+
clang::QualType PassedType)>
53+
Check) {
54+
for (unsigned I = 0; I < TheCall->getNumArgs(); ++I) {
55+
Expr *Arg = TheCall->getArg(I);
56+
if (Check(S, Arg->getBeginLoc(), I + 1, Arg->getType()))
57+
return true;
58+
}
59+
return false;
60+
}
61+
4962
static bool CheckAllArgTypesAreCorrect(
5063
Sema *S, CallExpr *TheCall,
5164
llvm::ArrayRef<
@@ -360,6 +373,19 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
360373
case SPIRV::BI__builtin_spirv_generic_cast_to_ptr_explicit: {
361374
return checkGenericCastToPtr(SemaRef, TheCall);
362375
}
376+
case SPIRV::BI__builtin_spirv_ddx_coarse:
377+
case SPIRV::BI__builtin_spirv_ddy_coarse: {
378+
if (SemaRef.checkArgCount(TheCall, 1))
379+
return true;
380+
381+
if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall,
382+
CheckFloatOrHalfRepresentation))
383+
return true;
384+
385+
QualType RetTy = TheCall->getArg(0)->getType();
386+
TheCall->setType(RetTy);
387+
break;
388+
}
363389
}
364390
return false;
365391
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
5+
// CHECK: define hidden noundef nofpclass(nan inf) half @
6+
// CHECK: %hlsl.ddx.coarse = call reassoc nnan ninf nsz arcp afn half @llvm.dx.ddx.coarse.f16(half %{{.*}})
7+
// CHECK: ret half %hlsl.ddx.coarse
8+
half test_f16_ddx_coarse(half val) {
9+
return __builtin_hlsl_elementwise_ddx_coarse(val);
10+
}
11+
12+
// CHECK: define hidden noundef nofpclass(nan inf) float @
13+
// CHECK: %hlsl.ddx.coarse = call reassoc nnan ninf nsz arcp afn float @llvm.dx.ddx.coarse.f32(float %{{.*}})
14+
// CHECK: ret float %hlsl.ddx.coarse
15+
float test_f32_ddx_coarse(float val) {
16+
return __builtin_hlsl_elementwise_ddx_coarse(val);
17+
}

0 commit comments

Comments
 (0)