[ir] Polyfill fwidthFine for MSL and HLSL

Compute the result using `dpdxFine` and `dpdyFine` to get the required
behavior.

Bug: 42251016
Change-Id: I30f072ca9a9e98d8575d5d74c6b89d88456de044
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/205497
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.cc b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
index cc75570..bb2c09e 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
@@ -105,6 +105,11 @@
                             worklist.Push(builtin);
                         }
                         break;
+                    case core::BuiltinFn::kFwidthFine:
+                        if (config.fwidth_fine) {
+                            worklist.Push(builtin);
+                        }
+                        break;
                     case core::BuiltinFn::kInsertBits:
                         if (config.insert_bits != BuiltinPolyfillLevel::kNone) {
                             worklist.Push(builtin);
@@ -183,6 +188,9 @@
                 case core::BuiltinFn::kFirstTrailingBit:
                     FirstTrailingBit(builtin);
                     break;
+                case core::BuiltinFn::kFwidthFine:
+                    FwidthFine(builtin);
+                    break;
                 case core::BuiltinFn::kInsertBits:
                     InsertBits(builtin);
                     break;
@@ -528,6 +536,22 @@
         call->Destroy();
     }
 
+    /// Polyfill a `fwidthFine()` builtin call.
+    /// @param call the builtin call instruction
+    void FwidthFine(ir::CoreBuiltinCall* call) {
+        auto* value = call->Args()[0];
+        auto* type = value->Type();
+        b.InsertBefore(call, [&] {
+            auto* dpdx = b.Call(type, core::BuiltinFn::kDpdxFine, value);
+            auto* dpdy = b.Call(type, core::BuiltinFn::kDpdyFine, value);
+            auto* abs_dpdx = b.Call(type, core::BuiltinFn::kAbs, dpdx);
+            auto* abs_dpdy = b.Call(type, core::BuiltinFn::kAbs, dpdy);
+            auto* result = b.Add(type, abs_dpdx, abs_dpdy);
+            call->Result(0)->ReplaceAllUsesWith(result->Result(0));
+        });
+        call->Destroy();
+    }
+
     /// Polyfill an `insertBits()` builtin call.
     /// @param call the builtin call instruction
     void InsertBits(ir::CoreBuiltinCall* call) {
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.h b/src/tint/lang/core/ir/transform/builtin_polyfill.h
index 482af64..acab62a 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.h
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.h
@@ -66,6 +66,8 @@
     bool first_leading_bit = false;
     /// Should `firstTrailingBit()` be polyfilled?
     bool first_trailing_bit = false;
+    /// Should `fwidthFine()` be polyfilled?
+    bool fwidth_fine = false;
     /// How should `insertBits()` be polyfilled?
     BuiltinPolyfillLevel insert_bits = BuiltinPolyfillLevel::kNone;
     /// Should `radians()` be polyfilled?
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc b/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
index 7e02718..6aec3b2 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
@@ -1340,6 +1340,88 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(IR_BuiltinPolyfillTest, FwidthFine_NoPolyfill) {
+    Build(core::BuiltinFn::kFwidthFine, ty.f32(), Vector{ty.f32()});
+    auto* src = R"(
+%foo = func(%arg:f32):f32 {
+  $B1: {
+    %result:f32 = fwidthFine %arg
+    ret %result
+  }
+}
+)";
+    auto* expect = src;
+
+    EXPECT_EQ(src, str());
+
+    BuiltinPolyfillConfig config;
+    config.fwidth_fine = false;
+    Run(BuiltinPolyfill, config);
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_F32) {
+    Build(core::BuiltinFn::kFwidthFine, ty.f32(), Vector{ty.f32()});
+    auto* src = R"(
+%foo = func(%arg:f32):f32 {
+  $B1: {
+    %result:f32 = fwidthFine %arg
+    ret %result
+  }
+}
+)";
+    auto* expect = R"(
+%foo = func(%arg:f32):f32 {
+  $B1: {
+    %3:f32 = dpdxFine %arg
+    %4:f32 = dpdyFine %arg
+    %5:f32 = abs %3
+    %6:f32 = abs %4
+    %7:f32 = add %5, %6
+    ret %7
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    BuiltinPolyfillConfig config;
+    config.fwidth_fine = true;
+    Run(BuiltinPolyfill, config);
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_Vector) {
+    Build(core::BuiltinFn::kFwidthFine, ty.vec4<f32>(), Vector{ty.vec4<f32>()});
+    auto* src = R"(
+%foo = func(%arg:vec4<f32>):vec4<f32> {
+  $B1: {
+    %result:vec4<f32> = fwidthFine %arg
+    ret %result
+  }
+}
+)";
+    auto* expect = R"(
+%foo = func(%arg:vec4<f32>):vec4<f32> {
+  $B1: {
+    %3:vec4<f32> = dpdxFine %arg
+    %4:vec4<f32> = dpdyFine %arg
+    %5:vec4<f32> = abs %3
+    %6:vec4<f32> = abs %4
+    %7:vec4<f32> = add %5, %6
+    ret %7
+  }
+}
+)";
+
+    EXPECT_EQ(src, str());
+
+    BuiltinPolyfillConfig config;
+    config.fwidth_fine = true;
+    Run(BuiltinPolyfill, config);
+    EXPECT_EQ(expect, str());
+}
+
 TEST_F(IR_BuiltinPolyfillTest, InsertBits_NoPolyfill) {
     Build(core::BuiltinFn::kInsertBits, ty.u32(), Vector{ty.u32(), ty.u32(), ty.u32(), ty.u32()});
     auto* src = R"(
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index 8420226..2b21e41 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -977,7 +977,6 @@
                 break;
             case core::BuiltinFn::kFwidth:
             case core::BuiltinFn::kFwidthCoarse:
-            case core::BuiltinFn::kFwidthFine:
                 out << "fwidth";
                 break;
             case core::BuiltinFn::kInverseSqrt:
diff --git a/src/tint/lang/hlsl/writer/raise/raise.cc b/src/tint/lang/hlsl/writer/raise/raise.cc
index 75564ee..607fcd43 100644
--- a/src/tint/lang/hlsl/writer/raise/raise.cc
+++ b/src/tint/lang/hlsl/writer/raise/raise.cc
@@ -109,7 +109,7 @@
         core_polyfills.extract_bits = core::ir::transform::BuiltinPolyfillLevel::kFull;
         core_polyfills.first_leading_bit = true;
         core_polyfills.first_trailing_bit = true;
-        // core_polyfills.fwidth_fine = true;
+        core_polyfills.fwidth_fine = true;
         core_polyfills.insert_bits = core::ir::transform::BuiltinPolyfillLevel::kFull;
         // core_polyfills.int_div_mod = !options.disable_polyfill_integer_div_mod;
 
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 4311e2b..e053fa0 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -1005,7 +1005,6 @@
                 break;
             case core::BuiltinFn::kFwidth:
             case core::BuiltinFn::kFwidthCoarse:
-            case core::BuiltinFn::kFwidthFine:
                 out << "fwidth";
                 break;
             case core::BuiltinFn::kFaceForward:
diff --git a/src/tint/lang/msl/writer/raise/raise.cc b/src/tint/lang/msl/writer/raise/raise.cc
index 21cb674..51506b3 100644
--- a/src/tint/lang/msl/writer/raise/raise.cc
+++ b/src/tint/lang/msl/writer/raise/raise.cc
@@ -88,6 +88,7 @@
         core_polyfills.extract_bits = core::ir::transform::BuiltinPolyfillLevel::kClampOrRangeCheck;
         core_polyfills.first_leading_bit = true;
         core_polyfills.first_trailing_bit = true;
+        core_polyfills.fwidth_fine = true;
         core_polyfills.insert_bits = core::ir::transform::BuiltinPolyfillLevel::kClampOrRangeCheck;
         core_polyfills.pack_unpack_4x8 = true;
         core_polyfills.pack_4xu8_clamp = true;
diff --git a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
index 4dbbda3..08e343b 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float3 fwidthFine_523fdc() {
-  float3 res = fwidth((1.0f).xxx);
+  float3 v = ddx_fine((1.0f).xxx);
+  float3 v_1 = ddy_fine((1.0f).xxx);
+  float3 v_2 = abs(v);
+  float3 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
index 4dbbda3..08e343b 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float3 fwidthFine_523fdc() {
-  float3 res = fwidth((1.0f).xxx);
+  float3 v = ddx_fine((1.0f).xxx);
+  float3 v_1 = ddy_fine((1.0f).xxx);
+  float3 v_2 = abs(v);
+  float3 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.msl b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.msl
index ac04891..95de91b 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/literal/fwidthFine/523fdc.wgsl.expected.ir.msl
@@ -6,7 +6,10 @@
 };
 
 float3 fwidthFine_523fdc() {
-  float3 res = fwidth(float3(1.0f));
+  float3 const v = dfdx(float3(1.0f));
+  float3 const v_1 = dfdy(float3(1.0f));
+  float3 const v_2 = abs(v);
+  float3 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
index dede8bc..ae515d1 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float4 fwidthFine_68f4ef() {
-  float4 res = fwidth((1.0f).xxxx);
+  float4 v = ddx_fine((1.0f).xxxx);
+  float4 v_1 = ddy_fine((1.0f).xxxx);
+  float4 v_2 = abs(v);
+  float4 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
index dede8bc..ae515d1 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float4 fwidthFine_68f4ef() {
-  float4 res = fwidth((1.0f).xxxx);
+  float4 v = ddx_fine((1.0f).xxxx);
+  float4 v_1 = ddy_fine((1.0f).xxxx);
+  float4 v_2 = abs(v);
+  float4 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.msl b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.msl
index 0aa4b32..ca34235 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/literal/fwidthFine/68f4ef.wgsl.expected.ir.msl
@@ -6,7 +6,10 @@
 };
 
 float4 fwidthFine_68f4ef() {
-  float4 res = fwidth(float4(1.0f));
+  float4 const v = dfdx(float4(1.0f));
+  float4 const v_1 = dfdy(float4(1.0f));
+  float4 const v_2 = abs(v);
+  float4 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
index 8fbc6a8..7bdf7bd 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float fwidthFine_f1742d() {
-  float res = fwidth(1.0f);
+  float v = ddx_fine(1.0f);
+  float v_1 = ddy_fine(1.0f);
+  float v_2 = abs(v);
+  float res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
index 8fbc6a8..7bdf7bd 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float fwidthFine_f1742d() {
-  float res = fwidth(1.0f);
+  float v = ddx_fine(1.0f);
+  float v_1 = ddy_fine(1.0f);
+  float v_2 = abs(v);
+  float res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.msl b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.msl
index ff58c9b..bc551de 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/literal/fwidthFine/f1742d.wgsl.expected.ir.msl
@@ -6,7 +6,10 @@
 };
 
 float fwidthFine_f1742d() {
-  float res = fwidth(1.0f);
+  float const v = dfdx(1.0f);
+  float const v_1 = dfdy(1.0f);
+  float const v_2 = abs(v);
+  float res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
index 5800cc7..133b56c 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float2 fwidthFine_ff6aa0() {
-  float2 res = fwidth((1.0f).xx);
+  float2 v = ddx_fine((1.0f).xx);
+  float2 v_1 = ddy_fine((1.0f).xx);
+  float2 v_2 = abs(v);
+  float2 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
index 5800cc7..133b56c 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
@@ -1,7 +1,10 @@
 
 RWByteAddressBuffer prevent_dce : register(u0);
 float2 fwidthFine_ff6aa0() {
-  float2 res = fwidth((1.0f).xx);
+  float2 v = ddx_fine((1.0f).xx);
+  float2 v_1 = ddy_fine((1.0f).xx);
+  float2 v_2 = abs(v);
+  float2 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.msl b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.msl
index 79fbf16..9ef44cb 100644
--- a/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/literal/fwidthFine/ff6aa0.wgsl.expected.ir.msl
@@ -6,7 +6,10 @@
 };
 
 float2 fwidthFine_ff6aa0() {
-  float2 res = fwidth(float2(1.0f));
+  float2 const v = dfdx(float2(1.0f));
+  float2 const v_1 = dfdy(float2(1.0f));
+  float2 const v_2 = abs(v);
+  float2 res = (v_2 + abs(v_1));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
index 0056092..59c3481 100644
--- a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.dxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float3 fwidthFine_523fdc() {
   float3 arg_0 = (1.0f).xxx;
-  float3 res = fwidth(arg_0);
+  float3 v = arg_0;
+  float3 v_1 = ddx_fine(v);
+  float3 v_2 = ddy_fine(v);
+  float3 v_3 = abs(v_1);
+  float3 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
index 0056092..59c3481 100644
--- a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.fxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float3 fwidthFine_523fdc() {
   float3 arg_0 = (1.0f).xxx;
-  float3 res = fwidth(arg_0);
+  float3 v = arg_0;
+  float3 v_1 = ddx_fine(v);
+  float3 v_2 = ddy_fine(v);
+  float3 v_3 = abs(v_1);
+  float3 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.msl b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.msl
index a016567..cdbeb4c 100644
--- a/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/var/fwidthFine/523fdc.wgsl.expected.ir.msl
@@ -7,7 +7,11 @@
 
 float3 fwidthFine_523fdc() {
   float3 arg_0 = float3(1.0f);
-  float3 res = fwidth(arg_0);
+  float3 const v = arg_0;
+  float3 const v_1 = dfdx(v);
+  float3 const v_2 = dfdy(v);
+  float3 const v_3 = abs(v_1);
+  float3 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
index bdb7b53..210f9f0 100644
--- a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.dxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float4 fwidthFine_68f4ef() {
   float4 arg_0 = (1.0f).xxxx;
-  float4 res = fwidth(arg_0);
+  float4 v = arg_0;
+  float4 v_1 = ddx_fine(v);
+  float4 v_2 = ddy_fine(v);
+  float4 v_3 = abs(v_1);
+  float4 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
index bdb7b53..210f9f0 100644
--- a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.fxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float4 fwidthFine_68f4ef() {
   float4 arg_0 = (1.0f).xxxx;
-  float4 res = fwidth(arg_0);
+  float4 v = arg_0;
+  float4 v_1 = ddx_fine(v);
+  float4 v_2 = ddy_fine(v);
+  float4 v_3 = abs(v_1);
+  float4 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.msl b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.msl
index b242169..5acbeca 100644
--- a/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/var/fwidthFine/68f4ef.wgsl.expected.ir.msl
@@ -7,7 +7,11 @@
 
 float4 fwidthFine_68f4ef() {
   float4 arg_0 = float4(1.0f);
-  float4 res = fwidth(arg_0);
+  float4 const v = arg_0;
+  float4 const v_1 = dfdx(v);
+  float4 const v_2 = dfdy(v);
+  float4 const v_3 = abs(v_1);
+  float4 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
index f040953..4adbd95 100644
--- a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.dxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float fwidthFine_f1742d() {
   float arg_0 = 1.0f;
-  float res = fwidth(arg_0);
+  float v = arg_0;
+  float v_1 = ddx_fine(v);
+  float v_2 = ddy_fine(v);
+  float v_3 = abs(v_1);
+  float res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
index f040953..4adbd95 100644
--- a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.fxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float fwidthFine_f1742d() {
   float arg_0 = 1.0f;
-  float res = fwidth(arg_0);
+  float v = arg_0;
+  float v_1 = ddx_fine(v);
+  float v_2 = ddy_fine(v);
+  float v_3 = abs(v_1);
+  float res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.msl b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.msl
index 510d8db..d933746 100644
--- a/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/var/fwidthFine/f1742d.wgsl.expected.ir.msl
@@ -7,7 +7,11 @@
 
 float fwidthFine_f1742d() {
   float arg_0 = 1.0f;
-  float res = fwidth(arg_0);
+  float const v = arg_0;
+  float const v_1 = dfdx(v);
+  float const v_2 = dfdy(v);
+  float const v_3 = abs(v_1);
+  float res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
index f22832c..30a3772 100644
--- a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.dxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float2 fwidthFine_ff6aa0() {
   float2 arg_0 = (1.0f).xx;
-  float2 res = fwidth(arg_0);
+  float2 v = arg_0;
+  float2 v_1 = ddx_fine(v);
+  float2 v_2 = ddy_fine(v);
+  float2 v_3 = abs(v_1);
+  float2 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
index f22832c..30a3772 100644
--- a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
+++ b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.fxc.hlsl
@@ -2,7 +2,11 @@
 RWByteAddressBuffer prevent_dce : register(u0);
 float2 fwidthFine_ff6aa0() {
   float2 arg_0 = (1.0f).xx;
-  float2 res = fwidth(arg_0);
+  float2 v = arg_0;
+  float2 v_1 = ddx_fine(v);
+  float2 v_2 = ddy_fine(v);
+  float2 v_3 = abs(v_1);
+  float2 res = (v_3 + abs(v_2));
   return res;
 }
 
diff --git a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.msl b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.msl
index 2257689..2d88e6c 100644
--- a/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.msl
+++ b/test/tint/builtins/gen/var/fwidthFine/ff6aa0.wgsl.expected.ir.msl
@@ -7,7 +7,11 @@
 
 float2 fwidthFine_ff6aa0() {
   float2 arg_0 = float2(1.0f);
-  float2 res = fwidth(arg_0);
+  float2 const v = arg_0;
+  float2 const v_1 = dfdx(v);
+  float2 const v_2 = dfdy(v);
+  float2 const v_3 = abs(v_1);
+  float2 res = (v_3 + abs(v_2));
   return res;
 }