https://github.com/Alexander-Johnston created https://github.com/llvm/llvm-project/pull/168874
Implements the HLSL ddx_fine and ddy_fine intrinsics. For the SPIRV backend the intrinsics are ensured to be unavailable in opencl (as they require fragment execution stage). Closes https://github.com/llvm/llvm-project/issues/99098 Closes https://github.com/llvm/llvm-project/issues/99101 >From 420c196024bcb1cf3d41729aa0cacdd4d7fca693 Mon Sep 17 00:00:00 2001 From: Alexander Johnston <[email protected]> Date: Wed, 19 Nov 2025 00:21:25 +0000 Subject: [PATCH] [HLSL] Implement ddx/ddy_fine intrinsics Implements the HLSL ddx_fine and ddy_fine intrinsics together as the implementations are nearly identical. --- clang/include/clang/Basic/Builtins.td | 12 +++ clang/lib/CodeGen/CGHLSLBuiltins.cpp | 18 ++++ clang/lib/CodeGen/CGHLSLRuntime.h | 2 + .../lib/Headers/hlsl/hlsl_alias_intrinsics.h | 68 +++++++++++++++ clang/lib/Sema/SemaHLSL.cpp | 4 +- .../builtins/ddx-fine-builtin.hlsl | 26 ++++++ clang/test/CodeGenHLSL/builtins/ddx-fine.hlsl | 86 +++++++++++++++++++ .../builtins/ddy-fine-builtin.hlsl | 26 ++++++ clang/test/CodeGenHLSL/builtins/ddy-fine.hlsl | 86 +++++++++++++++++++ .../SemaHLSL/BuiltIns/ddx-fine-errors.hlsl | 22 +++++ .../SemaHLSL/BuiltIns/ddy-fine-errors.hlsl | 22 +++++ llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 + llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 + llvm/lib/Target/DirectX/DXIL.td | 18 ++++ .../DirectX/DirectXTargetTransformInfo.cpp | 2 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 4 + llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp | 4 +- llvm/test/CodeGen/DirectX/ddx_fine-errors.ll | 29 +++++++ llvm/test/CodeGen/DirectX/ddx_fine.ll | 40 +++++++++ llvm/test/CodeGen/DirectX/ddy_fine-errors.ll | 29 +++++++ llvm/test/CodeGen/DirectX/ddy_fine.ll | 40 +++++++++ .../CodeGen/SPIRV/hlsl-intrinsics/ddx_fine.ll | 47 ++++++++++ .../CodeGen/SPIRV/hlsl-intrinsics/ddy_fine.ll | 47 ++++++++++ .../CodeGen/SPIRV/opencl/ddx_fine-error.ll | 12 +++ .../CodeGen/SPIRV/opencl/ddy_fine-error.ll | 12 +++ 25 files changed, 658 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/ddx-fine-builtin.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/ddx-fine.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/ddy-fine-builtin.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/ddy-fine.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ddx-fine-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ddy-fine-errors.hlsl create mode 100644 llvm/test/CodeGen/DirectX/ddx_fine-errors.ll create mode 100644 llvm/test/CodeGen/DirectX/ddx_fine.ll create mode 100644 llvm/test/CodeGen/DirectX/ddy_fine-errors.ll create mode 100644 llvm/test/CodeGen/DirectX/ddy_fine.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddx_fine.ll create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddy_fine.ll create mode 100644 llvm/test/CodeGen/SPIRV/opencl/ddx_fine-error.ll create mode 100644 llvm/test/CodeGen/SPIRV/opencl/ddy_fine-error.ll diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 502382a069856..64de76a01f335 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5265,6 +5265,18 @@ def HLSLDdyCoarse : LangBuiltin<"HLSL_LANG"> { let Prototype = "void(...)"; } +def HLSLDdxFine : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_ddx_fine"]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Prototype = "void(...)"; +} + +def HLSLDdyFine : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_ddy_fine"]; + let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Prototype = "void(...)"; +} + // Builtins for XRay. def XRayCustomEvent : Builtin { let Spellings = ["__xray_customevent"]; diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 12d9a98915ce3..bfa9a53b7804e 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -942,6 +942,24 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, ArrayRef<Value *>{Op0}, nullptr, "hlsl.ddy.coarse"); } + case Builtin::BI__builtin_hlsl_elementwise_ddx_fine: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + if (!E->getArg(0)->getType()->hasFloatingRepresentation()) + llvm_unreachable("ddx_fine operand must have a float representation"); + Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxFineIntrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID, + ArrayRef<Value *>{Op0}, nullptr, + "hlsl.ddx.fine"); + } + case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + if (!E->getArg(0)->getType()->hasFloatingRepresentation()) + llvm_unreachable("ddy_fine operand must have a float representation"); + Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyFineIntrinsic(); + return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID, + ArrayRef<Value *>{Op0}, nullptr, + "hlsl.ddy.fine"); + } case Builtin::BI__builtin_get_spirv_spec_constant_bool: case Builtin::BI__builtin_get_spirv_spec_constant_short: case Builtin::BI__builtin_get_spirv_spec_constant_ushort: diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index c883282a8d9c8..2ad39c91280a0 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -171,6 +171,8 @@ class CGHLSLRuntime { GENERATE_HLSL_INTRINSIC_FUNCTION(GetDimensionsX, resource_getdimensions_x) GENERATE_HLSL_INTRINSIC_FUNCTION(DdxCoarse, ddx_coarse) GENERATE_HLSL_INTRINSIC_FUNCTION(DdyCoarse, ddy_coarse) + GENERATE_HLSL_INTRINSIC_FUNCTION(DdxFine, ddx_fine) + GENERATE_HLSL_INTRINSIC_FUNCTION(DdyFine, ddy_fine) //===----------------------------------------------------------------------===// // End of reserved area for HLSL intrinsic getters. diff --git a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h index 38b95ee90736a..f58150ed61106 100644 --- a/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_alias_intrinsics.h @@ -3014,5 +3014,73 @@ float3 ddy_coarse(float3); _HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_coarse) float4 ddy_coarse(float4); +//===----------------------------------------------------------------------===// +// ddx_fine builtin +//===----------------------------------------------------------------------===// + +/// \fn T ddx_fine(T value) +/// \brief Computes a high precision partial derivative with respect to the +/// screen-space x-coordinate. +/// \param value The input value. +/// +/// The return value is a floating point scalar or vector containing the high +/// prevision partial derivative of the input value. + +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +half ddx_fine(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +half2 ddx_fine(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +half3 ddx_fine(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +half4 ddx_fine(half4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +float ddx_fine(float); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +float2 ddx_fine(float2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +float3 ddx_fine(float3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddx_fine) +float4 ddx_fine(float4); + +//===----------------------------------------------------------------------===// +// ddy_fine builtin +//===----------------------------------------------------------------------===// + +/// \fn T ddy_fine(T value) +/// \brief Computes a high precision partial derivative with respect to the +/// screen-space y-coordinate. +/// \param value The input value. +/// +/// The return value is a floating point scalar or vector containing the high +/// prevision partial derivative of the input value. + +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +half ddy_fine(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +half2 ddy_fine(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +half3 ddy_fine(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +half4 ddy_fine(half4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +float ddy_fine(float); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +float2 ddy_fine(float2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +float3 ddy_fine(float3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_ddy_fine) +float4 ddy_fine(float4); + } // namespace hlsl #endif //_HLSL_HLSL_ALIAS_INTRINSICS_H_ diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index c5666941fd36a..cc2939314b0eb 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3211,7 +3211,9 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__builtin_hlsl_elementwise_rsqrt: case Builtin::BI__builtin_hlsl_elementwise_frac: case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse: - case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: { + case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: + case Builtin::BI__builtin_hlsl_elementwise_ddx_fine: + case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: { if (SemaRef.checkArgCount(TheCall, 1)) return true; if (CheckAllArgTypesAreCorrect(&SemaRef, TheCall, diff --git a/clang/test/CodeGenHLSL/builtins/ddx-fine-builtin.hlsl b/clang/test/CodeGenHLSL/builtins/ddx-fine-builtin.hlsl new file mode 100644 index 0000000000000..69f7ab3c6ce62 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/ddx-fine-builtin.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-compute %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV + +// CHECK-LABEL: half @_Z17test_f16_ddx_fineDh +// CHECK: %hlsl.ddx.fine = call {{.*}} half @llvm.dx.ddx.fine.f16(half %{{.*}}) +// CHECK: ret half %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: half @_Z17test_f16_ddx_fineDh +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} half @llvm.spv.ddx.fine.f16(half %{{.*}}) +// CHECK-SPIRV: ret half %hlsl.ddx.fine +half test_f16_ddx_fine(half val) { + return __builtin_hlsl_elementwise_ddx_fine(val); +} + +// CHECK-LABEL: float @_Z17test_f32_ddx_finef +// CHECK: %hlsl.ddx.fine = call {{.*}} float @llvm.dx.ddx.fine.f32(float %{{.*}}) +// CHECK: ret float %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: float @_Z17test_f32_ddx_finef +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} float @llvm.spv.ddx.fine.f32(float %{{.*}}) +// CHECK-SPIRV: ret float %hlsl.ddx.fine +float test_f32_ddx_fine(float val) { + return __builtin_hlsl_elementwise_ddx_fine(val); +} diff --git a/clang/test/CodeGenHLSL/builtins/ddx-fine.hlsl b/clang/test/CodeGenHLSL/builtins/ddx-fine.hlsl new file mode 100644 index 0000000000000..2630260abcb43 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/ddx-fine.hlsl @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-compute %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV + +// CHECK-LABEL: half @_Z17test_f16_ddx_fineDh +// CHECK: %hlsl.ddx.fine = call {{.*}} half @llvm.dx.ddx.fine.f16(half %{{.*}}) +// CHECK: ret half %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: half @_Z17test_f16_ddx_fineDh +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} half @llvm.spv.ddx.fine.f16(half %{{.*}}) +// CHECK-SPIRV: ret half %hlsl.ddx.fine +half test_f16_ddx_fine(half val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <2 x half> @_Z18test_f16_ddx_fine2Dv2_Dh +// CHECK: %hlsl.ddx.fine = call {{.*}} <2 x half> @llvm.dx.ddx.fine.v2f16(<2 x half> %{{.*}}) +// CHECK: ret <2 x half> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <2 x half> @_Z18test_f16_ddx_fine2Dv2_Dh +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <2 x half> @llvm.spv.ddx.fine.v2f16(<2 x half> %{{.*}}) +// CHECK-SPIRV: ret <2 x half> %hlsl.ddx.fine +half2 test_f16_ddx_fine2(half2 val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <3 x half> @_Z18test_f16_ddx_fine3Dv3_Dh +// CHECK: %hlsl.ddx.fine = call {{.*}} <3 x half> @llvm.dx.ddx.fine.v3f16(<3 x half> %{{.*}}) +// CHECK: ret <3 x half> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <3 x half> @_Z18test_f16_ddx_fine3Dv3_Dh +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <3 x half> @llvm.spv.ddx.fine.v3f16(<3 x half> %{{.*}}) +// CHECK-SPIRV: ret <3 x half> %hlsl.ddx.fine +half3 test_f16_ddx_fine3(half3 val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <4 x half> @_Z18test_f16_ddx_fine4Dv4_Dh +// CHECK: %hlsl.ddx.fine = call {{.*}} <4 x half> @llvm.dx.ddx.fine.v4f16(<4 x half> %{{.*}}) +// CHECK: ret <4 x half> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <4 x half> @_Z18test_f16_ddx_fine4Dv4_Dh +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <4 x half> @llvm.spv.ddx.fine.v4f16(<4 x half> %{{.*}}) +// CHECK-SPIRV: ret <4 x half> %hlsl.ddx.fine +half4 test_f16_ddx_fine4(half4 val) { + return ddx_fine(val); +} + +// CHECK-LABEL: float @_Z17test_f32_ddx_finef +// CHECK: %hlsl.ddx.fine = call {{.*}} float @llvm.dx.ddx.fine.f32(float %{{.*}}) +// CHECK: ret float %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: float @_Z17test_f32_ddx_finef +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} float @llvm.spv.ddx.fine.f32(float %{{.*}}) +// CHECK-SPIRV: ret float %hlsl.ddx.fine +float test_f32_ddx_fine(float val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <2 x float> @_Z18test_f32_ddx_fine2Dv2_f +// CHECK: %hlsl.ddx.fine = call {{.*}} <2 x float> @llvm.dx.ddx.fine.v2f32(<2 x float> %{{.*}}) +// CHECK: ret <2 x float> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <2 x float> @_Z18test_f32_ddx_fine2Dv2_f +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <2 x float> @llvm.spv.ddx.fine.v2f32(<2 x float> %{{.*}}) +// CHECK-SPIRV: ret <2 x float> %hlsl.ddx.fine +float2 test_f32_ddx_fine2(float2 val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <3 x float> @_Z18test_f32_ddx_fine3Dv3_f +// CHECK: %hlsl.ddx.fine = call {{.*}} <3 x float> @llvm.dx.ddx.fine.v3f32(<3 x float> %{{.*}}) +// CHECK: ret <3 x float> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <3 x float> @_Z18test_f32_ddx_fine3Dv3_f +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <3 x float> @llvm.spv.ddx.fine.v3f32(<3 x float> %{{.*}}) +// CHECK-SPIRV: ret <3 x float> %hlsl.ddx.fine +float3 test_f32_ddx_fine3(float3 val) { + return ddx_fine(val); +} + +// CHECK-LABEL: <4 x float> @_Z18test_f32_ddx_fine4Dv4_f +// CHECK: %hlsl.ddx.fine = call {{.*}} <4 x float> @llvm.dx.ddx.fine.v4f32(<4 x float> %{{.*}}) +// CHECK: ret <4 x float> %hlsl.ddx.fine +// CHECK-LABEL-SPIRV: <4 x float> @_Z18test_f32_ddx_fine4Dv4_f +// CHECK-SPIRV: %hlsl.ddx.fine = call {{.*}} <4 x float> @llvm.spv.ddx.fine.v4f32(<4 x float> %{{.*}}) +// CHECK-SPIRV: ret <4 x float> %hlsl.ddx.fine +float4 test_f32_ddx_fine4(float4 val) { + return ddx_fine(val); +} diff --git a/clang/test/CodeGenHLSL/builtins/ddy-fine-builtin.hlsl b/clang/test/CodeGenHLSL/builtins/ddy-fine-builtin.hlsl new file mode 100644 index 0000000000000..00630721ceb66 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/ddy-fine-builtin.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-compute %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV + +// CHECK-LABEL: half @_Z17test_f16_ddy_fineDh +// CHECK: %hlsl.ddy.fine = call {{.*}} half @llvm.dx.ddy.fine.f16(half %{{.*}}) +// CHECK: ret half %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: half @_Z17test_f16_ddy_fineDh +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} half @llvm.spv.ddy.fine.f16(half %{{.*}}) +// CHECK-SPIRV: ret half %hlsl.ddy.fine +half test_f16_ddy_fine(half val) { + return __builtin_hlsl_elementwise_ddy_fine(val); +} + +// CHECK-LABEL: float @_Z17test_f32_ddy_finef +// CHECK: %hlsl.ddy.fine = call {{.*}} float @llvm.dx.ddy.fine.f32(float %{{.*}}) +// CHECK: ret float %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: float @_Z17test_f32_ddy_finef +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} float @llvm.spv.ddy.fine.f32(float %{{.*}}) +// CHECK-SPIRV: ret float %hlsl.ddy.fine +float test_f32_ddy_fine(float val) { + return __builtin_hlsl_elementwise_ddy_fine(val); +} diff --git a/clang/test/CodeGenHLSL/builtins/ddy-fine.hlsl b/clang/test/CodeGenHLSL/builtins/ddy-fine.hlsl new file mode 100644 index 0000000000000..7e32ee29e767d --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/ddy-fine.hlsl @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK +// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-compute %s \ +// RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK-SPIRV + +// CHECK-LABEL: half @_Z17test_f16_ddy_fineDh +// CHECK: %hlsl.ddy.fine = call {{.*}} half @llvm.dx.ddy.fine.f16(half %{{.*}}) +// CHECK: ret half %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: half @_Z17test_f16_ddy_fineDh +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} half @llvm.spv.ddy.fine.f16(half %{{.*}}) +// CHECK-SPIRV: ret half %hlsl.ddy.fine +half test_f16_ddy_fine(half val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <2 x half> @_Z18test_f16_ddy_fine2Dv2_Dh +// CHECK: %hlsl.ddy.fine = call {{.*}} <2 x half> @llvm.dx.ddy.fine.v2f16(<2 x half> %{{.*}}) +// CHECK: ret <2 x half> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <2 x half> @_Z18test_f16_ddy_fine2Dv2_Dh +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <2 x half> @llvm.spv.ddy.fine.v2f16(<2 x half> %{{.*}}) +// CHECK-SPIRV: ret <2 x half> %hlsl.ddy.fine +half2 test_f16_ddy_fine2(half2 val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <3 x half> @_Z18test_f16_ddy_fine3Dv3_Dh +// CHECK: %hlsl.ddy.fine = call {{.*}} <3 x half> @llvm.dx.ddy.fine.v3f16(<3 x half> %{{.*}}) +// CHECK: ret <3 x half> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <3 x half> @_Z18test_f16_ddy_fine3Dv3_Dh +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <3 x half> @llvm.spv.ddy.fine.v3f16(<3 x half> %{{.*}}) +// CHECK-SPIRV: ret <3 x half> %hlsl.ddy.fine +half3 test_f16_ddy_fine3(half3 val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <4 x half> @_Z18test_f16_ddy_fine4Dv4_Dh +// CHECK: %hlsl.ddy.fine = call {{.*}} <4 x half> @llvm.dx.ddy.fine.v4f16(<4 x half> %{{.*}}) +// CHECK: ret <4 x half> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <4 x half> @_Z18test_f16_ddy_fine4Dv4_Dh +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <4 x half> @llvm.spv.ddy.fine.v4f16(<4 x half> %{{.*}}) +// CHECK-SPIRV: ret <4 x half> %hlsl.ddy.fine +half4 test_f16_ddy_fine4(half4 val) { + return ddy_fine(val); +} + +// CHECK-LABEL: float @_Z17test_f32_ddy_finef +// CHECK: %hlsl.ddy.fine = call {{.*}} float @llvm.dx.ddy.fine.f32(float %{{.*}}) +// CHECK: ret float %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: float @_Z17test_f32_ddy_finef +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} float @llvm.spv.ddy.fine.f32(float %{{.*}}) +// CHECK-SPIRV: ret float %hlsl.ddy.fine +float test_f32_ddy_fine(float val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <2 x float> @_Z18test_f32_ddy_fine2Dv2_f +// CHECK: %hlsl.ddy.fine = call {{.*}} <2 x float> @llvm.dx.ddy.fine.v2f32(<2 x float> %{{.*}}) +// CHECK: ret <2 x float> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <2 x float> @_Z18test_f32_ddy_fine2Dv2_f +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <2 x float> @llvm.spv.ddy.fine.v2f32(<2 x float> %{{.*}}) +// CHECK-SPIRV: ret <2 x float> %hlsl.ddy.fine +float2 test_f32_ddy_fine2(float2 val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <3 x float> @_Z18test_f32_ddy_fine3Dv3_f +// CHECK: %hlsl.ddy.fine = call {{.*}} <3 x float> @llvm.dx.ddy.fine.v3f32(<3 x float> %{{.*}}) +// CHECK: ret <3 x float> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <3 x float> @_Z18test_f32_ddy_fine3Dv3_f +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <3 x float> @llvm.spv.ddy.fine.v3f32(<3 x float> %{{.*}}) +// CHECK-SPIRV: ret <3 x float> %hlsl.ddy.fine +float3 test_f32_ddy_fine3(float3 val) { + return ddy_fine(val); +} + +// CHECK-LABEL: <4 x float> @_Z18test_f32_ddy_fine4Dv4_f +// CHECK: %hlsl.ddy.fine = call {{.*}} <4 x float> @llvm.dx.ddy.fine.v4f32(<4 x float> %{{.*}}) +// CHECK: ret <4 x float> %hlsl.ddy.fine +// CHECK-LABEL-SPIRV: <4 x float> @_Z18test_f32_ddy_fine4Dv4_f +// CHECK-SPIRV: %hlsl.ddy.fine = call {{.*}} <4 x float> @llvm.spv.ddy.fine.v4f32(<4 x float> %{{.*}}) +// CHECK-SPIRV: ret <4 x float> %hlsl.ddy.fine +float4 test_f32_ddy_fine4(float4 val) { + return ddy_fine(val); +} diff --git a/clang/test/SemaHLSL/BuiltIns/ddx-fine-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/ddx-fine-errors.hlsl new file mode 100644 index 0000000000000..71196943c322a --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ddx-fine-errors.hlsl @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -verify +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library %s -fnative-half-type -verify + +float no_arg() { + return __builtin_hlsl_elementwise_ddx_fine(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +float too_many_args(float val) { + return __builtin_hlsl_elementwise_ddx_fine(val, val); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +float test_integer_scalar_input(int val) { + return __builtin_hlsl_elementwise_ddx_fine(val); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int')}} +} + +double test_double_scalar_input(double val) { + return __builtin_hlsl_elementwise_ddx_fine(val); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'double')}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/ddy-fine-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/ddy-fine-errors.hlsl new file mode 100644 index 0000000000000..e17d5f36832b2 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ddy-fine-errors.hlsl @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -verify +// RUN: %clang_cc1 -triple spirv-unknown-vulkan1.3-library %s -fnative-half-type -verify + +float no_arg() { + return __builtin_hlsl_elementwise_ddy_fine(); + // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} +} + +float too_many_args(float val) { + return __builtin_hlsl_elementwise_ddy_fine(val, val); + // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} +} + +float test_integer_scalar_input(int val) { + return __builtin_hlsl_elementwise_ddy_fine(val); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'int')}} +} + +double test_double_scalar_input(double val) { + return __builtin_hlsl_elementwise_ddy_fine(val); + // expected-error@-1 {{1st argument must be a scalar or vector of 16 or 32 bit floating-point types (was 'double')}} +} diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 485a49b16e2d2..8ca93731ffa04 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -172,6 +172,8 @@ def int_dx_radians : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0> def int_dx_discard : DefaultAttrsIntrinsic<[], [llvm_i1_ty], []>; def int_dx_ddx_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; def int_dx_ddy_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; +def int_dx_ddx_fine : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; +def int_dx_ddy_fine : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; def int_dx_firstbituhigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; def int_dx_firstbitshigh : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; def int_dx_firstbitlow : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_anyint_ty], [IntrNoMem]>; diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 366f8cf36d75c..552cc0aa59d77 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -136,6 +136,8 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] def int_spv_discard : DefaultAttrsIntrinsic<[], [], []>; def int_spv_ddx_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; def int_spv_ddy_coarse : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; + def int_spv_ddx_fine : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; + def int_spv_ddy_fine : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; def int_spv_fwidth : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>; def int_spv_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; def int_spv_sclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>; diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index 8b2866260e9c9..b221fa2d7fe87 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -948,6 +948,24 @@ def DerivCoarseY : DXILOp<84, unary> { let stages = [Stages<DXIL1_0, [library, pixel]>]; } +def DerivFineX : DXILOp<85, unary> { + let Doc = "computes the rate of change per stamp in x direction"; + let intrinsics = [IntrinSelect<int_dx_ddx_fine>]; + let arguments = [OverloadTy]; + let result = OverloadTy; + let overloads = [Overloads<DXIL1_0, [HalfTy, FloatTy]>]; + let stages = [Stages<DXIL1_0, [library, pixel]>]; +} + +def DerivFineY : DXILOp<86, unary> { + let Doc = "computes the rate of change per stamp in y direction"; + let intrinsics = [IntrinSelect<int_dx_ddy_fine>]; + let arguments = [OverloadTy]; + let result = OverloadTy; + let overloads = [Overloads<DXIL1_0, [HalfTy, FloatTy]>]; + let stages = [Stages<DXIL1_0, [library, pixel]>]; +} + def ThreadId : DXILOp<93, threadId> { let Doc = "Reads the thread ID"; let intrinsics = [IntrinSelect<int_dx_thread_id>]; diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp index a755dd522969d..f54b48b91265e 100644 --- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp +++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp @@ -66,6 +66,8 @@ bool DirectXTTIImpl::isTargetIntrinsicTriviallyScalarizable( case Intrinsic::dx_umad: case Intrinsic::dx_ddx_coarse: case Intrinsic::dx_ddy_coarse: + case Intrinsic::dx_ddx_fine: + case Intrinsic::dx_ddy_fine: return true; default: return false; diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index d3fc08eb56cb3..1599d72254f79 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -3586,6 +3586,10 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse); case Intrinsic::spv_ddy_coarse: return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse); + case Intrinsic::spv_ddx_fine: + return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxFine); + case Intrinsic::spv_ddy_fine: + return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyFine); case Intrinsic::spv_fwidth: return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth); default: { diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index bd754d17694b8..d1608f9790beb 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -2150,7 +2150,9 @@ void addInstrRequirements(const MachineInstr &MI, break; } case SPIRV::OpDPdxCoarse: - case SPIRV::OpDPdyCoarse: { + case SPIRV::OpDPdyCoarse: + case SPIRV::OpDPdxFine: + case SPIRV::OpDPdyFine: { Reqs.addCapability(SPIRV::Capability::DerivativeControl); break; } diff --git a/llvm/test/CodeGen/DirectX/ddx_fine-errors.ll b/llvm/test/CodeGen/DirectX/ddx_fine-errors.ll new file mode 100644 index 0000000000000..c7c58599b47b4 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ddx_fine-errors.ll @@ -0,0 +1,29 @@ +; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck --check-prefixes=CHECK-TYPE %s +; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-compute %s 2>&1 | FileCheck --check-prefixes=CHECK-STAGE %s + +; DXIL operation ddx.fine does not support double overload type +; CHECK-TYPE: in function ddx.fine +; CHECK-TYPE-SAME: Cannot create DerivFineX operation: Invalid overload type + +; Function Attrs: noinline nounwind optnone +define noundef double @ddx.fine_double(double noundef %a) #0 { +entry: + %a.addr = alloca double, align 8 + store double %a, ptr %a.addr, align 8 + %0 = load double, ptr %a.addr, align 8 + %dx.ddx.fine = call double @llvm.dx.ddx.fine.f64(double %0) + ret double %dx.ddx.fine +} + +; DXIL operation ddx.fine does not support compute shader stage +; CHECK-STAGE: in function ddx.fine +; CHECK-STAGE-SAME: Cannot create DerivFineX operation: Invalid stage +; Function Attrs: noinline nounwind optnone +define noundef float @ddx.fine_float(float noundef %a) #0 { +entry: + %a.addr = alloca float, align 8 + store float %a, ptr %a.addr, align 8 + %0 = load float, ptr %a.addr, align 8 + %dx.ddx.fine = call float @llvm.dx.ddx.fine.f32(float %0) + ret float %dx.ddx.fine +} diff --git a/llvm/test/CodeGen/DirectX/ddx_fine.ll b/llvm/test/CodeGen/DirectX/ddx_fine.ll new file mode 100644 index 0000000000000..b00df1572e083 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ddx_fine.ll @@ -0,0 +1,40 @@ +; RUN: opt -S -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s + +; Make sure dxil operation function calls for ddx_fine are generated for half/float and matching vectors + +define noundef half @deriv_fine_x_half(half noundef %a) { +; CHECK: call half @dx.op.unary.f16(i32 85, half %{{.*}}) +entry: + %dx.ddx.fine = call half @llvm.dx.ddx.fine.f16(half %a) + ret half %dx.ddx.fine +} + +define noundef float @deriv_fine_x_float(float noundef %a) { +; CHECK: call float @dx.op.unary.f32(i32 85, float %{{.*}}) +entry: + %dx.ddx.fine = call float @llvm.dx.ddx.fine.f32(float %a) + ret float %dx.ddx.fine +} + +define noundef <4 x float> @deriv_fine_x_float4(<4 x float> noundef %a) { +; CHECK: [[ee0:%.*]] = extractelement <4 x float> %a, i64 0 +; CHECK: [[ie0:%.*]] = call float @dx.op.unary.f32(i32 85, float [[ee0]]) +; CHECK: [[ee1:%.*]] = extractelement <4 x float> %a, i64 1 +; CHECK: [[ie1:%.*]] = call float @dx.op.unary.f32(i32 85, float [[ee1]]) +; CHECK: [[ee2:%.*]] = extractelement <4 x float> %a, i64 2 +; CHECK: [[ie2:%.*]] = call float @dx.op.unary.f32(i32 85, float [[ee2]]) +; CHECK: [[ee3:%.*]] = extractelement <4 x float> %a, i64 3 +; CHECK: [[ie3:%.*]] = call float @dx.op.unary.f32(i32 85, float [[ee3]]) +; CHECK: insertelement <4 x float> poison, float [[ie0]], i64 0 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie1]], i64 1 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie2]], i64 2 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie3]], i64 3 +; CHECK: ret <4 x float> %{{.*}} +entry: + %dx.ddx.fine = call <4 x float> @llvm.dx.ddx.fine.v4f32(<4 x float> %a) + ret <4 x float> %dx.ddx.fine +} + +declare half @llvm.dx.ddx.fine.f16(half) +declare float @llvm.dx.ddx.fine.f32(float) +declare <4 x float> @llvm.dx.ddx.fine.v4f32(<4 x float>) diff --git a/llvm/test/CodeGen/DirectX/ddy_fine-errors.ll b/llvm/test/CodeGen/DirectX/ddy_fine-errors.ll new file mode 100644 index 0000000000000..f92ca2a314d4c --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ddy_fine-errors.ll @@ -0,0 +1,29 @@ +; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck --check-prefixes=CHECK-TYPE %s +; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-compute %s 2>&1 | FileCheck --check-prefixes=CHECK-STAGE %s + +; DXIL operation ddy.fine does not support double overload type +; CHECK-TYPE: in function ddy.fine +; CHECK-TYPE-SAME: Cannot create DerivFineY operation: Invalid overload type + +; Function Attrs: noinline nounwind optnone +define noundef double @ddy.fine_double(double noundef %a) #0 { +entry: + %a.addr = alloca double, align 8 + store double %a, ptr %a.addr, align 8 + %0 = load double, ptr %a.addr, align 8 + %dx.ddy.fine = call double @llvm.dx.ddy.fine.f64(double %0) + ret double %dx.ddy.fine +} + +; DXIL operation ddy.fine does not support compute shader stage +; CHECK-STAGE: in function ddy.fine +; CHECK-STAGE-SAME: Cannot create DerivFineY operation: Invalid stage +; Function Attrs: noinline nounwind optnone +define noundef float @ddy.fine_float(float noundef %a) #0 { +entry: + %a.addr = alloca float, align 8 + store float %a, ptr %a.addr, align 8 + %0 = load float, ptr %a.addr, align 8 + %dx.ddy.fine = call float @llvm.dx.ddy.fine.f32(float %0) + ret float %dx.ddy.fine +} diff --git a/llvm/test/CodeGen/DirectX/ddy_fine.ll b/llvm/test/CodeGen/DirectX/ddy_fine.ll new file mode 100644 index 0000000000000..e6c0da2c2c568 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ddy_fine.ll @@ -0,0 +1,40 @@ +; RUN: opt -S -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s + +; Make sure dxil operation function calls for ddy_fine are generated for half/float and matching vectors + +define noundef half @deriv_fine_y_half(half noundef %a) { +; CHECK: call half @dx.op.unary.f16(i32 86, half %{{.*}}) +entry: + %dx.ddy.fine = call half @llvm.dx.ddy.fine.f16(half %a) + ret half %dx.ddy.fine +} + +define noundef float @deriv_fine_y_float(float noundef %a) { +; CHECK: call float @dx.op.unary.f32(i32 86, float %{{.*}}) +entry: + %dx.ddy.fine = call float @llvm.dx.ddy.fine.f32(float %a) + ret float %dx.ddy.fine +} + +define noundef <4 x float> @deriv_fine_y_float4(<4 x float> noundef %a) { +; CHECK: [[ee0:%.*]] = extractelement <4 x float> %a, i64 0 +; CHECK: [[ie0:%.*]] = call float @dx.op.unary.f32(i32 86, float [[ee0]]) +; CHECK: [[ee1:%.*]] = extractelement <4 x float> %a, i64 1 +; CHECK: [[ie1:%.*]] = call float @dx.op.unary.f32(i32 86, float [[ee1]]) +; CHECK: [[ee2:%.*]] = extractelement <4 x float> %a, i64 2 +; CHECK: [[ie2:%.*]] = call float @dx.op.unary.f32(i32 86, float [[ee2]]) +; CHECK: [[ee3:%.*]] = extractelement <4 x float> %a, i64 3 +; CHECK: [[ie3:%.*]] = call float @dx.op.unary.f32(i32 86, float [[ee3]]) +; CHECK: insertelement <4 x float> poison, float [[ie0]], i64 0 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie1]], i64 1 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie2]], i64 2 +; CHECK: insertelement <4 x float> %{{.*}}, float [[ie3]], i64 3 +; CHECK: ret <4 x float> %{{.*}} +entry: + %dx.ddy.fine = call <4 x float> @llvm.dx.ddy.fine.v4f32(<4 x float> %a) + ret <4 x float> %dx.ddy.fine +} + +declare half @llvm.dx.ddy.fine.f16(half) +declare float @llvm.dx.ddy.fine.f32(float) +declare <4 x float> @llvm.dx.ddy.fine.v4f32(<4 x float>) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddx_fine.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddx_fine.ll new file mode 100644 index 0000000000000..bba4612a05f52 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddx_fine.ll @@ -0,0 +1,47 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val --target-env spv1.4 %} + +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 + +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 + +define noundef float @ddx_fine_float(float noundef %a) { +entry: +; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]] +; CHECK: %[[#]] = OpDPdxFine %[[#float_32]] %[[#float_32_arg]] + %elt.ddx.fine = call float @llvm.spv.ddx.fine.f32(float %a) + ret float %elt.ddx.fine +} + +define noundef half @ddx_fine_half(half noundef %a) { +entry: +; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]] +; CHECK: %[[#converted:]] = OpFConvert %[[#float_32:]] %[[#float_16_arg]] +; CHECK: %[[#fine:]] = OpDPdxFine %[[#float_32]] %[[#converted]] +; CHECK: %[[#]] = OpFConvert %[[#float_16]] %[[#fine]] + %elt.ddx.fine = call half @llvm.spv.ddx.fine.f16(half %a) + ret half %elt.ddx.fine +} + +define noundef <4 x float> @ddx_fine_float_vector(<4 x float> noundef %a) { +entry: +; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]] +; CHECK: %[[#]] = OpDPdxFine %[[#vec4_float_32]] %[[#vec4_float_32_arg]] + %elt.ddx.fine = call <4 x float> @llvm.spv.ddx.fine.v4f32(<4 x float> %a) + ret <4 x float> %elt.ddx.fine +} + +define noundef <4 x half> @ddx_fine_half_vector(<4 x half> noundef %a) { +entry: +; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]] +; CHECK: %[[#converted:]] = OpFConvert %[[#vec4_float_32:]] %[[#vec4_float_16_arg]] +; CHECK: %[[#fine:]] = OpDPdxFine %[[#vec4_float_32]] %[[#converted]] +; CHECK: %[[#]] = OpFConvert %[[#vec4_float_16]] %[[#fine]] + %elt.ddx.fine = call <4 x half> @llvm.spv.ddx.fine.v4f16(<4 x half> %a) + ret <4 x half> %elt.ddx.fine +} + +declare float @llvm.spv.ddx.fine.f32(float) +declare half @llvm.spv.ddx.fine.f16(half) diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddy_fine.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddy_fine.ll new file mode 100644 index 0000000000000..a5609de03bfd8 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/ddy_fine.ll @@ -0,0 +1,47 @@ +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val --target-env spv1.4 %} + +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 + +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 + +define noundef float @ddy_fine_float(float noundef %a) { +entry: +; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]] +; CHECK: %[[#]] = OpDPdyFine %[[#float_32]] %[[#float_32_arg]] + %elt.ddy.fine = call float @llvm.spv.ddy.fine.f32(float %a) + ret float %elt.ddy.fine +} + +define noundef half @ddy_fine_half(half noundef %a) { +entry: +; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]] +; CHECK: %[[#converted:]] = OpFConvert %[[#float_32:]] %[[#float_16_arg]] +; CHECK: %[[#fine:]] = OpDPdyFine %[[#float_32]] %[[#converted]] +; CHECK: %[[#]] = OpFConvert %[[#float_16]] %[[#fine]] + %elt.ddy.fine = call half @llvm.spv.ddy.fine.f16(half %a) + ret half %elt.ddy.fine +} + +define noundef <4 x float> @ddy_fine_float_vector(<4 x float> noundef %a) { +entry: +; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]] +; CHECK: %[[#]] = OpDPdyFine %[[#vec4_float_32]] %[[#vec4_float_32_arg]] + %elt.ddy.fine = call <4 x float> @llvm.spv.ddy.fine.v4f32(<4 x float> %a) + ret <4 x float> %elt.ddy.fine +} + +define noundef <4 x half> @ddy_fine_half_vector(<4 x half> noundef %a) { +entry: +; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]] +; CHECK: %[[#converted:]] = OpFConvert %[[#vec4_float_32:]] %[[#vec4_float_16_arg]] +; CHECK: %[[#fine:]] = OpDPdyFine %[[#vec4_float_32]] %[[#converted]] +; CHECK: %[[#]] = OpFConvert %[[#vec4_float_16]] %[[#fine]] + %elt.ddy.fine = call <4 x half> @llvm.spv.ddy.fine.v4f16(<4 x half> %a) + ret <4 x half> %elt.ddy.fine +} + +declare float @llvm.spv.ddy.fine.f32(float) +declare half @llvm.spv.ddy.fine.f16(half) diff --git a/llvm/test/CodeGen/SPIRV/opencl/ddx_fine-error.ll b/llvm/test/CodeGen/SPIRV/opencl/ddx_fine-error.ll new file mode 100644 index 0000000000000..88ac0f594cb5d --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/opencl/ddx_fine-error.ll @@ -0,0 +1,12 @@ +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: LLVM ERROR: %{{.*}} = G_INTRINSIC intrinsic(@llvm.spv.ddx.fine), %{{.*}} is only supported in shaders. + +define noundef float @ddx_fine(float noundef %a) { +entry: + %spv.ddx.fine = call float @llvm.spv.ddx.fine.f32(float %a) + ret float %spv.ddx.fine +} + +declare float @llvm.spv.ddx.fine.f32(float) diff --git a/llvm/test/CodeGen/SPIRV/opencl/ddy_fine-error.ll b/llvm/test/CodeGen/SPIRV/opencl/ddy_fine-error.ll new file mode 100644 index 0000000000000..f1353d2fc59bc --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/opencl/ddy_fine-error.ll @@ -0,0 +1,12 @@ +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: LLVM ERROR: %{{.*}} = G_INTRINSIC intrinsic(@llvm.spv.ddy.fine), %{{.*}} is only supported in shaders. + +define noundef float @ddy_fine(float noundef %a) { +entry: + %spv.ddy.fine = call float @llvm.spv.ddy.fine.f32(float %a) + ret float %spv.ddy.fine +} + +declare float @llvm.spv.ddy.fine.f32(float) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
