[glsl][ir] Polyfill `fma`.

The `fma` instruction exists in GLSL 4.00, but not ES 3.10. So, create
an emulated version which we use in both cases for consistency.

Bug: 42251044
Change-Id: I9f158d29cdb252e61bb7d8c102cfa61a06a0b427
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/207754
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index a6583c2..8686eca 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -538,11 +538,25 @@
     /// @returns the operation
     template <typename LHS, typename RHS>
     ir::CoreBinary* Binary(BinaryOp op, const core::type::Type* type, LHS&& lhs, RHS&& rhs) {
+        return BinaryWithResult(InstructionResult(type), op, std::forward<LHS>(lhs),
+                                std::forward<RHS>(rhs));
+    }
+
+    /// Creates an op for `lhs kind rhs`
+    /// @param op the binary operator
+    /// @param result the result of the binary expression
+    /// @param lhs the left-hand-side of the operation
+    /// @param rhs the right-hand-side of the operation
+    /// @returns the operation
+    template <typename LHS, typename RHS>
+    ir::CoreBinary* BinaryWithResult(ir::InstructionResult* result,
+                                     BinaryOp op,
+                                     LHS&& lhs,
+                                     RHS&& rhs) {
         CheckForNonDeterministicEvaluation<LHS, RHS>();
         auto* lhs_val = Value(std::forward<LHS>(lhs));
         auto* rhs_val = Value(std::forward<RHS>(rhs));
-        return Append(
-            ir.CreateInstruction<ir::CoreBinary>(InstructionResult(type), op, lhs_val, rhs_val));
+        return Append(ir.CreateInstruction<ir::CoreBinary>(result, op, lhs_val, rhs_val));
     }
 
     /// Creates an op for `lhs kind rhs`
@@ -814,6 +828,17 @@
         return Add(type, std::forward<LHS>(lhs), std::forward<RHS>(rhs));
     }
 
+    /// Creates an Add operation
+    /// @param result the result
+    /// @param lhs the lhs of the add
+    /// @param rhs the rhs of the add
+    /// @returns the operation
+    template <typename LHS, typename RHS>
+    ir::CoreBinary* AddWithResult(ir::InstructionResult* result, LHS&& lhs, RHS&& rhs) {
+        return BinaryWithResult(result, BinaryOp::kAdd, std::forward<LHS>(lhs),
+                                std::forward<RHS>(rhs));
+    }
+
     /// Creates an Subtract operation
     /// @param type the result type of the expression
     /// @param lhs the lhs of the add
diff --git a/src/tint/lang/glsl/writer/builtin_test.cc b/src/tint/lang/glsl/writer/builtin_test.cc
index bec6193..45c90f3 100644
--- a/src/tint/lang/glsl/writer/builtin_test.cc
+++ b/src/tint/lang/glsl/writer/builtin_test.cc
@@ -1379,5 +1379,48 @@
 )");
 }
 
+TEST_F(GlslWriterTest, BuiltinFMA_f32) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* x = b.Splat(ty.vec3<f32>(), 1_f);
+        auto* y = b.Splat(ty.vec3<f32>(), 2_f);
+        auto* z = b.Splat(ty.vec3<f32>(), 3_f);
+
+        b.Let("x", b.Call(ty.vec3<f32>(), core::BuiltinFn::kFma, x, y, z));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+    EXPECT_EQ(output_.glsl, GlslHeader() + R"(precision highp float;
+precision highp int;
+
+void main() {
+  vec3 x = ((vec3(1.0f) * vec3(2.0f)) + vec3(3.0f));
+}
+)");
+}
+
+TEST_F(GlslWriterTest, BuiltinFMA_f16) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* x = b.Splat(ty.vec3<f16>(), 1_h);
+        auto* y = b.Splat(ty.vec3<f16>(), 2_h);
+        auto* z = b.Splat(ty.vec3<f16>(), 3_h);
+
+        b.Let("x", b.Call(ty.vec3<f16>(), core::BuiltinFn::kFma, x, y, z));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+    EXPECT_EQ(output_.glsl, GlslHeader() + R"(precision highp float;
+precision highp int;
+#extension GL_AMD_gpu_shader_half_float: require
+
+void main() {
+  f16vec3 x = ((f16vec3(1.0hf) * f16vec3(2.0hf)) + f16vec3(3.0hf));
+}
+)");
+}
+
 }  // namespace
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
index 20f7bc9..4859832 100644
--- a/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
@@ -72,6 +72,7 @@
                     case core::BuiltinFn::kAtomicLoad:
                     case core::BuiltinFn::kCountOneBits:
                     case core::BuiltinFn::kExtractBits:
+                    case core::BuiltinFn::kFma:
                     case core::BuiltinFn::kInsertBits:
                     case core::BuiltinFn::kSelect:
                     case core::BuiltinFn::kStorageBarrier:
@@ -108,6 +109,9 @@
                 case core::BuiltinFn::kExtractBits:
                     ExtractBits(call);
                     break;
+                case core::BuiltinFn::kFma:
+                    FMA(call);
+                    break;
                 case core::BuiltinFn::kInsertBits:
                     InsertBits(call);
                     break;
@@ -162,6 +166,20 @@
         call->Destroy();
     }
 
+    // There is no `fma` method in GLSL ES 3.10 so we emulate it. `fma` does exist in desktop after
+    // 4.00 but we use the emulated version to be consistent. We could use the real one on desktop
+    // if we decide too in the future.
+    void FMA(core::ir::Call* call) {
+        auto args = call->Args();
+
+        b.InsertBefore(call, [&] {
+            auto* res_ty = call->Result(0)->Type();
+            auto* mul = b.Multiply(res_ty, args[0], args[1]);
+            b.AddWithResult(call->DetachResult(), mul, args[2]);
+        });
+        call->Destroy();
+    }
+
     // GLSL `bitCount` always returns an `i32` so we need to convert it. Convert to a `bitCount`
     // call to make it clear this isn't `countOneBits`.
     void CountOneBits(core::ir::Call* call) {
diff --git a/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
index 6275cb5..d785a78 100644
--- a/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
@@ -1317,7 +1317,80 @@
 )";
 
     Run(BuiltinPolyfill);
+    EXPECT_EQ(expect, str());
+}
 
+TEST_F(GlslWriter_BuiltinPolyfillTest, FMA_f32) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* x = b.Splat(ty.vec3<f32>(), 1_f);
+        auto* y = b.Splat(ty.vec3<f32>(), 2_f);
+        auto* z = b.Splat(ty.vec3<f32>(), 3_f);
+
+        b.Let("x", b.Call(ty.vec3<f32>(), core::BuiltinFn::kFma, x, y, z));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %2:vec3<f32> = fma vec3<f32>(1.0f), vec3<f32>(2.0f), vec3<f32>(3.0f)
+    %x:vec3<f32> = let %2
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %2:vec3<f32> = mul vec3<f32>(1.0f), vec3<f32>(2.0f)
+    %3:vec3<f32> = add %2, vec3<f32>(3.0f)
+    %x:vec3<f32> = let %3
+    ret
+  }
+}
+)";
+
+    Run(BuiltinPolyfill);
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(GlslWriter_BuiltinPolyfillTest, FMA_f16) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* x = b.Splat(ty.vec3<f16>(), 1_h);
+        auto* y = b.Splat(ty.vec3<f16>(), 2_h);
+        auto* z = b.Splat(ty.vec3<f16>(), 3_h);
+
+        b.Let("x", b.Call(ty.vec3<f16>(), core::BuiltinFn::kFma, x, y, z));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %2:vec3<f16> = fma vec3<f16>(1.0h), vec3<f16>(2.0h), vec3<f16>(3.0h)
+    %x:vec3<f16> = let %2
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %2:vec3<f16> = mul vec3<f16>(1.0h), vec3<f16>(2.0h)
+    %3:vec3<f16> = add %2, vec3<f16>(3.0h)
+    %x:vec3<f16> = let %3
+    ret
+  }
+}
+)";
+
+    Run(BuiltinPolyfill);
     EXPECT_EQ(expect, str());
 }
 
diff --git a/test/tint/builtins/gen/var/fma/26a7a9.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/26a7a9.wgsl.expected.ir.glsl
index dfe42f9..63ae06b 100644
--- a/test/tint/builtins/gen/var/fma/26a7a9.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/26a7a9.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -12,21 +10,12 @@
   vec2 arg_0 = vec2(1.0f);
   vec2 arg_1 = vec2(1.0f);
   vec2 arg_2 = vec2(1.0f);
-  vec2 res = fma(arg_0, arg_1, arg_2);
+  vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_26a7a9();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:13: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 layout(binding = 0, std430)
@@ -37,22 +26,13 @@
   vec2 arg_0 = vec2(1.0f);
   vec2 arg_1 = vec2(1.0f);
   vec2 arg_2 = vec2(1.0f);
-  vec2 res = fma(arg_0, arg_1, arg_2);
+  vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_26a7a9();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:11: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:11: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 
@@ -66,7 +46,7 @@
   vec2 arg_0 = vec2(1.0f);
   vec2 arg_1 = vec2(1.0f);
   vec2 arg_2 = vec2(1.0f);
-  vec2 res = fma(arg_0, arg_1, arg_2);
+  vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -83,14 +63,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/6a3283.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/6a3283.wgsl.expected.ir.glsl
index b80ef2a..7606df7 100644
--- a/test/tint/builtins/gen/var/fma/6a3283.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/6a3283.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -12,21 +10,12 @@
   vec4 arg_0 = vec4(1.0f);
   vec4 arg_1 = vec4(1.0f);
   vec4 arg_2 = vec4(1.0f);
-  vec4 res = fma(arg_0, arg_1, arg_2);
+  vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_6a3283();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:13: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 layout(binding = 0, std430)
@@ -37,22 +26,13 @@
   vec4 arg_0 = vec4(1.0f);
   vec4 arg_1 = vec4(1.0f);
   vec4 arg_2 = vec4(1.0f);
-  vec4 res = fma(arg_0, arg_1, arg_2);
+  vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_6a3283();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:11: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:11: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 
@@ -66,7 +46,7 @@
   vec4 arg_0 = vec4(1.0f);
   vec4 arg_1 = vec4(1.0f);
   vec4 arg_2 = vec4(1.0f);
-  vec4 res = fma(arg_0, arg_1, arg_2);
+  vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -83,14 +63,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/ab7818.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/ab7818.wgsl.expected.ir.glsl
index dc39c4e..599932c 100644
--- a/test/tint/builtins/gen/var/fma/ab7818.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/ab7818.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 precision highp float;
@@ -13,21 +11,12 @@
   f16vec4 arg_0 = f16vec4(1.0hf);
   f16vec4 arg_1 = f16vec4(1.0hf);
   f16vec4 arg_2 = f16vec4(1.0hf);
-  f16vec4 res = fma(arg_0, arg_1, arg_2);
+  f16vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_ab7818();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -39,22 +28,13 @@
   f16vec4 arg_0 = f16vec4(1.0hf);
   f16vec4 arg_1 = f16vec4(1.0hf);
   f16vec4 arg_2 = f16vec4(1.0hf);
-  f16vec4 res = fma(arg_0, arg_1, arg_2);
+  f16vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_ab7818();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -69,7 +49,7 @@
   f16vec4 arg_0 = f16vec4(1.0hf);
   f16vec4 arg_1 = f16vec4(1.0hf);
   f16vec4 arg_2 = f16vec4(1.0hf);
-  f16vec4 res = fma(arg_0, arg_1, arg_2);
+  f16vec4 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -86,14 +66,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/bf21b6.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/bf21b6.wgsl.expected.ir.glsl
index 2156d76..30c986a 100644
--- a/test/tint/builtins/gen/var/fma/bf21b6.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/bf21b6.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 precision highp float;
@@ -13,21 +11,12 @@
   f16vec2 arg_0 = f16vec2(1.0hf);
   f16vec2 arg_1 = f16vec2(1.0hf);
   f16vec2 arg_2 = f16vec2(1.0hf);
-  f16vec2 res = fma(arg_0, arg_1, arg_2);
+  f16vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_bf21b6();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -39,22 +28,13 @@
   f16vec2 arg_0 = f16vec2(1.0hf);
   f16vec2 arg_1 = f16vec2(1.0hf);
   f16vec2 arg_2 = f16vec2(1.0hf);
-  f16vec2 res = fma(arg_0, arg_1, arg_2);
+  f16vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_bf21b6();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -69,7 +49,7 @@
   f16vec2 arg_0 = f16vec2(1.0hf);
   f16vec2 arg_1 = f16vec2(1.0hf);
   f16vec2 arg_2 = f16vec2(1.0hf);
-  f16vec2 res = fma(arg_0, arg_1, arg_2);
+  f16vec2 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -86,14 +66,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/c10ba3.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/c10ba3.wgsl.expected.ir.glsl
index bcc8f14..2684d06 100644
--- a/test/tint/builtins/gen/var/fma/c10ba3.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/c10ba3.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -12,21 +10,12 @@
   float arg_0 = 1.0f;
   float arg_1 = 1.0f;
   float arg_2 = 1.0f;
-  float res = fma(arg_0, arg_1, arg_2);
+  float res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_c10ba3();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:13: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 layout(binding = 0, std430)
@@ -37,22 +26,13 @@
   float arg_0 = 1.0f;
   float arg_1 = 1.0f;
   float arg_2 = 1.0f;
-  float res = fma(arg_0, arg_1, arg_2);
+  float res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_c10ba3();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:11: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:11: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 
@@ -66,7 +46,7 @@
   float arg_0 = 1.0f;
   float arg_1 = 1.0f;
   float arg_2 = 1.0f;
-  float res = fma(arg_0, arg_1, arg_2);
+  float res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -83,14 +63,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/c8abb3.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/c8abb3.wgsl.expected.ir.glsl
index c588b30..b4b458ad 100644
--- a/test/tint/builtins/gen/var/fma/c8abb3.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/c8abb3.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 precision highp float;
@@ -13,21 +11,12 @@
   float16_t arg_0 = 1.0hf;
   float16_t arg_1 = 1.0hf;
   float16_t arg_2 = 1.0hf;
-  float16_t res = fma(arg_0, arg_1, arg_2);
+  float16_t res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_c8abb3();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -39,22 +28,13 @@
   float16_t arg_0 = 1.0hf;
   float16_t arg_1 = 1.0hf;
   float16_t arg_2 = 1.0hf;
-  float16_t res = fma(arg_0, arg_1, arg_2);
+  float16_t res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_c8abb3();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -69,7 +49,7 @@
   float16_t arg_0 = 1.0hf;
   float16_t arg_1 = 1.0hf;
   float16_t arg_2 = 1.0hf;
-  float16_t res = fma(arg_0, arg_1, arg_2);
+  float16_t res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -86,14 +66,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/e17c5c.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/e17c5c.wgsl.expected.ir.glsl
index c56f9c4..d78b0ca 100644
--- a/test/tint/builtins/gen/var/fma/e17c5c.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/e17c5c.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 precision highp float;
 precision highp int;
@@ -12,21 +10,12 @@
   vec3 arg_0 = vec3(1.0f);
   vec3 arg_1 = vec3(1.0f);
   vec3 arg_2 = vec3(1.0f);
-  vec3 res = fma(arg_0, arg_1, arg_2);
+  vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_e17c5c();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:13: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:13: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 layout(binding = 0, std430)
@@ -37,22 +26,13 @@
   vec3 arg_0 = vec3(1.0f);
   vec3 arg_1 = vec3(1.0f);
   vec3 arg_2 = vec3(1.0f);
-  vec3 res = fma(arg_0, arg_1, arg_2);
+  vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_e17c5c();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:11: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:11: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 
 
@@ -66,7 +46,7 @@
   vec3 arg_0 = vec3(1.0f);
   vec3 arg_1 = vec3(1.0f);
   vec3 arg_2 = vec3(1.0f);
-  vec3 res = fma(arg_0, arg_1, arg_2);
+  vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -83,14 +63,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1
diff --git a/test/tint/builtins/gen/var/fma/e7abdc.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/fma/e7abdc.wgsl.expected.ir.glsl
index 4cfa48c..964bbd2 100644
--- a/test/tint/builtins/gen/var/fma/e7abdc.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/fma/e7abdc.wgsl.expected.ir.glsl
@@ -1,5 +1,3 @@
-SKIP: FAILED
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 precision highp float;
@@ -13,21 +11,12 @@
   f16vec3 arg_0 = f16vec3(1.0hf);
   f16vec3 arg_1 = f16vec3(1.0hf);
   f16vec3 arg_2 = f16vec3(1.0hf);
-  f16vec3 res = fma(arg_0, arg_1, arg_2);
+  f16vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 void main() {
   v.tint_symbol = fma_e7abdc();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:14: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:14: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -39,22 +28,13 @@
   f16vec3 arg_0 = f16vec3(1.0hf);
   f16vec3 arg_1 = f16vec3(1.0hf);
   f16vec3 arg_2 = f16vec3(1.0hf);
-  f16vec3 res = fma(arg_0, arg_1, arg_2);
+  f16vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
   v.tint_symbol = fma_e7abdc();
 }
-error: Error parsing GLSL shader:
-ERROR: 0:12: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:12: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
 #version 310 es
 #extension GL_AMD_gpu_shader_half_float: require
 
@@ -69,7 +49,7 @@
   f16vec3 arg_0 = f16vec3(1.0hf);
   f16vec3 arg_1 = f16vec3(1.0hf);
   f16vec3 arg_2 = f16vec3(1.0hf);
-  f16vec3 res = fma(arg_0, arg_1, arg_2);
+  f16vec3 res = ((arg_0 * arg_1) + arg_2);
   return res;
 }
 VertexOutput vertex_main_inner() {
@@ -86,14 +66,3 @@
   vertex_main_loc0_Output = v.prevent_dce;
   gl_PointSize = 1.0f;
 }
-error: Error parsing GLSL shader:
-ERROR: 0:15: 'fma' : required extension not requested: Possible extensions include:
-GL_EXT_gpu_shader5
-GL_OES_gpu_shader5
-ERROR: 0:15: '' : compilation terminated 
-ERROR: 2 compilation errors.  No code generated.
-
-
-
-
-tint executable returned error: exit status 1