Optimize remaining simple 1-argument intrinsics.

Aside from sqrt() and normalize(), we now optimize all the intrinsics
which take a single argument as input, and return that argument with
each of its components permuted as output.

This CL also introduces a minor restriction--we no longer optimize
intrinsics which evaluate to inf or nan, such as `inversesqrt(-1)`.
These will be left in the source as-is.

Change-Id: I4919b3c18a2df81accd6daf2f650b9f587ff43fc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/406577
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/resources/sksl/intrinsics/Degrees.sksl b/resources/sksl/intrinsics/Degrees.sksl
index 5bf9504..bbd41bf 100644
--- a/resources/sksl/intrinsics/Degrees.sksl
+++ b/resources/sksl/intrinsics/Degrees.sksl
@@ -1 +1,14 @@
-uniform half a; void main() { sk_FragColor.x = degrees(a); }
+uniform half4 input, expected;
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(1.5707963268, 3.1415926536, 4.7123889804, 6.2831853072);
+    return (degrees(input.x)       == expected.x     &&
+            degrees(input.xy)      == expected.xy    &&
+            degrees(input.xyz)     == expected.xyz   &&
+            degrees(input.xyzw)    == expected.xyzw  &&
+            degrees(constVal.x)    == expected.x     &&
+            degrees(constVal.xy)   == expected.xy    &&
+            degrees(constVal.xyz)  == expected.xyz   &&
+            degrees(constVal.xyzw) == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/resources/sksl/intrinsics/Inversesqrt.sksl b/resources/sksl/intrinsics/Inversesqrt.sksl
index 50d428c..1c19d93 100644
--- a/resources/sksl/intrinsics/Inversesqrt.sksl
+++ b/resources/sksl/intrinsics/Inversesqrt.sksl
@@ -1 +1,19 @@
-uniform float a; void main() { sk_FragColor.x = half(inversesqrt(a)); }
+uniform half4 input, expected;
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(1, 4, 16, 64);
+    const half4 negativeVal = half4(-1, -4, -16, -64);  // should not optimize away
+    return (inversesqrt(input.x)          == expected.x     &&
+            inversesqrt(input.xy)         == expected.xy    &&
+            inversesqrt(input.xyz)        == expected.xyz   &&
+            inversesqrt(input.xyzw)       == expected.xyzw  &&
+            inversesqrt(constVal.x)       == expected.x     &&
+            inversesqrt(constVal.xy)      == expected.xy    &&
+            inversesqrt(constVal.xyz)     == expected.xyz   &&
+            inversesqrt(constVal.xyzw)    == expected.xyzw  &&
+            inversesqrt(negativeVal.x)    == expected.x     &&
+            inversesqrt(negativeVal.xy)   == expected.xy    &&
+            inversesqrt(negativeVal.xyz)  == expected.xyz   &&
+            inversesqrt(negativeVal.xyzw) == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/resources/sksl/intrinsics/Radians.sksl b/resources/sksl/intrinsics/Radians.sksl
index 922bd07..b06ebb1 100644
--- a/resources/sksl/intrinsics/Radians.sksl
+++ b/resources/sksl/intrinsics/Radians.sksl
@@ -1 +1,14 @@
-uniform half a; void main() { sk_FragColor.x = radians(a); }
+uniform half4 input, expected;
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(0);
+    return (radians(input.x)       == expected.x     &&
+            radians(input.xy)      == expected.xy    &&
+            radians(input.xyz)     == expected.xyz   &&
+            radians(input.xyzw)    == expected.xyzw  &&
+            radians(constVal.x)    == expected.x     &&
+            radians(constVal.xy)   == expected.xy    &&
+            radians(constVal.xyz)  == expected.xyz   &&
+            radians(constVal.xyzw) == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/resources/sksl/intrinsics/Round.sksl b/resources/sksl/intrinsics/Round.sksl
index 49de442..e3f6463 100644
--- a/resources/sksl/intrinsics/Round.sksl
+++ b/resources/sksl/intrinsics/Round.sksl
@@ -1 +1,14 @@
-uniform half a; void main() { sk_FragColor.x = round(a); }
+uniform half4 input, expected;
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(-1.5, -0.5, 0.5, 1.5);
+    return (round(input.x)       == expected.x     &&
+            round(input.xy)      == expected.xy    &&
+            round(input.xyz)     == expected.xyz   &&
+            round(input.xyzw)    == expected.xyzw  &&
+            round(constVal.x)    == expected.x     &&
+            round(constVal.xy)   == expected.xy    &&
+            round(constVal.xyz)  == expected.xyz   &&
+            round(constVal.xyzw) == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/resources/sksl/intrinsics/RoundEven.sksl b/resources/sksl/intrinsics/RoundEven.sksl
index c196392..17e4a92 100644
--- a/resources/sksl/intrinsics/RoundEven.sksl
+++ b/resources/sksl/intrinsics/RoundEven.sksl
@@ -1 +1,14 @@
-uniform half a; void main() { sk_FragColor.x = roundEven(a); }
+uniform half4 input, expected;
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(-1.5, -0.5, 0.5, 1.5);
+    return (roundEven(input.x)       == expected.x     &&
+            roundEven(input.xy)      == expected.xy    &&
+            roundEven(input.xyz)     == expected.xyz   &&
+            roundEven(input.xyzw)    == expected.xyzw  &&
+            roundEven(constVal.x)    == expected.x     &&
+            roundEven(constVal.xy)   == expected.xy    &&
+            roundEven(constVal.xyz)  == expected.xyz   &&
+            roundEven(constVal.xyzw) == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/resources/sksl/intrinsics/Saturate.sksl b/resources/sksl/intrinsics/Saturate.sksl
index 98fa3f5..0ef1390 100644
--- a/resources/sksl/intrinsics/Saturate.sksl
+++ b/resources/sksl/intrinsics/Saturate.sksl
@@ -1 +1,15 @@
-uniform half a; void main() { sk_FragColor.x = saturate(a); }
+uniform half4 testInputs;  // equals (-1.25, 0, 0.75, 2.25)
+uniform half4 colorGreen, colorRed;
+
+half4 main(float2 coords) {
+    const half4 constVal = half4(-1.25, 0, 0.75, 2.25);
+    half4 expected = half4(0, 0, 0.75, 1);
+    return (saturate(testInputs.x)    == expected.x     &&
+            saturate(testInputs.xy)   == expected.xy    &&
+            saturate(testInputs.xyz)  == expected.xyz   &&
+            saturate(testInputs.xyzw) == expected.xyzw  &&
+            saturate(constVal.x)      == expected.x     &&
+            saturate(constVal.xy)     == expected.xy    &&
+            saturate(constVal.xyz)    == expected.xyz   &&
+            saturate(constVal.xyzw)   == expected.xyzw) ? colorGreen : colorRed;
+}
diff --git a/src/sksl/ir/SkSLFunctionCall.cpp b/src/sksl/ir/SkSLFunctionCall.cpp
index 63384ad..bd385b1 100644
--- a/src/sksl/ir/SkSLFunctionCall.cpp
+++ b/src/sksl/ir/SkSLFunctionCall.cpp
@@ -108,6 +108,12 @@
         const Expression* subexpr = arg->getConstantSubexpression(index);
         SkASSERT(subexpr);
         auto value = evaluate(subexpr->as<LITERAL>().value());
+        if constexpr (std::is_floating_point<decltype(value)>::value) {
+            // If evaluation of the intrinsic yields a non-finite value, bail on optimization.
+            if (!isfinite(value)) {
+                return nullptr;
+            }
+        }
         result.push_back(LITERAL::Make(subexpr->fOffset, value, &type));
     }
 
@@ -249,6 +255,22 @@
         case k_log2_IntrinsicKind:
             return evaluate_intrinsic_float1(context, arguments, [](float a) { return log2(a); });
 
+        case k_saturate_IntrinsicKind:
+            return evaluate_intrinsic_float1(context, arguments,
+                                             [](float a) { return (a < 0) ? 0 : (a > 1) ? 1 : a; });
+        case k_round_IntrinsicKind:      // GLSL `round` documents its rounding mode as unspecified
+        case k_roundEven_IntrinsicKind:  // and is allowed to behave identically to `roundEven`.
+            return evaluate_intrinsic_float1(context, arguments,
+                                             [](float a) { return round(a / 2) * 2; });
+        case k_inversesqrt_IntrinsicKind:
+            return evaluate_intrinsic_float1(context, arguments,
+                                             [](float a) { return 1 / sqrt(a); });
+        case k_radians_IntrinsicKind:
+            return evaluate_intrinsic_float1(context, arguments,
+                                             [](float a) { return a * 0.0174532925; });
+        case k_degrees_IntrinsicKind:
+            return evaluate_intrinsic_float1(context, arguments,
+                                             [](float a) { return a * 57.2957795; });
         default:
             return nullptr;
     }
diff --git a/tests/sksl/intrinsics/Degrees.asm.frag b/tests/sksl/intrinsics/Degrees.asm.frag
index c2c7c21..c37964c 100644
--- a/tests/sksl/intrinsics/Degrees.asm.frag
+++ b/tests/sksl/intrinsics/Degrees.asm.frag
@@ -1,12 +1,16 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "input"
+OpMemberName %_UniformBuffer 1 "expected"
+OpMemberName %_UniformBuffer 2 "colorGreen"
+OpMemberName %_UniformBuffer 3 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -14,11 +18,46 @@
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
 OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 3 Offset 48
+OpMemberDecorate %_UniformBuffer 3 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %16 RelaxedPrecision
-OpDecorate %21 RelaxedPrecision
+OpDecorate %27 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
+OpDecorate %47 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %70 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+OpDecorate %82 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %90 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %98 RelaxedPrecision
+OpDecorate %100 RelaxedPrecision
+OpDecorate %101 RelaxedPrecision
+OpDecorate %108 RelaxedPrecision
+OpDecorate %110 RelaxedPrecision
+OpDecorate %121 RelaxedPrecision
+OpDecorate %124 RelaxedPrecision
+OpDecorate %125 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -26,21 +65,153 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 Degrees %21
-%22 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %22 %16
+%int_1 = OpConstant %int 1
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%float_90 = OpConstant %float 90
+%float_180 = OpConstant %float 180
+%88 = OpConstantComposite %v2float %float_90 %float_180
+%float_270 = OpConstant %float 270
+%98 = OpConstantComposite %v3float %float_90 %float_180 %float_270
+%float_360 = OpConstant %float 360
+%108 = OpConstantComposite %v4float %float_90 %float_180 %float_270 %float_360
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%114 = OpVariable %_ptr_Function_v4float Function
+%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%32 = OpLoad %v4float %28
+%33 = OpCompositeExtract %float %32 0
+%27 = OpExtInst %float %1 Degrees %33
+%34 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%36 = OpLoad %v4float %34
+%37 = OpCompositeExtract %float %36 0
+%38 = OpFOrdEqual %bool %27 %37
+OpSelectionMerge %40 None
+OpBranchConditional %38 %39 %40
+%39 = OpLabel
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+%44 = OpVectorShuffle %v2float %43 %43 0 1
+%41 = OpExtInst %v2float %1 Degrees %44
+%45 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%46 = OpLoad %v4float %45
+%47 = OpVectorShuffle %v2float %46 %46 0 1
+%48 = OpFOrdEqual %v2bool %41 %47
+%50 = OpAll %bool %48
+OpBranch %40
+%40 = OpLabel
+%51 = OpPhi %bool %false %25 %50 %39
+OpSelectionMerge %53 None
+OpBranchConditional %51 %52 %53
+%52 = OpLabel
+%55 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%56 = OpLoad %v4float %55
+%57 = OpVectorShuffle %v3float %56 %56 0 1 2
+%54 = OpExtInst %v3float %1 Degrees %57
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%60 = OpLoad %v4float %59
+%61 = OpVectorShuffle %v3float %60 %60 0 1 2
+%62 = OpFOrdEqual %v3bool %54 %61
+%64 = OpAll %bool %62
+OpBranch %53
+%53 = OpLabel
+%65 = OpPhi %bool %false %40 %64 %52
+OpSelectionMerge %67 None
+OpBranchConditional %65 %66 %67
+%66 = OpLabel
+%69 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%70 = OpLoad %v4float %69
+%68 = OpExtInst %v4float %1 Degrees %70
+%71 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%72 = OpLoad %v4float %71
+%73 = OpFOrdEqual %v4bool %68 %72
+%75 = OpAll %bool %73
+OpBranch %67
+%67 = OpLabel
+%76 = OpPhi %bool %false %53 %75 %66
+OpSelectionMerge %78 None
+OpBranchConditional %76 %77 %78
+%77 = OpLabel
+%80 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%81 = OpLoad %v4float %80
+%82 = OpCompositeExtract %float %81 0
+%83 = OpFOrdEqual %bool %float_90 %82
+OpBranch %78
+%78 = OpLabel
+%84 = OpPhi %bool %false %67 %83 %77
+OpSelectionMerge %86 None
+OpBranchConditional %84 %85 %86
+%85 = OpLabel
+%89 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%90 = OpLoad %v4float %89
+%91 = OpVectorShuffle %v2float %90 %90 0 1
+%92 = OpFOrdEqual %v2bool %88 %91
+%93 = OpAll %bool %92
+OpBranch %86
+%86 = OpLabel
+%94 = OpPhi %bool %false %78 %93 %85
+OpSelectionMerge %96 None
+OpBranchConditional %94 %95 %96
+%95 = OpLabel
+%99 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%100 = OpLoad %v4float %99
+%101 = OpVectorShuffle %v3float %100 %100 0 1 2
+%102 = OpFOrdEqual %v3bool %98 %101
+%103 = OpAll %bool %102
+OpBranch %96
+%96 = OpLabel
+%104 = OpPhi %bool %false %86 %103 %95
+OpSelectionMerge %106 None
+OpBranchConditional %104 %105 %106
+%105 = OpLabel
+%109 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%110 = OpLoad %v4float %109
+%111 = OpFOrdEqual %v4bool %108 %110
+%112 = OpAll %bool %111
+OpBranch %106
+%106 = OpLabel
+%113 = OpPhi %bool %false %96 %112 %105
+OpSelectionMerge %118 None
+OpBranchConditional %113 %116 %117
+%116 = OpLabel
+%119 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%121 = OpLoad %v4float %119
+OpStore %114 %121
+OpBranch %118
+%117 = OpLabel
+%122 = OpAccessChain %_ptr_Uniform_v4float %10 %int_3
+%124 = OpLoad %v4float %122
+OpStore %114 %124
+OpBranch %118
+%118 = OpLabel
+%125 = OpLoad %v4float %114
+OpReturnValue %125
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/Degrees.glsl b/tests/sksl/intrinsics/Degrees.glsl
index 8332033..d7e110e 100644
--- a/tests/sksl/intrinsics/Degrees.glsl
+++ b/tests/sksl/intrinsics/Degrees.glsl
@@ -1,6 +1,9 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = degrees(a);
+uniform vec4 input;
+uniform vec4 expected;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    return ((((((degrees(input.x) == expected.x && degrees(input.xy) == expected.xy) && degrees(input.xyz) == expected.xyz) && degrees(input) == expected) && 90.0 == expected.x) && vec2(90.0, 180.0) == expected.xy) && vec3(90.0, 180.0, 270.0) == expected.xyz) && vec4(90.0, 180.0, 270.0, 360.0) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/Degrees.metal b/tests/sksl/intrinsics/Degrees.metal
index c1791f4..ecfd43b 100644
--- a/tests/sksl/intrinsics/Degrees.metal
+++ b/tests/sksl/intrinsics/Degrees.metal
@@ -2,7 +2,10 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 input;
+    float4 expected;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +16,6 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = ((_uniforms.a) * 57.2957795);
+    _out.sk_FragColor = ((((((((_uniforms.input.x) * 57.2957795) == _uniforms.expected.x && all(((_uniforms.input.xy) * 57.2957795) == _uniforms.expected.xy)) && all(((_uniforms.input.xyz) * 57.2957795) == _uniforms.expected.xyz)) && all(((_uniforms.input) * 57.2957795) == _uniforms.expected)) && 90.0 == _uniforms.expected.x) && all(float2(90.0, 180.0) == _uniforms.expected.xy)) && all(float3(90.0, 180.0, 270.0) == _uniforms.expected.xyz)) && all(float4(90.0, 180.0, 270.0, 360.0) == _uniforms.expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }
diff --git a/tests/sksl/intrinsics/Inversesqrt.asm.frag b/tests/sksl/intrinsics/Inversesqrt.asm.frag
index 0359126..0a572d1 100644
--- a/tests/sksl/intrinsics/Inversesqrt.asm.frag
+++ b/tests/sksl/intrinsics/Inversesqrt.asm.frag
@@ -1,21 +1,79 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "input"
+OpMemberName %_UniformBuffer 1 "expected"
+OpMemberName %_UniformBuffer 2 "colorGreen"
+OpMemberName %_UniformBuffer 3 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
+OpName %negativeVal "negativeVal"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
 OpDecorate %sk_FragColor Index 0
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
+OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 3 Offset 48
+OpMemberDecorate %_UniformBuffer 3 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
+OpDecorate %negativeVal RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %34 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %40 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %48 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %51 RelaxedPrecision
+OpDecorate %53 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %63 RelaxedPrecision
+OpDecorate %64 RelaxedPrecision
+OpDecorate %67 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %77 RelaxedPrecision
+OpDecorate %79 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %89 RelaxedPrecision
+OpDecorate %95 RelaxedPrecision
+OpDecorate %97 RelaxedPrecision
+OpDecorate %98 RelaxedPrecision
+OpDecorate %105 RelaxedPrecision
+OpDecorate %107 RelaxedPrecision
+OpDecorate %108 RelaxedPrecision
+OpDecorate %115 RelaxedPrecision
+OpDecorate %117 RelaxedPrecision
+OpDecorate %125 RelaxedPrecision
+OpDecorate %126 RelaxedPrecision
+OpDecorate %131 RelaxedPrecision
+OpDecorate %132 RelaxedPrecision
+OpDecorate %134 RelaxedPrecision
+OpDecorate %135 RelaxedPrecision
+OpDecorate %141 RelaxedPrecision
+OpDecorate %142 RelaxedPrecision
+OpDecorate %144 RelaxedPrecision
+OpDecorate %145 RelaxedPrecision
+OpDecorate %151 RelaxedPrecision
+OpDecorate %152 RelaxedPrecision
+OpDecorate %154 RelaxedPrecision
+OpDecorate %164 RelaxedPrecision
+OpDecorate %167 RelaxedPrecision
+OpDecorate %168 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -23,21 +81,209 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%float_n1 = OpConstant %float -1
+%float_n4 = OpConstant %float -4
+%float_n16 = OpConstant %float -16
+%float_n64 = OpConstant %float -64
+%32 = OpConstantComposite %v4float %float_n1 %float_n4 %float_n16 %float_n64
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 InverseSqrt %21
-%22 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %22 %16
+%int_1 = OpConstant %int 1
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%float_1 = OpConstant %float 1
+%float_0_5 = OpConstant %float 0.5
+%95 = OpConstantComposite %v2float %float_1 %float_0_5
+%float_0_25 = OpConstant %float 0.25
+%105 = OpConstantComposite %v3float %float_1 %float_0_5 %float_0_25
+%float_0_125 = OpConstant %float 0.125
+%115 = OpConstantComposite %v4float %float_1 %float_0_5 %float_0_25 %float_0_125
+%132 = OpConstantComposite %v2float %float_n1 %float_n4
+%142 = OpConstantComposite %v3float %float_n1 %float_n4 %float_n16
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%negativeVal = OpVariable %_ptr_Function_v4float Function
+%158 = OpVariable %_ptr_Function_v4float Function
+OpStore %negativeVal %32
+%35 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%39 = OpLoad %v4float %35
+%40 = OpCompositeExtract %float %39 0
+%34 = OpExtInst %float %1 InverseSqrt %40
+%41 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%43 = OpLoad %v4float %41
+%44 = OpCompositeExtract %float %43 0
+%45 = OpFOrdEqual %bool %34 %44
+OpSelectionMerge %47 None
+OpBranchConditional %45 %46 %47
+%46 = OpLabel
+%49 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%50 = OpLoad %v4float %49
+%51 = OpVectorShuffle %v2float %50 %50 0 1
+%48 = OpExtInst %v2float %1 InverseSqrt %51
+%52 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%53 = OpLoad %v4float %52
+%54 = OpVectorShuffle %v2float %53 %53 0 1
+%55 = OpFOrdEqual %v2bool %48 %54
+%57 = OpAll %bool %55
+OpBranch %47
+%47 = OpLabel
+%58 = OpPhi %bool %false %25 %57 %46
+OpSelectionMerge %60 None
+OpBranchConditional %58 %59 %60
+%59 = OpLabel
+%62 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%63 = OpLoad %v4float %62
+%64 = OpVectorShuffle %v3float %63 %63 0 1 2
+%61 = OpExtInst %v3float %1 InverseSqrt %64
+%66 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%67 = OpLoad %v4float %66
+%68 = OpVectorShuffle %v3float %67 %67 0 1 2
+%69 = OpFOrdEqual %v3bool %61 %68
+%71 = OpAll %bool %69
+OpBranch %60
+%60 = OpLabel
+%72 = OpPhi %bool %false %47 %71 %59
+OpSelectionMerge %74 None
+OpBranchConditional %72 %73 %74
+%73 = OpLabel
+%76 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%77 = OpLoad %v4float %76
+%75 = OpExtInst %v4float %1 InverseSqrt %77
+%78 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%79 = OpLoad %v4float %78
+%80 = OpFOrdEqual %v4bool %75 %79
+%82 = OpAll %bool %80
+OpBranch %74
+%74 = OpLabel
+%83 = OpPhi %bool %false %60 %82 %73
+OpSelectionMerge %85 None
+OpBranchConditional %83 %84 %85
+%84 = OpLabel
+%87 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%88 = OpLoad %v4float %87
+%89 = OpCompositeExtract %float %88 0
+%90 = OpFOrdEqual %bool %float_1 %89
+OpBranch %85
+%85 = OpLabel
+%91 = OpPhi %bool %false %74 %90 %84
+OpSelectionMerge %93 None
+OpBranchConditional %91 %92 %93
+%92 = OpLabel
+%96 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%97 = OpLoad %v4float %96
+%98 = OpVectorShuffle %v2float %97 %97 0 1
+%99 = OpFOrdEqual %v2bool %95 %98
+%100 = OpAll %bool %99
+OpBranch %93
+%93 = OpLabel
+%101 = OpPhi %bool %false %85 %100 %92
+OpSelectionMerge %103 None
+OpBranchConditional %101 %102 %103
+%102 = OpLabel
+%106 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%107 = OpLoad %v4float %106
+%108 = OpVectorShuffle %v3float %107 %107 0 1 2
+%109 = OpFOrdEqual %v3bool %105 %108
+%110 = OpAll %bool %109
+OpBranch %103
+%103 = OpLabel
+%111 = OpPhi %bool %false %93 %110 %102
+OpSelectionMerge %113 None
+OpBranchConditional %111 %112 %113
+%112 = OpLabel
+%116 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%117 = OpLoad %v4float %116
+%118 = OpFOrdEqual %v4bool %115 %117
+%119 = OpAll %bool %118
+OpBranch %113
+%113 = OpLabel
+%120 = OpPhi %bool %false %103 %119 %112
+OpSelectionMerge %122 None
+OpBranchConditional %120 %121 %122
+%121 = OpLabel
+%123 = OpExtInst %float %1 InverseSqrt %float_n1
+%124 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%125 = OpLoad %v4float %124
+%126 = OpCompositeExtract %float %125 0
+%127 = OpFOrdEqual %bool %123 %126
+OpBranch %122
+%122 = OpLabel
+%128 = OpPhi %bool %false %113 %127 %121
+OpSelectionMerge %130 None
+OpBranchConditional %128 %129 %130
+%129 = OpLabel
+%131 = OpExtInst %v2float %1 InverseSqrt %132
+%133 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%134 = OpLoad %v4float %133
+%135 = OpVectorShuffle %v2float %134 %134 0 1
+%136 = OpFOrdEqual %v2bool %131 %135
+%137 = OpAll %bool %136
+OpBranch %130
+%130 = OpLabel
+%138 = OpPhi %bool %false %122 %137 %129
+OpSelectionMerge %140 None
+OpBranchConditional %138 %139 %140
+%139 = OpLabel
+%141 = OpExtInst %v3float %1 InverseSqrt %142
+%143 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%144 = OpLoad %v4float %143
+%145 = OpVectorShuffle %v3float %144 %144 0 1 2
+%146 = OpFOrdEqual %v3bool %141 %145
+%147 = OpAll %bool %146
+OpBranch %140
+%140 = OpLabel
+%148 = OpPhi %bool %false %130 %147 %139
+OpSelectionMerge %150 None
+OpBranchConditional %148 %149 %150
+%149 = OpLabel
+%152 = OpLoad %v4float %negativeVal
+%151 = OpExtInst %v4float %1 InverseSqrt %152
+%153 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%154 = OpLoad %v4float %153
+%155 = OpFOrdEqual %v4bool %151 %154
+%156 = OpAll %bool %155
+OpBranch %150
+%150 = OpLabel
+%157 = OpPhi %bool %false %140 %156 %149
+OpSelectionMerge %161 None
+OpBranchConditional %157 %159 %160
+%159 = OpLabel
+%162 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%164 = OpLoad %v4float %162
+OpStore %158 %164
+OpBranch %161
+%160 = OpLabel
+%165 = OpAccessChain %_ptr_Uniform_v4float %10 %int_3
+%167 = OpLoad %v4float %165
+OpStore %158 %167
+OpBranch %161
+%161 = OpLabel
+%168 = OpLoad %v4float %158
+OpReturnValue %168
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/Inversesqrt.glsl b/tests/sksl/intrinsics/Inversesqrt.glsl
index f822896..71c4bec 100644
--- a/tests/sksl/intrinsics/Inversesqrt.glsl
+++ b/tests/sksl/intrinsics/Inversesqrt.glsl
@@ -1,6 +1,10 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = inversesqrt(a);
+uniform vec4 input;
+uniform vec4 expected;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    const vec4 negativeVal = vec4(-1.0, -4.0, -16.0, -64.0);
+    return ((((((((((inversesqrt(input.x) == expected.x && inversesqrt(input.xy) == expected.xy) && inversesqrt(input.xyz) == expected.xyz) && inversesqrt(input) == expected) && 1.0 == expected.x) && vec2(1.0, 0.5) == expected.xy) && vec3(1.0, 0.5, 0.25) == expected.xyz) && vec4(1.0, 0.5, 0.25, 0.125) == expected) && inversesqrt(-1.0) == expected.x) && inversesqrt(vec2(-1.0, -4.0)) == expected.xy) && inversesqrt(vec3(-1.0, -4.0, -16.0)) == expected.xyz) && inversesqrt(negativeVal) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/Inversesqrt.metal b/tests/sksl/intrinsics/Inversesqrt.metal
index 0742e24..422726f9 100644
--- a/tests/sksl/intrinsics/Inversesqrt.metal
+++ b/tests/sksl/intrinsics/Inversesqrt.metal
@@ -2,7 +2,10 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 input;
+    float4 expected;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +16,7 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = rsqrt(_uniforms.a);
+    const float4 negativeVal = float4(-1.0, -4.0, -16.0, -64.0);
+    _out.sk_FragColor = ((((((((((rsqrt(_uniforms.input.x) == _uniforms.expected.x && all(rsqrt(_uniforms.input.xy) == _uniforms.expected.xy)) && all(rsqrt(_uniforms.input.xyz) == _uniforms.expected.xyz)) && all(rsqrt(_uniforms.input) == _uniforms.expected)) && 1.0 == _uniforms.expected.x) && all(float2(1.0, 0.5) == _uniforms.expected.xy)) && all(float3(1.0, 0.5, 0.25) == _uniforms.expected.xyz)) && all(float4(1.0, 0.5, 0.25, 0.125) == _uniforms.expected)) && rsqrt(-1.0) == _uniforms.expected.x) && all(rsqrt(float2(-1.0, -4.0)) == _uniforms.expected.xy)) && all(rsqrt(float3(-1.0, -4.0, -16.0)) == _uniforms.expected.xyz)) && all(rsqrt(negativeVal) == _uniforms.expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }
diff --git a/tests/sksl/intrinsics/Radians.asm.frag b/tests/sksl/intrinsics/Radians.asm.frag
index 1484550..18eae0d 100644
--- a/tests/sksl/intrinsics/Radians.asm.frag
+++ b/tests/sksl/intrinsics/Radians.asm.frag
@@ -1,12 +1,16 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "input"
+OpMemberName %_UniformBuffer 1 "expected"
+OpMemberName %_UniformBuffer 2 "colorGreen"
+OpMemberName %_UniformBuffer 3 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -14,11 +18,45 @@
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
 OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 3 Offset 48
+OpMemberDecorate %_UniformBuffer 3 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %16 RelaxedPrecision
-OpDecorate %21 RelaxedPrecision
+OpDecorate %27 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
+OpDecorate %47 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %70 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %80 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+OpDecorate %87 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %94 RelaxedPrecision
+OpDecorate %96 RelaxedPrecision
+OpDecorate %97 RelaxedPrecision
+OpDecorate %103 RelaxedPrecision
+OpDecorate %105 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %119 RelaxedPrecision
+OpDecorate %120 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -26,21 +64,148 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 Radians %21
-%22 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %22 %16
+%int_1 = OpConstant %int 1
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%94 = OpConstantComposite %v3float %float_0 %float_0 %float_0
+%103 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%109 = OpVariable %_ptr_Function_v4float Function
+%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%32 = OpLoad %v4float %28
+%33 = OpCompositeExtract %float %32 0
+%27 = OpExtInst %float %1 Radians %33
+%34 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%36 = OpLoad %v4float %34
+%37 = OpCompositeExtract %float %36 0
+%38 = OpFOrdEqual %bool %27 %37
+OpSelectionMerge %40 None
+OpBranchConditional %38 %39 %40
+%39 = OpLabel
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+%44 = OpVectorShuffle %v2float %43 %43 0 1
+%41 = OpExtInst %v2float %1 Radians %44
+%45 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%46 = OpLoad %v4float %45
+%47 = OpVectorShuffle %v2float %46 %46 0 1
+%48 = OpFOrdEqual %v2bool %41 %47
+%50 = OpAll %bool %48
+OpBranch %40
+%40 = OpLabel
+%51 = OpPhi %bool %false %25 %50 %39
+OpSelectionMerge %53 None
+OpBranchConditional %51 %52 %53
+%52 = OpLabel
+%55 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%56 = OpLoad %v4float %55
+%57 = OpVectorShuffle %v3float %56 %56 0 1 2
+%54 = OpExtInst %v3float %1 Radians %57
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%60 = OpLoad %v4float %59
+%61 = OpVectorShuffle %v3float %60 %60 0 1 2
+%62 = OpFOrdEqual %v3bool %54 %61
+%64 = OpAll %bool %62
+OpBranch %53
+%53 = OpLabel
+%65 = OpPhi %bool %false %40 %64 %52
+OpSelectionMerge %67 None
+OpBranchConditional %65 %66 %67
+%66 = OpLabel
+%69 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%70 = OpLoad %v4float %69
+%68 = OpExtInst %v4float %1 Radians %70
+%71 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%72 = OpLoad %v4float %71
+%73 = OpFOrdEqual %v4bool %68 %72
+%75 = OpAll %bool %73
+OpBranch %67
+%67 = OpLabel
+%76 = OpPhi %bool %false %53 %75 %66
+OpSelectionMerge %78 None
+OpBranchConditional %76 %77 %78
+%77 = OpLabel
+%79 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%80 = OpLoad %v4float %79
+%81 = OpCompositeExtract %float %80 0
+%82 = OpFOrdEqual %bool %float_0 %81
+OpBranch %78
+%78 = OpLabel
+%83 = OpPhi %bool %false %67 %82 %77
+OpSelectionMerge %85 None
+OpBranchConditional %83 %84 %85
+%84 = OpLabel
+%86 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%87 = OpLoad %v4float %86
+%88 = OpVectorShuffle %v2float %87 %87 0 1
+%89 = OpFOrdEqual %v2bool %19 %88
+%90 = OpAll %bool %89
+OpBranch %85
+%85 = OpLabel
+%91 = OpPhi %bool %false %78 %90 %84
+OpSelectionMerge %93 None
+OpBranchConditional %91 %92 %93
+%92 = OpLabel
+%95 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%96 = OpLoad %v4float %95
+%97 = OpVectorShuffle %v3float %96 %96 0 1 2
+%98 = OpFOrdEqual %v3bool %94 %97
+%99 = OpAll %bool %98
+OpBranch %93
+%93 = OpLabel
+%100 = OpPhi %bool %false %85 %99 %92
+OpSelectionMerge %102 None
+OpBranchConditional %100 %101 %102
+%101 = OpLabel
+%104 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%105 = OpLoad %v4float %104
+%106 = OpFOrdEqual %v4bool %103 %105
+%107 = OpAll %bool %106
+OpBranch %102
+%102 = OpLabel
+%108 = OpPhi %bool %false %93 %107 %101
+OpSelectionMerge %113 None
+OpBranchConditional %108 %111 %112
+%111 = OpLabel
+%114 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%116 = OpLoad %v4float %114
+OpStore %109 %116
+OpBranch %113
+%112 = OpLabel
+%117 = OpAccessChain %_ptr_Uniform_v4float %10 %int_3
+%119 = OpLoad %v4float %117
+OpStore %109 %119
+OpBranch %113
+%113 = OpLabel
+%120 = OpLoad %v4float %109
+OpReturnValue %120
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/Radians.glsl b/tests/sksl/intrinsics/Radians.glsl
index 3eb98a8..4c939d3 100644
--- a/tests/sksl/intrinsics/Radians.glsl
+++ b/tests/sksl/intrinsics/Radians.glsl
@@ -1,6 +1,9 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = radians(a);
+uniform vec4 input;
+uniform vec4 expected;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    return ((((((radians(input.x) == expected.x && radians(input.xy) == expected.xy) && radians(input.xyz) == expected.xyz) && radians(input) == expected) && 0.0 == expected.x) && vec2(0.0, 0.0) == expected.xy) && vec3(0.0, 0.0, 0.0) == expected.xyz) && vec4(0.0, 0.0, 0.0, 0.0) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/Radians.metal b/tests/sksl/intrinsics/Radians.metal
index c77b02a..0a5aa41 100644
--- a/tests/sksl/intrinsics/Radians.metal
+++ b/tests/sksl/intrinsics/Radians.metal
@@ -2,7 +2,10 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 input;
+    float4 expected;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +16,6 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = ((_uniforms.a) * 0.0174532925);
+    _out.sk_FragColor = ((((((((_uniforms.input.x) * 0.0174532925) == _uniforms.expected.x && all(((_uniforms.input.xy) * 0.0174532925) == _uniforms.expected.xy)) && all(((_uniforms.input.xyz) * 0.0174532925) == _uniforms.expected.xyz)) && all(((_uniforms.input) * 0.0174532925) == _uniforms.expected)) && 0.0 == _uniforms.expected.x) && all(float2(0.0, 0.0) == _uniforms.expected.xy)) && all(float3(0.0, 0.0, 0.0) == _uniforms.expected.xyz)) && all(float4(0.0, 0.0, 0.0, 0.0) == _uniforms.expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }
diff --git a/tests/sksl/intrinsics/Round.asm.frag b/tests/sksl/intrinsics/Round.asm.frag
index 1aafe5f..ce549eb 100644
--- a/tests/sksl/intrinsics/Round.asm.frag
+++ b/tests/sksl/intrinsics/Round.asm.frag
@@ -1,12 +1,16 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "input"
+OpMemberName %_UniformBuffer 1 "expected"
+OpMemberName %_UniformBuffer 2 "colorGreen"
+OpMemberName %_UniformBuffer 3 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -14,11 +18,46 @@
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
 OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 3 Offset 48
+OpMemberDecorate %_UniformBuffer 3 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %16 RelaxedPrecision
-OpDecorate %21 RelaxedPrecision
+OpDecorate %27 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
+OpDecorate %47 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %70 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+OpDecorate %82 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %90 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %97 RelaxedPrecision
+OpDecorate %99 RelaxedPrecision
+OpDecorate %100 RelaxedPrecision
+OpDecorate %107 RelaxedPrecision
+OpDecorate %109 RelaxedPrecision
+OpDecorate %120 RelaxedPrecision
+OpDecorate %123 RelaxedPrecision
+OpDecorate %124 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -26,21 +65,152 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 Round %21
-%22 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %22 %16
+%int_1 = OpConstant %int 1
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%float_n2 = OpConstant %float -2
+%float_n0 = OpConstant %float -0
+%88 = OpConstantComposite %v2float %float_n2 %float_n0
+%97 = OpConstantComposite %v3float %float_n2 %float_n0 %float_0
+%float_2 = OpConstant %float 2
+%107 = OpConstantComposite %v4float %float_n2 %float_n0 %float_0 %float_2
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%113 = OpVariable %_ptr_Function_v4float Function
+%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%32 = OpLoad %v4float %28
+%33 = OpCompositeExtract %float %32 0
+%27 = OpExtInst %float %1 Round %33
+%34 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%36 = OpLoad %v4float %34
+%37 = OpCompositeExtract %float %36 0
+%38 = OpFOrdEqual %bool %27 %37
+OpSelectionMerge %40 None
+OpBranchConditional %38 %39 %40
+%39 = OpLabel
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+%44 = OpVectorShuffle %v2float %43 %43 0 1
+%41 = OpExtInst %v2float %1 Round %44
+%45 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%46 = OpLoad %v4float %45
+%47 = OpVectorShuffle %v2float %46 %46 0 1
+%48 = OpFOrdEqual %v2bool %41 %47
+%50 = OpAll %bool %48
+OpBranch %40
+%40 = OpLabel
+%51 = OpPhi %bool %false %25 %50 %39
+OpSelectionMerge %53 None
+OpBranchConditional %51 %52 %53
+%52 = OpLabel
+%55 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%56 = OpLoad %v4float %55
+%57 = OpVectorShuffle %v3float %56 %56 0 1 2
+%54 = OpExtInst %v3float %1 Round %57
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%60 = OpLoad %v4float %59
+%61 = OpVectorShuffle %v3float %60 %60 0 1 2
+%62 = OpFOrdEqual %v3bool %54 %61
+%64 = OpAll %bool %62
+OpBranch %53
+%53 = OpLabel
+%65 = OpPhi %bool %false %40 %64 %52
+OpSelectionMerge %67 None
+OpBranchConditional %65 %66 %67
+%66 = OpLabel
+%69 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%70 = OpLoad %v4float %69
+%68 = OpExtInst %v4float %1 Round %70
+%71 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%72 = OpLoad %v4float %71
+%73 = OpFOrdEqual %v4bool %68 %72
+%75 = OpAll %bool %73
+OpBranch %67
+%67 = OpLabel
+%76 = OpPhi %bool %false %53 %75 %66
+OpSelectionMerge %78 None
+OpBranchConditional %76 %77 %78
+%77 = OpLabel
+%80 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%81 = OpLoad %v4float %80
+%82 = OpCompositeExtract %float %81 0
+%83 = OpFOrdEqual %bool %float_n2 %82
+OpBranch %78
+%78 = OpLabel
+%84 = OpPhi %bool %false %67 %83 %77
+OpSelectionMerge %86 None
+OpBranchConditional %84 %85 %86
+%85 = OpLabel
+%89 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%90 = OpLoad %v4float %89
+%91 = OpVectorShuffle %v2float %90 %90 0 1
+%92 = OpFOrdEqual %v2bool %88 %91
+%93 = OpAll %bool %92
+OpBranch %86
+%86 = OpLabel
+%94 = OpPhi %bool %false %78 %93 %85
+OpSelectionMerge %96 None
+OpBranchConditional %94 %95 %96
+%95 = OpLabel
+%98 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%99 = OpLoad %v4float %98
+%100 = OpVectorShuffle %v3float %99 %99 0 1 2
+%101 = OpFOrdEqual %v3bool %97 %100
+%102 = OpAll %bool %101
+OpBranch %96
+%96 = OpLabel
+%103 = OpPhi %bool %false %86 %102 %95
+OpSelectionMerge %105 None
+OpBranchConditional %103 %104 %105
+%104 = OpLabel
+%108 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%109 = OpLoad %v4float %108
+%110 = OpFOrdEqual %v4bool %107 %109
+%111 = OpAll %bool %110
+OpBranch %105
+%105 = OpLabel
+%112 = OpPhi %bool %false %96 %111 %104
+OpSelectionMerge %117 None
+OpBranchConditional %112 %115 %116
+%115 = OpLabel
+%118 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%120 = OpLoad %v4float %118
+OpStore %113 %120
+OpBranch %117
+%116 = OpLabel
+%121 = OpAccessChain %_ptr_Uniform_v4float %10 %int_3
+%123 = OpLoad %v4float %121
+OpStore %113 %123
+OpBranch %117
+%117 = OpLabel
+%124 = OpLoad %v4float %113
+OpReturnValue %124
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/Round.glsl b/tests/sksl/intrinsics/Round.glsl
index 942b7a1..215af92 100644
--- a/tests/sksl/intrinsics/Round.glsl
+++ b/tests/sksl/intrinsics/Round.glsl
@@ -1,6 +1,9 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = round(a);
+uniform vec4 input;
+uniform vec4 expected;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    return ((((((round(input.x) == expected.x && round(input.xy) == expected.xy) && round(input.xyz) == expected.xyz) && round(input) == expected) && -2.0 == expected.x) && vec2(-2.0, -0.0) == expected.xy) && vec3(-2.0, -0.0, 0.0) == expected.xyz) && vec4(-2.0, -0.0, 0.0, 2.0) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/Round.metal b/tests/sksl/intrinsics/Round.metal
index 9d4a151..7ec38a2 100644
--- a/tests/sksl/intrinsics/Round.metal
+++ b/tests/sksl/intrinsics/Round.metal
@@ -2,7 +2,10 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 input;
+    float4 expected;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +16,6 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = round(_uniforms.a);
+    _out.sk_FragColor = ((((((round(_uniforms.input.x) == _uniforms.expected.x && all(round(_uniforms.input.xy) == _uniforms.expected.xy)) && all(round(_uniforms.input.xyz) == _uniforms.expected.xyz)) && all(round(_uniforms.input) == _uniforms.expected)) && -2.0 == _uniforms.expected.x) && all(float2(-2.0, -0.0) == _uniforms.expected.xy)) && all(float3(-2.0, -0.0, 0.0) == _uniforms.expected.xyz)) && all(float4(-2.0, -0.0, 0.0, 2.0) == _uniforms.expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }
diff --git a/tests/sksl/intrinsics/RoundEven.asm.frag b/tests/sksl/intrinsics/RoundEven.asm.frag
index 6a41345..413e218 100644
--- a/tests/sksl/intrinsics/RoundEven.asm.frag
+++ b/tests/sksl/intrinsics/RoundEven.asm.frag
@@ -1,12 +1,16 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "input"
+OpMemberName %_UniformBuffer 1 "expected"
+OpMemberName %_UniformBuffer 2 "colorGreen"
+OpMemberName %_UniformBuffer 3 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
@@ -14,11 +18,46 @@
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
 OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 3 Offset 48
+OpMemberDecorate %_UniformBuffer 3 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %16 RelaxedPrecision
-OpDecorate %21 RelaxedPrecision
+OpDecorate %27 RelaxedPrecision
+OpDecorate %32 RelaxedPrecision
+OpDecorate %33 RelaxedPrecision
+OpDecorate %36 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %41 RelaxedPrecision
+OpDecorate %43 RelaxedPrecision
+OpDecorate %44 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
+OpDecorate %47 RelaxedPrecision
+OpDecorate %54 RelaxedPrecision
+OpDecorate %56 RelaxedPrecision
+OpDecorate %57 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %68 RelaxedPrecision
+OpDecorate %70 RelaxedPrecision
+OpDecorate %72 RelaxedPrecision
+OpDecorate %81 RelaxedPrecision
+OpDecorate %82 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %90 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %97 RelaxedPrecision
+OpDecorate %99 RelaxedPrecision
+OpDecorate %100 RelaxedPrecision
+OpDecorate %107 RelaxedPrecision
+OpDecorate %109 RelaxedPrecision
+OpDecorate %120 RelaxedPrecision
+OpDecorate %123 RelaxedPrecision
+OpDecorate %124 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -26,21 +65,152 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 RoundEven %21
-%22 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %22 %16
+%int_1 = OpConstant %int 1
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%float_n2 = OpConstant %float -2
+%float_n0 = OpConstant %float -0
+%88 = OpConstantComposite %v2float %float_n2 %float_n0
+%97 = OpConstantComposite %v3float %float_n2 %float_n0 %float_0
+%float_2 = OpConstant %float 2
+%107 = OpConstantComposite %v4float %float_n2 %float_n0 %float_0 %float_2
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%int_2 = OpConstant %int 2
+%int_3 = OpConstant %int 3
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%113 = OpVariable %_ptr_Function_v4float Function
+%28 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%32 = OpLoad %v4float %28
+%33 = OpCompositeExtract %float %32 0
+%27 = OpExtInst %float %1 RoundEven %33
+%34 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%36 = OpLoad %v4float %34
+%37 = OpCompositeExtract %float %36 0
+%38 = OpFOrdEqual %bool %27 %37
+OpSelectionMerge %40 None
+OpBranchConditional %38 %39 %40
+%39 = OpLabel
+%42 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%43 = OpLoad %v4float %42
+%44 = OpVectorShuffle %v2float %43 %43 0 1
+%41 = OpExtInst %v2float %1 RoundEven %44
+%45 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%46 = OpLoad %v4float %45
+%47 = OpVectorShuffle %v2float %46 %46 0 1
+%48 = OpFOrdEqual %v2bool %41 %47
+%50 = OpAll %bool %48
+OpBranch %40
+%40 = OpLabel
+%51 = OpPhi %bool %false %25 %50 %39
+OpSelectionMerge %53 None
+OpBranchConditional %51 %52 %53
+%52 = OpLabel
+%55 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%56 = OpLoad %v4float %55
+%57 = OpVectorShuffle %v3float %56 %56 0 1 2
+%54 = OpExtInst %v3float %1 RoundEven %57
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%60 = OpLoad %v4float %59
+%61 = OpVectorShuffle %v3float %60 %60 0 1 2
+%62 = OpFOrdEqual %v3bool %54 %61
+%64 = OpAll %bool %62
+OpBranch %53
+%53 = OpLabel
+%65 = OpPhi %bool %false %40 %64 %52
+OpSelectionMerge %67 None
+OpBranchConditional %65 %66 %67
+%66 = OpLabel
+%69 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%70 = OpLoad %v4float %69
+%68 = OpExtInst %v4float %1 RoundEven %70
+%71 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%72 = OpLoad %v4float %71
+%73 = OpFOrdEqual %v4bool %68 %72
+%75 = OpAll %bool %73
+OpBranch %67
+%67 = OpLabel
+%76 = OpPhi %bool %false %53 %75 %66
+OpSelectionMerge %78 None
+OpBranchConditional %76 %77 %78
+%77 = OpLabel
+%80 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%81 = OpLoad %v4float %80
+%82 = OpCompositeExtract %float %81 0
+%83 = OpFOrdEqual %bool %float_n2 %82
+OpBranch %78
+%78 = OpLabel
+%84 = OpPhi %bool %false %67 %83 %77
+OpSelectionMerge %86 None
+OpBranchConditional %84 %85 %86
+%85 = OpLabel
+%89 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%90 = OpLoad %v4float %89
+%91 = OpVectorShuffle %v2float %90 %90 0 1
+%92 = OpFOrdEqual %v2bool %88 %91
+%93 = OpAll %bool %92
+OpBranch %86
+%86 = OpLabel
+%94 = OpPhi %bool %false %78 %93 %85
+OpSelectionMerge %96 None
+OpBranchConditional %94 %95 %96
+%95 = OpLabel
+%98 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%99 = OpLoad %v4float %98
+%100 = OpVectorShuffle %v3float %99 %99 0 1 2
+%101 = OpFOrdEqual %v3bool %97 %100
+%102 = OpAll %bool %101
+OpBranch %96
+%96 = OpLabel
+%103 = OpPhi %bool %false %86 %102 %95
+OpSelectionMerge %105 None
+OpBranchConditional %103 %104 %105
+%104 = OpLabel
+%108 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%109 = OpLoad %v4float %108
+%110 = OpFOrdEqual %v4bool %107 %109
+%111 = OpAll %bool %110
+OpBranch %105
+%105 = OpLabel
+%112 = OpPhi %bool %false %96 %111 %104
+OpSelectionMerge %117 None
+OpBranchConditional %112 %115 %116
+%115 = OpLabel
+%118 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%120 = OpLoad %v4float %118
+OpStore %113 %120
+OpBranch %117
+%116 = OpLabel
+%121 = OpAccessChain %_ptr_Uniform_v4float %10 %int_3
+%123 = OpLoad %v4float %121
+OpStore %113 %123
+OpBranch %117
+%117 = OpLabel
+%124 = OpLoad %v4float %113
+OpReturnValue %124
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/RoundEven.glsl b/tests/sksl/intrinsics/RoundEven.glsl
index b4b90ab..8aa8a1f 100644
--- a/tests/sksl/intrinsics/RoundEven.glsl
+++ b/tests/sksl/intrinsics/RoundEven.glsl
@@ -1,6 +1,9 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = roundEven(a);
+uniform vec4 input;
+uniform vec4 expected;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    return ((((((roundEven(input.x) == expected.x && roundEven(input.xy) == expected.xy) && roundEven(input.xyz) == expected.xyz) && roundEven(input) == expected) && -2.0 == expected.x) && vec2(-2.0, -0.0) == expected.xy) && vec3(-2.0, -0.0, 0.0) == expected.xyz) && vec4(-2.0, -0.0, 0.0, 2.0) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/RoundEven.metal b/tests/sksl/intrinsics/RoundEven.metal
index 65d72c3..7b8f8ef 100644
--- a/tests/sksl/intrinsics/RoundEven.metal
+++ b/tests/sksl/intrinsics/RoundEven.metal
@@ -2,7 +2,10 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 input;
+    float4 expected;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +16,6 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = rint(_uniforms.a);
+    _out.sk_FragColor = ((((((rint(_uniforms.input.x) == _uniforms.expected.x && all(rint(_uniforms.input.xy) == _uniforms.expected.xy)) && all(rint(_uniforms.input.xyz) == _uniforms.expected.xyz)) && all(rint(_uniforms.input) == _uniforms.expected)) && -2.0 == _uniforms.expected.x) && all(float2(-2.0, -0.0) == _uniforms.expected.xy)) && all(float3(-2.0, -0.0, 0.0) == _uniforms.expected.xyz)) && all(float4(-2.0, -0.0, 0.0, 2.0) == _uniforms.expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }
diff --git a/tests/sksl/intrinsics/Saturate.asm.frag b/tests/sksl/intrinsics/Saturate.asm.frag
index 91374f0..afc166a 100644
--- a/tests/sksl/intrinsics/Saturate.asm.frag
+++ b/tests/sksl/intrinsics/Saturate.asm.frag
@@ -1,23 +1,57 @@
 OpCapability Shader
 %1 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
-OpEntryPoint Fragment %main "main" %sk_FragColor %sk_Clockwise
-OpExecutionMode %main OriginUpperLeft
+OpEntryPoint Fragment %_entrypoint_v "_entrypoint" %sk_FragColor %sk_Clockwise
+OpExecutionMode %_entrypoint_v OriginUpperLeft
 OpName %sk_FragColor "sk_FragColor"
 OpName %sk_Clockwise "sk_Clockwise"
 OpName %_UniformBuffer "_UniformBuffer"
-OpMemberName %_UniformBuffer 0 "a"
+OpMemberName %_UniformBuffer 0 "testInputs"
+OpMemberName %_UniformBuffer 1 "colorGreen"
+OpMemberName %_UniformBuffer 2 "colorRed"
+OpName %_entrypoint_v "_entrypoint_v"
 OpName %main "main"
+OpName %expected "expected"
 OpDecorate %sk_FragColor RelaxedPrecision
 OpDecorate %sk_FragColor Location 0
 OpDecorate %sk_FragColor Index 0
 OpDecorate %sk_Clockwise BuiltIn FrontFacing
 OpMemberDecorate %_UniformBuffer 0 Offset 0
 OpMemberDecorate %_UniformBuffer 0 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 1 Offset 16
+OpMemberDecorate %_UniformBuffer 1 RelaxedPrecision
+OpMemberDecorate %_UniformBuffer 2 Offset 32
+OpMemberDecorate %_UniformBuffer 2 RelaxedPrecision
 OpDecorate %_UniformBuffer Block
 OpDecorate %10 Binding 0
 OpDecorate %10 DescriptorSet 0
-OpDecorate %21 RelaxedPrecision
+OpDecorate %expected RelaxedPrecision
+OpDecorate %30 RelaxedPrecision
+OpDecorate %37 RelaxedPrecision
+OpDecorate %38 RelaxedPrecision
+OpDecorate %39 RelaxedPrecision
+OpDecorate %40 RelaxedPrecision
+OpDecorate %46 RelaxedPrecision
+OpDecorate %47 RelaxedPrecision
+OpDecorate %50 RelaxedPrecision
+OpDecorate %51 RelaxedPrecision
+OpDecorate %60 RelaxedPrecision
+OpDecorate %61 RelaxedPrecision
+OpDecorate %65 RelaxedPrecision
+OpDecorate %66 RelaxedPrecision
+OpDecorate %75 RelaxedPrecision
+OpDecorate %78 RelaxedPrecision
+OpDecorate %85 RelaxedPrecision
+OpDecorate %86 RelaxedPrecision
+OpDecorate %91 RelaxedPrecision
+OpDecorate %92 RelaxedPrecision
+OpDecorate %98 RelaxedPrecision
+OpDecorate %99 RelaxedPrecision
+OpDecorate %100 RelaxedPrecision
+OpDecorate %106 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %119 RelaxedPrecision
+OpDecorate %120 RelaxedPrecision
 %float = OpTypeFloat 32
 %v4float = OpTypeVector %float 4
 %_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -25,23 +59,149 @@
 %bool = OpTypeBool
 %_ptr_Input_bool = OpTypePointer Input %bool
 %sk_Clockwise = OpVariable %_ptr_Input_bool Input
-%_UniformBuffer = OpTypeStruct %float
+%_UniformBuffer = OpTypeStruct %v4float %v4float %v4float
 %_ptr_Uniform__UniformBuffer = OpTypePointer Uniform %_UniformBuffer
 %10 = OpVariable %_ptr_Uniform__UniformBuffer Uniform
 %void = OpTypeVoid
-%14 = OpTypeFunction %void
-%_ptr_Uniform_float = OpTypePointer Uniform %float
+%15 = OpTypeFunction %void
+%v2float = OpTypeVector %float 2
+%float_0 = OpConstant %float 0
+%19 = OpConstantComposite %v2float %float_0 %float_0
+%_ptr_Function_v2float = OpTypePointer Function %v2float
+%23 = OpTypeFunction %v4float %_ptr_Function_v2float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+%float_0_75 = OpConstant %float 0.75
+%float_1 = OpConstant %float 1
+%30 = OpConstantComposite %v4float %float_0 %float_0 %float_0_75 %float_1
+%false = OpConstantFalse %bool
+%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
 %int = OpTypeInt 32 1
 %int_0 = OpConstant %int 0
-%float_0 = OpConstant %float 0
-%float_1 = OpConstant %float 1
-%_ptr_Output_float = OpTypePointer Output %float
-%main = OpFunction %void None %14
-%15 = OpLabel
-%17 = OpAccessChain %_ptr_Uniform_float %10 %int_0
-%21 = OpLoad %float %17
-%16 = OpExtInst %float %1 FClamp %21 %float_0 %float_1
-%24 = OpAccessChain %_ptr_Output_float %sk_FragColor %int_0
-OpStore %24 %16
+%v2bool = OpTypeVector %bool 2
+%v3float = OpTypeVector %float 3
+%v3bool = OpTypeVector %bool 3
+%v4bool = OpTypeVector %bool 4
+%98 = OpConstantComposite %v3float %float_0 %float_0 %float_0_75
+%int_1 = OpConstant %int 1
+%int_2 = OpConstant %int 2
+%_entrypoint_v = OpFunction %void None %15
+%16 = OpLabel
+%20 = OpVariable %_ptr_Function_v2float Function
+OpStore %20 %19
+%22 = OpFunctionCall %v4float %main %20
+OpStore %sk_FragColor %22
 OpReturn
 OpFunctionEnd
+%main = OpFunction %v4float None %23
+%24 = OpFunctionParameter %_ptr_Function_v2float
+%25 = OpLabel
+%expected = OpVariable %_ptr_Function_v4float Function
+%110 = OpVariable %_ptr_Function_v4float Function
+OpStore %expected %30
+%33 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%37 = OpLoad %v4float %33
+%38 = OpCompositeExtract %float %37 0
+%32 = OpExtInst %float %1 FClamp %38 %float_0 %float_1
+%39 = OpLoad %v4float %expected
+%40 = OpCompositeExtract %float %39 0
+%41 = OpFOrdEqual %bool %32 %40
+OpSelectionMerge %43 None
+OpBranchConditional %41 %42 %43
+%42 = OpLabel
+%45 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%46 = OpLoad %v4float %45
+%47 = OpVectorShuffle %v2float %46 %46 0 1
+%48 = OpCompositeConstruct %v2float %float_0 %float_0
+%49 = OpCompositeConstruct %v2float %float_1 %float_1
+%44 = OpExtInst %v2float %1 FClamp %47 %48 %49
+%50 = OpLoad %v4float %expected
+%51 = OpVectorShuffle %v2float %50 %50 0 1
+%52 = OpFOrdEqual %v2bool %44 %51
+%54 = OpAll %bool %52
+OpBranch %43
+%43 = OpLabel
+%55 = OpPhi %bool %false %25 %54 %42
+OpSelectionMerge %57 None
+OpBranchConditional %55 %56 %57
+%56 = OpLabel
+%59 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%60 = OpLoad %v4float %59
+%61 = OpVectorShuffle %v3float %60 %60 0 1 2
+%63 = OpCompositeConstruct %v3float %float_0 %float_0 %float_0
+%64 = OpCompositeConstruct %v3float %float_1 %float_1 %float_1
+%58 = OpExtInst %v3float %1 FClamp %61 %63 %64
+%65 = OpLoad %v4float %expected
+%66 = OpVectorShuffle %v3float %65 %65 0 1 2
+%67 = OpFOrdEqual %v3bool %58 %66
+%69 = OpAll %bool %67
+OpBranch %57
+%57 = OpLabel
+%70 = OpPhi %bool %false %43 %69 %56
+OpSelectionMerge %72 None
+OpBranchConditional %70 %71 %72
+%71 = OpLabel
+%74 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%75 = OpLoad %v4float %74
+%76 = OpCompositeConstruct %v4float %float_0 %float_0 %float_0 %float_0
+%77 = OpCompositeConstruct %v4float %float_1 %float_1 %float_1 %float_1
+%73 = OpExtInst %v4float %1 FClamp %75 %76 %77
+%78 = OpLoad %v4float %expected
+%79 = OpFOrdEqual %v4bool %73 %78
+%81 = OpAll %bool %79
+OpBranch %72
+%72 = OpLabel
+%82 = OpPhi %bool %false %57 %81 %71
+OpSelectionMerge %84 None
+OpBranchConditional %82 %83 %84
+%83 = OpLabel
+%85 = OpLoad %v4float %expected
+%86 = OpCompositeExtract %float %85 0
+%87 = OpFOrdEqual %bool %float_0 %86
+OpBranch %84
+%84 = OpLabel
+%88 = OpPhi %bool %false %72 %87 %83
+OpSelectionMerge %90 None
+OpBranchConditional %88 %89 %90
+%89 = OpLabel
+%91 = OpLoad %v4float %expected
+%92 = OpVectorShuffle %v2float %91 %91 0 1
+%93 = OpFOrdEqual %v2bool %19 %92
+%94 = OpAll %bool %93
+OpBranch %90
+%90 = OpLabel
+%95 = OpPhi %bool %false %84 %94 %89
+OpSelectionMerge %97 None
+OpBranchConditional %95 %96 %97
+%96 = OpLabel
+%99 = OpLoad %v4float %expected
+%100 = OpVectorShuffle %v3float %99 %99 0 1 2
+%101 = OpFOrdEqual %v3bool %98 %100
+%102 = OpAll %bool %101
+OpBranch %97
+%97 = OpLabel
+%103 = OpPhi %bool %false %90 %102 %96
+OpSelectionMerge %105 None
+OpBranchConditional %103 %104 %105
+%104 = OpLabel
+%106 = OpLoad %v4float %expected
+%107 = OpFOrdEqual %v4bool %30 %106
+%108 = OpAll %bool %107
+OpBranch %105
+%105 = OpLabel
+%109 = OpPhi %bool %false %97 %108 %104
+OpSelectionMerge %113 None
+OpBranchConditional %109 %111 %112
+%111 = OpLabel
+%114 = OpAccessChain %_ptr_Uniform_v4float %10 %int_1
+%116 = OpLoad %v4float %114
+OpStore %110 %116
+OpBranch %113
+%112 = OpLabel
+%117 = OpAccessChain %_ptr_Uniform_v4float %10 %int_2
+%119 = OpLoad %v4float %117
+OpStore %110 %119
+OpBranch %113
+%113 = OpLabel
+%120 = OpLoad %v4float %110
+OpReturnValue %120
+OpFunctionEnd
diff --git a/tests/sksl/intrinsics/Saturate.glsl b/tests/sksl/intrinsics/Saturate.glsl
index e5fbc2c..e3a8eef 100644
--- a/tests/sksl/intrinsics/Saturate.glsl
+++ b/tests/sksl/intrinsics/Saturate.glsl
@@ -1,6 +1,9 @@
 
 out vec4 sk_FragColor;
-uniform float a;
-void main() {
-    sk_FragColor.x = clamp(a, 0.0, 1.0);
+uniform vec4 testInputs;
+uniform vec4 colorGreen;
+uniform vec4 colorRed;
+vec4 main() {
+    vec4 expected = vec4(0.0, 0.0, 0.75, 1.0);
+    return ((((((clamp(testInputs.x, 0.0, 1.0) == expected.x && clamp(testInputs.xy, 0.0, 1.0) == expected.xy) && clamp(testInputs.xyz, 0.0, 1.0) == expected.xyz) && clamp(testInputs, 0.0, 1.0) == expected) && 0.0 == expected.x) && vec2(0.0, 0.0) == expected.xy) && vec3(0.0, 0.0, 0.75) == expected.xyz) && vec4(0.0, 0.0, 0.75, 1.0) == expected ? colorGreen : colorRed;
 }
diff --git a/tests/sksl/intrinsics/Saturate.metal b/tests/sksl/intrinsics/Saturate.metal
index 2715297..3a5d925 100644
--- a/tests/sksl/intrinsics/Saturate.metal
+++ b/tests/sksl/intrinsics/Saturate.metal
@@ -2,7 +2,9 @@
 #include <simd/simd.h>
 using namespace metal;
 struct Uniforms {
-    float a;
+    float4 testInputs;
+    float4 colorGreen;
+    float4 colorRed;
 };
 struct Inputs {
 };
@@ -13,6 +15,7 @@
 fragment Outputs fragmentMain(Inputs _in [[stage_in]], constant Uniforms& _uniforms [[buffer(0)]], bool _frontFacing [[front_facing]], float4 _fragCoord [[position]]) {
     Outputs _out;
     (void)_out;
-    _out.sk_FragColor.x = saturate(_uniforms.a);
+    float4 expected = float4(0.0, 0.0, 0.75, 1.0);
+    _out.sk_FragColor = ((((((saturate(_uniforms.testInputs.x) == expected.x && all(saturate(_uniforms.testInputs.xy) == expected.xy)) && all(saturate(_uniforms.testInputs.xyz) == expected.xyz)) && all(saturate(_uniforms.testInputs) == expected)) && 0.0 == expected.x) && all(float2(0.0, 0.0) == expected.xy)) && all(float3(0.0, 0.0, 0.75) == expected.xyz)) && all(float4(0.0, 0.0, 0.75, 1.0) == expected) ? _uniforms.colorGreen : _uniforms.colorRed;
     return _out;
 }