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

Reply via email to