Revert "Revert "support for 'half' types in sksl, plus general numeric type improvements""

This reverts commit 0e9605542444a7653359f4fc610f7620df9f6313.

Bug: skia:
Change-Id: Id45d091c1950887316c901ed9c9281181f346bcf
Reviewed-on: https://skia-review.googlesource.com/29602
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index 3b70493..17b94ff 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -28,12 +28,12 @@
                 "0.0039215686274509803;\n        break;\n    case 1:\n        range = "
                 "0.015873015873015872;\n        break;\n    default:\n        range = "
                 "0.0083333333333333332;\n        break;\n}\n@if (sk_Caps.integerSupport) {\n    "
-                "int x = int(sk_FragCoord.x);\n    int y = int(sk_FragCoord.y);\n    uint m = "
-                "uint((((((y & 1) << 5 | (x & 1) << 4) | (y & 2) << 2) | (x & 2) << 1) | (y & 4) "
-                ">> 1) | (x & 4) >> 2);\n    value = float(m) / 64.0 - 0.4921875;\n} else {\n    "
-                "value = fract(sin(dot(sk_FragCoord.xy, float2(12.989800000000001, "
-                "78.233000000000004))) * 43758.545299999998) - 0.5;\n}\n%s = float4(clamp(%s.xyz + "
-                "value * range, 0.0, %s.w), %s.w);\n",
+                "uint x = uint(sk_FragCoord.x);\n    uint y = uint(sk_FragCoord.y);\n    uint m = "
+                "(((((y & 1) << 5 | (x & 1) << 4) | (y & 2) << 2) | (x & 2) << 1) | (y & 4) >> 1) "
+                "| (x & 4) >> 2;\n    value = float(m) / 64.0 - 0.4921875;\n} else {\n    value = "
+                "fract(sin(dot(sk_FragCoord.xy, float2(12.989800000000001, 78.233000000000004))) * "
+                "43758.545299999998) - 0.5;\n}\n%s = float4(clamp(%s.xyz + value * range, 0.0, "
+                "%s.w), %s.w);\n",
                 _outer.rangeType(), args.fOutputColor,
                 args.fInputColor ? args.fInputColor : "float4(1)",
                 args.fInputColor ? args.fInputColor : "float4(1)",
diff --git a/src/gpu/effects/GrDitherEffect.fp b/src/gpu/effects/GrDitherEffect.fp
index f983702..308e02e 100644
--- a/src/gpu/effects/GrDitherEffect.fp
+++ b/src/gpu/effects/GrDitherEffect.fp
@@ -48,8 +48,8 @@
     }
     @if (sk_Caps.integerSupport) {
         // This ordered-dither code is lifted from the cpu backend.
-        int x = int(sk_FragCoord.x);
-        int y = int(sk_FragCoord.y);
+        uint x = uint(sk_FragCoord.x);
+        uint y = uint(sk_FragCoord.y);
         uint m = (y & 1) << 5 | (x & 1) << 4 |
                  (y & 2) << 2 | (x & 2) << 1 |
                  (y & 4) >> 1 | (x & 4) >> 2;
diff --git a/src/gpu/instanced/InstanceProcessor.cpp b/src/gpu/instanced/InstanceProcessor.cpp
index 28095da..d3cc9fa 100644
--- a/src/gpu/instanced/InstanceProcessor.cpp
+++ b/src/gpu/instanced/InstanceProcessor.cpp
@@ -238,7 +238,7 @@
         v->defineConstantf("int", "PERSPECTIVE_FLAG", "0x%x", kPerspective_InfoFlag);
         v->codeAppendf("float3x3 shapeMatrix = float3x3(%s, %s, float3(0, 0, 1));",
                        inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY));
-        v->codeAppendf("if (0 != (%s & PERSPECTIVE_FLAG)) {",
+        v->codeAppendf("if (0 != (%s & uint(PERSPECTIVE_FLAG))) {",
                        inputs.attr(Attrib::kInstanceInfo));
         v->codeAppend (    "shapeMatrix[2] = ");
         inputs.fetchNextParam(kVec3f_GrSLType);
@@ -249,7 +249,7 @@
     bool hasSingleShapeType = SkIsPow2(ip.opInfo().fShapeTypes);
     if (!hasSingleShapeType) {
         v->defineConstant("SHAPE_TYPE_BIT", kShapeType_InfoBit);
-        v->codeAppendf("uint shapeType = %s >> SHAPE_TYPE_BIT;",
+        v->codeAppendf("uint shapeType = %s >> uint(SHAPE_TYPE_BIT);",
                        inputs.attr(Attrib::kInstanceInfo));
     }
 
@@ -268,7 +268,7 @@
         }
     } else {
         if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) {
-            v->codeAppend ("if (shapeType >= SIMPLE_R_RECT_SHAPE_TYPE) {");
+            v->codeAppend ("if (shapeType >= uint(SIMPLE_R_RECT_SHAPE_TYPE)) {");
             backend->setupRRect(v, &usedShapeDefinitions);
             v->codeAppend ("}");
             usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
@@ -278,7 +278,7 @@
                 if (ip.opInfo().fShapeTypes & kRRect_ShapesMask) {
                     v->codeAppend ("else ");
                 }
-                v->codeAppend ("if (OVAL_SHAPE_TYPE == shapeType) {");
+                v->codeAppend ("if (uint(OVAL_SHAPE_TYPE) == shapeType) {");
                 usedShapeDefinitions |= kOval_ShapeFlag;
             } else {
                 v->codeAppend ("else {");
@@ -298,8 +298,8 @@
         if (!hasSingleInnerShapeType) {
             v->defineConstantf("int", "INNER_SHAPE_TYPE_MASK", "0x%x", kInnerShapeType_InfoMask);
             v->defineConstant("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit);
-            v->codeAppendf("uint innerShapeType = ((%s & INNER_SHAPE_TYPE_MASK) >> "
-                                                  "INNER_SHAPE_TYPE_BIT);",
+            v->codeAppendf("uint innerShapeType = ((%s & uint(INNER_SHAPE_TYPE_MASK)) >> "
+                                                  "uint(INNER_SHAPE_TYPE_BIT));",
                            inputs.attr(Attrib::kInstanceInfo));
         }
         // Here we take advantage of the fact that outerRect == localRect in recordDRRect.
@@ -330,7 +330,7 @@
             }
         } else {
             if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) {
-                v->codeAppend ("if (SIMPLE_R_RECT_SHAPE_TYPE == innerShapeType) {");
+                v->codeAppend ("if (uint(SIMPLE_R_RECT_SHAPE_TYPE) == innerShapeType) {");
                 backend->setupInnerSimpleRRect(v);
                 v->codeAppend("}");
                 usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
@@ -340,7 +340,7 @@
                     if (ip.opInfo().fInnerShapeTypes & kSimpleRRect_ShapeFlag) {
                         v->codeAppend ("else ");
                     }
-                    v->codeAppend ("if (OVAL_SHAPE_TYPE == innerShapeType) {");
+                    v->codeAppend ("if (uint(OVAL_SHAPE_TYPE) == innerShapeType) {");
                     usedShapeDefinitions |= kOval_ShapeFlag;
                 } else {
                     v->codeAppend ("else {");
@@ -378,7 +378,7 @@
     }
     if (ip.opInfo().fHasLocalMatrix && ip.opInfo().fHasParams) {
         v->defineConstantf("int", "LOCAL_MATRIX_FLAG", "0x%x", kLocalMatrix_InfoFlag);
-        v->codeAppendf("if (0 != (%s & LOCAL_MATRIX_FLAG)) {",
+        v->codeAppendf("if (0 != (%s & uint(LOCAL_MATRIX_FLAG))) {",
                        inputs.attr(Attrib::kInstanceInfo));
         if (!ip.opInfo().fUsesLocalCoords) {
             inputs.skipParams(2);
@@ -421,7 +421,7 @@
 }
 
 void GLSLInstanceProcessor::Backend::setupRRect(GrGLSLVertexBuilder* v, int* usedShapeDefinitions) {
-    v->codeAppendf("uint2 corner = uint2(%s & 1, (%s >> 1) & 1);",
+    v->codeAppendf("uint2 corner = uint2(uint(%s) & 1, (uint(%s) >> 1) & 1);",
                    fInputs.attr(Attrib::kVertexAttrs), fInputs.attr(Attrib::kVertexAttrs));
     v->codeAppend ("float2 cornerSign = float2(corner) * 2.0 - 1.0;");
     v->codeAppendf("float2 radii%s;", fNeedsNeighborRadii ? ", neighborRadii" : "");
@@ -439,7 +439,7 @@
         }
     } else {
         if (types & kSimpleRRect_ShapeFlag) {
-            v->codeAppend ("if (SIMPLE_R_RECT_SHAPE_TYPE == shapeType) {");
+            v->codeAppend ("if (uint(SIMPLE_R_RECT_SHAPE_TYPE) == shapeType) {");
             this->setupSimpleRadii(v);
             v->codeAppend ("}");
             *usedShapeDefinitions |= kSimpleRRect_ShapeFlag;
@@ -449,7 +449,7 @@
                 if (types & kSimpleRRect_ShapeFlag) {
                     v->codeAppend ("else ");
                 }
-                v->codeAppend ("if (NINE_PATCH_SHAPE_TYPE == shapeType) {");
+                v->codeAppend ("if (uint(NINE_PATCH_SHAPE_TYPE) == shapeType) {");
                 *usedShapeDefinitions |= kNinePatch_ShapeFlag;
             } else {
                 v->codeAppend ("else {");
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index 2276ce3..76faef9 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -181,6 +181,10 @@
     ABORT("should have found sampler in parameters\n");
 }
 
+void CPPCodeGenerator::writeIntLiteral(const IntLiteral& i) {
+    this->write(to_string((int32_t) i.fValue));
+}
+
 void CPPCodeGenerator::writeVariableReference(const VariableReference& ref) {
     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
         case SK_INCOLOR_BUILTIN:
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index b4f31ba..27b434a 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -39,6 +39,8 @@
 
     void writeIndexExpression(const IndexExpression& i) override;
 
+    void writeIntLiteral(const IntLiteral& i) override;
+
     void writeVariableReference(const VariableReference& ref) override;
 
     String getSamplerHandle(const Variable& var);
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index d96515c..4ea956c 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -68,6 +68,10 @@
     ADD_TYPE(Float2);
     ADD_TYPE(Float3);
     ADD_TYPE(Float4);
+    ADD_TYPE(Half);
+    ADD_TYPE(Half2);
+    ADD_TYPE(Half3);
+    ADD_TYPE(Half4);
     ADD_TYPE(Double);
     ADD_TYPE(Double2);
     ADD_TYPE(Double3);
@@ -80,6 +84,14 @@
     ADD_TYPE(UInt2);
     ADD_TYPE(UInt3);
     ADD_TYPE(UInt4);
+    ADD_TYPE(Short);
+    ADD_TYPE(Short2);
+    ADD_TYPE(Short3);
+    ADD_TYPE(Short4);
+    ADD_TYPE(UShort);
+    ADD_TYPE(UShort2);
+    ADD_TYPE(UShort3);
+    ADD_TYPE(UShort4);
     ADD_TYPE(Bool);
     ADD_TYPE(Bool2);
     ADD_TYPE(Bool3);
@@ -93,7 +105,26 @@
     ADD_TYPE(Float4x2);
     ADD_TYPE(Float4x3);
     ADD_TYPE(Float4x4);
+    ADD_TYPE(Half2x2);
+    ADD_TYPE(Half2x3);
+    ADD_TYPE(Half2x4);
+    ADD_TYPE(Half3x2);
+    ADD_TYPE(Half3x3);
+    ADD_TYPE(Half3x4);
+    ADD_TYPE(Half4x2);
+    ADD_TYPE(Half4x3);
+    ADD_TYPE(Half4x4);
+    ADD_TYPE(Double2x2);
+    ADD_TYPE(Double2x3);
+    ADD_TYPE(Double2x4);
+    ADD_TYPE(Double3x2);
+    ADD_TYPE(Double3x3);
+    ADD_TYPE(Double3x4);
+    ADD_TYPE(Double4x2);
+    ADD_TYPE(Double4x3);
+    ADD_TYPE(Double4x4);
     ADD_TYPE(GenType);
+    ADD_TYPE(GenHType);
     ADD_TYPE(GenDType);
     ADD_TYPE(GenIType);
     ADD_TYPE(GenUType);
@@ -104,9 +135,12 @@
     ADD_TYPE(GVec2);
     ADD_TYPE(GVec3);
     ADD_TYPE(GVec4);
+    ADD_TYPE(HVec);
     ADD_TYPE(DVec);
     ADD_TYPE(IVec);
     ADD_TYPE(UVec);
+    ADD_TYPE(SVec);
+    ADD_TYPE(USVec);
     ADD_TYPE(BVec);
 
     ADD_TYPE(Sampler1D);
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index 2de584f..b132cec 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -21,45 +21,65 @@
     Context()
     : fInvalid_Type(new Type(String("<INVALID>")))
     , fVoid_Type(new Type(String("void")))
-    , fDouble_Type(new Type(String("double"), true))
+    , fDouble_Type(new Type(String("double"), Type::kFloat_NumberKind))
     , fDouble2_Type(new Type(String("double2"), *fDouble_Type, 2))
     , fDouble3_Type(new Type(String("double3"), *fDouble_Type, 3))
     , fDouble4_Type(new Type(String("double4"), *fDouble_Type, 4))
-    , fFloat_Type(new Type(String("float"), true, { fDouble_Type.get() }))
+    , fFloat_Type(new Type(String("float"), Type::kFloat_NumberKind))
     , fFloat2_Type(new Type(String("float2"), *fFloat_Type, 2))
     , fFloat3_Type(new Type(String("float3"), *fFloat_Type, 3))
     , fFloat4_Type(new Type(String("float4"), *fFloat_Type, 4))
-    , fUInt_Type(new Type(String("uint"), true, { fFloat_Type.get(), fDouble_Type.get() }))
+    , fHalf_Type(new Type(String("half"), Type::kFloat_NumberKind))
+    , fHalf2_Type(new Type(String("half2"), *fHalf_Type, 2))
+    , fHalf3_Type(new Type(String("half3"), *fHalf_Type, 3))
+    , fHalf4_Type(new Type(String("half4"), *fHalf_Type, 4))
+    , fUInt_Type(new Type(String("uint"), Type::kUnsigned_NumberKind))
     , fUInt2_Type(new Type(String("uint2"), *fUInt_Type, 2))
     , fUInt3_Type(new Type(String("uint3"), *fUInt_Type, 3))
     , fUInt4_Type(new Type(String("uint4"), *fUInt_Type, 4))
-    , fInt_Type(new Type(String("int"), true, { fUInt_Type.get(), fFloat_Type.get(),
-                                                  fDouble_Type.get() }))
+    , fInt_Type(new Type(String("int"), Type::kSigned_NumberKind))
     , fInt2_Type(new Type(String("int2"), *fInt_Type, 2))
     , fInt3_Type(new Type(String("int3"), *fInt_Type, 3))
     , fInt4_Type(new Type(String("int4"), *fInt_Type, 4))
-    , fBool_Type(new Type(String("bool"), false))
+    , fUShort_Type(new Type(String("ushort"), Type::kUnsigned_NumberKind))
+    , fUShort2_Type(new Type(String("ushort2"), *fUShort_Type, 2))
+    , fUShort3_Type(new Type(String("ushort3"), *fUShort_Type, 3))
+    , fUShort4_Type(new Type(String("ushort4"), *fUShort_Type, 4))
+    , fShort_Type(new Type(String("short"), Type::kSigned_NumberKind))
+    , fShort2_Type(new Type(String("short2"), *fShort_Type, 2))
+    , fShort3_Type(new Type(String("short3"), *fShort_Type, 3))
+    , fShort4_Type(new Type(String("short4"), *fShort_Type, 4))
+    , fBool_Type(new Type(String("bool"), Type::kNonnumeric_NumberKind))
     , fBool2_Type(new Type(String("bool2"), *fBool_Type, 2))
     , fBool3_Type(new Type(String("bool3"), *fBool_Type, 3))
     , fBool4_Type(new Type(String("bool4"), *fBool_Type, 4))
-    , fFloat2x2_Type(new Type(String("float2x2"),   *fFloat_Type, 2, 2))
+    , fFloat2x2_Type(new Type(String("float2x2"), *fFloat_Type, 2, 2))
     , fFloat2x3_Type(new Type(String("float2x3"), *fFloat_Type, 2, 3))
     , fFloat2x4_Type(new Type(String("float2x4"), *fFloat_Type, 2, 4))
     , fFloat3x2_Type(new Type(String("float3x2"), *fFloat_Type, 3, 2))
-    , fFloat3x3_Type(new Type(String("float3x3"),   *fFloat_Type, 3, 3))
+    , fFloat3x3_Type(new Type(String("float3x3"), *fFloat_Type, 3, 3))
     , fFloat3x4_Type(new Type(String("float3x4"), *fFloat_Type, 3, 4))
     , fFloat4x2_Type(new Type(String("float4x2"), *fFloat_Type, 4, 2))
     , fFloat4x3_Type(new Type(String("float4x3"), *fFloat_Type, 4, 3))
-    , fFloat4x4_Type(new Type(String("float4x4"),   *fFloat_Type, 4, 4))
-    , fDouble2x2_Type(new Type(String("double2x2"),   *fFloat_Type, 2, 2))
-    , fDouble2x3_Type(new Type(String("double2x3"), *fFloat_Type, 2, 3))
-    , fDouble2x4_Type(new Type(String("double2x4"), *fFloat_Type, 2, 4))
-    , fDouble3x2_Type(new Type(String("double3x2"), *fFloat_Type, 3, 2))
-    , fDouble3x3_Type(new Type(String("double3x3"),   *fFloat_Type, 3, 3))
-    , fDouble3x4_Type(new Type(String("double3x4"), *fFloat_Type, 3, 4))
-    , fDouble4x2_Type(new Type(String("double4x2"), *fFloat_Type, 4, 2))
-    , fDouble4x3_Type(new Type(String("double4x3"), *fFloat_Type, 4, 3))
-    , fDouble4x4_Type(new Type(String("double4x4"),   *fFloat_Type, 4, 4))
+    , fFloat4x4_Type(new Type(String("float4x4"), *fFloat_Type, 4, 4))
+    , fHalf2x2_Type(new Type(String("half2x2"), *fHalf_Type, 2, 2))
+    , fHalf2x3_Type(new Type(String("half2x3"), *fHalf_Type, 2, 3))
+    , fHalf2x4_Type(new Type(String("half2x4"), *fHalf_Type, 2, 4))
+    , fHalf3x2_Type(new Type(String("half3x2"), *fHalf_Type, 3, 2))
+    , fHalf3x3_Type(new Type(String("half3x3"), *fHalf_Type, 3, 3))
+    , fHalf3x4_Type(new Type(String("half3x4"), *fHalf_Type, 3, 4))
+    , fHalf4x2_Type(new Type(String("half4x2"), *fHalf_Type, 4, 2))
+    , fHalf4x3_Type(new Type(String("half4x3"), *fHalf_Type, 4, 3))
+    , fHalf4x4_Type(new Type(String("half4x4"), *fHalf_Type, 4, 4))
+    , fDouble2x2_Type(new Type(String("double2x2"), *fDouble_Type, 2, 2))
+    , fDouble2x3_Type(new Type(String("double2x3"), *fDouble_Type, 2, 3))
+    , fDouble2x4_Type(new Type(String("double2x4"), *fDouble_Type, 2, 4))
+    , fDouble3x2_Type(new Type(String("double3x2"), *fDouble_Type, 3, 2))
+    , fDouble3x3_Type(new Type(String("double3x3"), *fDouble_Type, 3, 3))
+    , fDouble3x4_Type(new Type(String("double3x4"), *fDouble_Type, 3, 4))
+    , fDouble4x2_Type(new Type(String("double4x2"), *fDouble_Type, 4, 2))
+    , fDouble4x3_Type(new Type(String("double4x3"), *fDouble_Type, 4, 3))
+    , fDouble4x4_Type(new Type(String("double4x4"), *fDouble_Type, 4, 4))
     , fSampler1D_Type(new Type(String("sampler1D"), SpvDim1D, false, false, false, true))
     , fSampler2D_Type(new Type(String("sampler2D"), SpvDim2D, false, false, false, true))
     , fSampler3D_Type(new Type(String("sampler3D"), SpvDim3D, false, false, false, true))
@@ -118,6 +138,8 @@
                                              static_type(*fSamplerCubeArrayShadow_Type)))
     , fGenType_Type(new Type(String("$genType"), { fFloat_Type.get(), fFloat2_Type.get(),
                                                    fFloat3_Type.get(), fFloat4_Type.get() }))
+    , fGenHType_Type(new Type(String("$genHType"), { fHalf_Type.get(), fHalf2_Type.get(),
+                                                     fHalf3_Type.get(), fHalf4_Type.get() }))
     , fGenDType_Type(new Type(String("$genDType"), { fDouble_Type.get(), fDouble2_Type.get(),
                                                      fDouble3_Type.get(), fDouble4_Type.get() }))
     , fGenIType_Type(new Type(String("$genIType"), { fInt_Type.get(), fInt2_Type.get(),
@@ -130,23 +152,34 @@
                                            fFloat2x4_Type.get(),  fFloat3x2_Type.get(),
                                            fFloat3x3_Type.get(),  fFloat3x4_Type.get(),
                                            fFloat4x2_Type.get(),  fFloat4x3_Type.get(),
-                                           fFloat4x4_Type.get(),  fDouble2x2_Type.get(),
-                                           fDouble2x3_Type.get(), fDouble2x4_Type.get(),
-                                           fDouble3x2_Type.get(), fDouble3x3_Type.get(),
-                                           fDouble3x4_Type.get(), fDouble4x2_Type.get(),
-                                           fDouble4x3_Type.get(), fDouble4x4_Type.get() }))
+                                           fFloat4x4_Type.get(),  fHalf2x2_Type.get(),
+                                           fHalf2x3_Type.get(),   fHalf2x4_Type.get(),
+                                           fHalf3x2_Type.get(),   fHalf3x3_Type.get(),
+                                           fHalf3x4_Type.get(),   fHalf4x2_Type.get(),
+                                           fHalf4x3_Type.get(),   fHalf4x4_Type.get(),
+                                           fDouble2x2_Type.get(), fDouble2x3_Type.get(),
+                                           fDouble2x4_Type.get(), fDouble3x2_Type.get(),
+                                           fDouble3x3_Type.get(), fDouble3x4_Type.get(),
+                                           fDouble4x2_Type.get(), fDouble4x3_Type.get(),
+                                           fDouble4x4_Type.get() }))
     , fVec_Type(new Type(String("$vec"), { fInvalid_Type.get(), fFloat2_Type.get(),
                                            fFloat3_Type.get(), fFloat4_Type.get() }))
     , fGVec_Type(new Type(String("$gvec")))
     , fGVec2_Type(new Type(String("$gfloat2")))
     , fGVec3_Type(new Type(String("$gfloat3")))
     , fGVec4_Type(new Type(String("$gfloat4"), static_type(*fFloat4_Type)))
+    , fHVec_Type(new Type(String("$hvec"), { fInvalid_Type.get(), fHalf2_Type.get(),
+                                             fHalf3_Type.get(), fHalf4_Type.get() }))
     , fDVec_Type(new Type(String("$dvec"), { fInvalid_Type.get(), fDouble2_Type.get(),
                                              fDouble3_Type.get(), fDouble4_Type.get() }))
     , fIVec_Type(new Type(String("$ivec"), { fInvalid_Type.get(), fInt2_Type.get(),
                                              fInt3_Type.get(), fInt4_Type.get() }))
     , fUVec_Type(new Type(String("$uvec"), { fInvalid_Type.get(), fUInt2_Type.get(),
                                              fUInt3_Type.get(), fUInt4_Type.get() }))
+    , fSVec_Type(new Type(String("$svec"), { fInvalid_Type.get(), fShort2_Type.get(),
+                                             fShort3_Type.get(), fShort4_Type.get() }))
+    , fUSVec_Type(new Type(String("$usvec"), { fInvalid_Type.get(), fUShort2_Type.get(),
+                                               fUShort3_Type.get(), fUShort4_Type.get() }))
     , fBVec_Type(new Type(String("$bvec"), { fInvalid_Type.get(), fBool2_Type.get(),
                                              fBool3_Type.get(), fBool4_Type.get() }))
     , fSkCaps_Type(new Type(String("$sk_Caps")))
@@ -171,6 +204,11 @@
     const std::unique_ptr<Type> fFloat3_Type;
     const std::unique_ptr<Type> fFloat4_Type;
 
+    const std::unique_ptr<Type> fHalf_Type;
+    const std::unique_ptr<Type> fHalf2_Type;
+    const std::unique_ptr<Type> fHalf3_Type;
+    const std::unique_ptr<Type> fHalf4_Type;
+
     const std::unique_ptr<Type> fUInt_Type;
     const std::unique_ptr<Type> fUInt2_Type;
     const std::unique_ptr<Type> fUInt3_Type;
@@ -181,6 +219,16 @@
     const std::unique_ptr<Type> fInt3_Type;
     const std::unique_ptr<Type> fInt4_Type;
 
+    const std::unique_ptr<Type> fUShort_Type;
+    const std::unique_ptr<Type> fUShort2_Type;
+    const std::unique_ptr<Type> fUShort3_Type;
+    const std::unique_ptr<Type> fUShort4_Type;
+
+    const std::unique_ptr<Type> fShort_Type;
+    const std::unique_ptr<Type> fShort2_Type;
+    const std::unique_ptr<Type> fShort3_Type;
+    const std::unique_ptr<Type> fShort4_Type;
+
     const std::unique_ptr<Type> fBool_Type;
     const std::unique_ptr<Type> fBool2_Type;
     const std::unique_ptr<Type> fBool3_Type;
@@ -196,6 +244,16 @@
     const std::unique_ptr<Type> fFloat4x3_Type;
     const std::unique_ptr<Type> fFloat4x4_Type;
 
+    const std::unique_ptr<Type> fHalf2x2_Type;
+    const std::unique_ptr<Type> fHalf2x3_Type;
+    const std::unique_ptr<Type> fHalf2x4_Type;
+    const std::unique_ptr<Type> fHalf3x2_Type;
+    const std::unique_ptr<Type> fHalf3x3_Type;
+    const std::unique_ptr<Type> fHalf3x4_Type;
+    const std::unique_ptr<Type> fHalf4x2_Type;
+    const std::unique_ptr<Type> fHalf4x3_Type;
+    const std::unique_ptr<Type> fHalf4x4_Type;
+
     const std::unique_ptr<Type> fDouble2x2_Type;
     const std::unique_ptr<Type> fDouble2x3_Type;
     const std::unique_ptr<Type> fDouble2x4_Type;
@@ -249,6 +307,7 @@
     const std::unique_ptr<Type> fGSamplerCubeArrayShadow_Type;
 
     const std::unique_ptr<Type> fGenType_Type;
+    const std::unique_ptr<Type> fGenHType_Type;
     const std::unique_ptr<Type> fGenDType_Type;
     const std::unique_ptr<Type> fGenIType_Type;
     const std::unique_ptr<Type> fGenUType_Type;
@@ -262,9 +321,12 @@
     const std::unique_ptr<Type> fGVec2_Type;
     const std::unique_ptr<Type> fGVec3_Type;
     const std::unique_ptr<Type> fGVec4_Type;
+    const std::unique_ptr<Type> fHVec_Type;
     const std::unique_ptr<Type> fDVec_Type;
     const std::unique_ptr<Type> fIVec_Type;
     const std::unique_ptr<Type> fUVec_Type;
+    const std::unique_ptr<Type> fSVec_Type;
+    const std::unique_ptr<Type> fUSVec_Type;
 
     const std::unique_ptr<Type> fBVec_Type;
 
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 330f145..69d3028 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -68,6 +68,7 @@
         fIndentation++;
         for (const auto& f : type.fields()) {
             this->writeModifiers(f.fModifiers, false);
+            this->writeTypePrecision(*f.fType);
             // sizes (which must be static in structs) are part of the type name here
             this->writeType(*f.fType);
             this->writeLine(" " + f.fName + ";");
@@ -78,32 +79,38 @@
         switch (type.kind()) {
             case Type::kVector_Kind: {
                 Type component = type.componentType();
-                if (component == *fContext.fFloat_Type) {
+                if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
                     this->write("vec");
                 }
                 else if (component == *fContext.fDouble_Type) {
                     this->write("dvec");
                 }
-                else if (component == *fContext.fInt_Type) {
+                else if (component == *fContext.fInt_Type || component == *fContext.fShort_Type) {
                     this->write("ivec");
                 }
-                else if (component == *fContext.fUInt_Type) {
+                else if (component == *fContext.fUInt_Type || component == *fContext.fUShort_Type) {
                     this->write("uvec");
                 }
                 else if (component == *fContext.fBool_Type) {
                     this->write("bvec");
                 }
+                else {
+                    ABORT("unsupported vector type");
+                }
                 this->write(to_string(type.columns()));
                 break;
             }
             case Type::kMatrix_Kind: {
                 Type component = type.componentType();
-                if (component == *fContext.fFloat_Type) {
+                if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
                     this->write("mat");
                 }
                 else if (component == *fContext.fDouble_Type) {
                     this->write("dmat");
                 }
+                else {
+                    ABORT("unsupported matrix type");
+                }
                 this->write(to_string(type.columns()));
                 if (type.columns() != type.rows()) {
                     this->write("x");
@@ -120,6 +127,21 @@
                 this->write("]");
                 break;
             }
+            case Type::kScalar_Kind: {
+                if (type == *fContext.fHalf_Type) {
+                    this->write("float");
+                }
+                else if (type == *fContext.fShort_Type) {
+                    this->write("int");
+                }
+                else if (type == *fContext.fUShort_Type) {
+                    this->write("uint");
+                }
+                else {
+                    this->write(type.name());
+                }
+                break;
+            }
             default:
                 this->write(type.name());
         }
@@ -653,6 +675,7 @@
     }
     for (const auto& f : structType->fields()) {
         this->writeModifiers(f.fModifiers, false);
+        this->writeTypePrecision(*f.fType);
         this->writeType(*f.fType);
         this->writeLine(" " + f.fName + ";");
     }
@@ -676,6 +699,25 @@
     this->writeExpression(value, kTopLevel_Precedence);
 }
 
+void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
+    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
+        switch (type.kind()) {
+            case Type::kScalar_Kind:
+                if (type == *fContext.fHalf_Type || type == *fContext.fShort_Type ||
+                        type == *fContext.fUShort_Type) {
+                    this->write("mediump ");
+                }
+                break;
+            case Type::kVector_Kind: // fall through
+            case Type::kMatrix_Kind:
+                this->writeTypePrecision(type.componentType());
+                break;
+            default:
+                break;
+        }
+    }
+}
+
 void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
     ASSERT(decl.fVars.size() > 0);
     bool wroteType = false;
@@ -685,6 +727,7 @@
             this->write(", ");
         } else {
             this->writeModifiers(var.fVar->fModifiers, global);
+            this->writeTypePrecision(decl.fBaseType);
             this->writeType(decl.fBaseType);
             this->write(" ");
             wroteType = true;
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 115d89a..e10299a 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -116,6 +116,8 @@
 
     virtual void writeVarInitializer(const Variable& var, const Expression& value);
 
+    void writeTypePrecision(const Type& type);
+
     void writeVarDeclarations(const VarDeclarations& decl, bool global);
 
     void writeFragCoord();
@@ -150,7 +152,7 @@
 
     void writeBoolLiteral(const BoolLiteral& b);
 
-    void writeIntLiteral(const IntLiteral& i);
+    virtual void writeIntLiteral(const IntLiteral& i);
 
     void writeFloatLiteral(const FloatLiteral& f);
 
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 3604cd9..a46a931 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -910,7 +910,7 @@
     if (expr->fType == *fContext.fInvalid_Type) {
         return nullptr;
     }
-    if (!expr->fType.canCoerceTo(type)) {
+    if (expr->coercionCost(type) == INT_MAX) {
         fErrors.error(expr->fPosition, "expected '" + type.description() + "', but found '" +
                                         expr->fType.description() + "'");
         return nullptr;
@@ -1213,8 +1213,20 @@
     const Type* leftType;
     const Type* rightType;
     const Type* resultType;
-    if (!determine_binary_type(fContext, expression.fOperator, left->fType, right->fType, &leftType,
-                               &rightType, &resultType,
+    const Type* rawLeftType;
+    if (left->fKind == Expression::kIntLiteral_Kind && right->fType.isInteger()) {
+        rawLeftType = &right->fType;
+    } else {
+        rawLeftType = &left->fType;
+    }
+    const Type* rawRightType;
+    if (right->fKind == Expression::kIntLiteral_Kind && left->fType.isInteger()) {
+        rawRightType = &left->fType;
+    } else {
+        rawRightType = &right->fType;
+    }
+    if (!determine_binary_type(fContext, expression.fOperator, *rawLeftType, *rawRightType,
+                               &leftType, &rightType, &resultType,
                                !Token::IsAssignment(expression.fOperator))) {
         fErrors.error(expression.fPosition, "type mismatch: '" +
                                             Token::OperatorName(expression.fOperator) +
@@ -1367,32 +1379,30 @@
 }
 
 /**
- * Determines the cost of coercing the arguments of a function to the required types. Returns true
- * if the cost could be computed, false if the call is not valid. Cost has no particular meaning
- * other than "lower costs are preferred".
+ * Determines the cost of coercing the arguments of a function to the required types. Cost has no
+ * particular meaning other than "lower costs are preferred". Returns INT_MAX if the call is not
+ * valid.
  */
-bool IRGenerator::determineCallCost(const FunctionDeclaration& function,
-                                    const std::vector<std::unique_ptr<Expression>>& arguments,
-                                    int* outCost) {
+int IRGenerator::callCost(const FunctionDeclaration& function,
+             const std::vector<std::unique_ptr<Expression>>& arguments) {
     if (function.fParameters.size() != arguments.size()) {
-        return false;
+        return INT_MAX;
     }
     int total = 0;
     std::vector<const Type*> types;
     const Type* ignored;
     if (!function.determineFinalTypes(arguments, &types, &ignored)) {
-        return false;
+        return INT_MAX;
     }
     for (size_t i = 0; i < arguments.size(); i++) {
-        int cost;
-        if (arguments[i]->fType.determineCoercionCost(*types[i], &cost)) {
+        int cost = arguments[i]->coercionCost(*types[i]);
+        if (cost != INT_MAX) {
             total += cost;
         } else {
-            return false;
+            return INT_MAX;
         }
     }
-    *outCost = total;
-    return true;
+    return total;
 }
 
 std::unique_ptr<Expression> IRGenerator::applyColorSpace(std::unique_ptr<Expression> texture,
@@ -1436,8 +1446,8 @@
     const FunctionDeclaration* best = nullptr;
     if (ref->fFunctions.size() > 1) {
         for (const auto& f : ref->fFunctions) {
-            int cost;
-            if (this->determineCallCost(*f, arguments, &cost) && cost < bestCost) {
+            int cost = this->callCost(*f, arguments);
+            if (cost < bestCost) {
                 bestCost = cost;
                 best = f;
             }
@@ -1470,8 +1480,16 @@
                                 to_string((uint64_t) args.size()) + ")");
         return nullptr;
     }
-    if (type == *fContext.fFloat_Type && args.size() == 1 &&
-        args[0]->fKind == Expression::kIntLiteral_Kind) {
+    if (type.isFloat() && args[0]->fType.isFloat()) {
+        return std::move(args[0]);
+    }
+    if (type.isSigned() && args[0]->fType.isSigned()) {
+        return std::move(args[0]);
+    }
+    if (type.isUnsigned() && args[0]->fType.isUnsigned()) {
+        return std::move(args[0]);
+    }
+    if (type.isFloat() && args.size() == 1 && args[0]->fKind == Expression::kIntLiteral_Kind) {
         int64_t value = ((IntLiteral&) *args[0]).fValue;
         return std::unique_ptr<Expression>(new FloatLiteral(fContext, position, (double) value));
     }
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 70416c5..0a1bae4 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -106,11 +106,11 @@
     std::unique_ptr<Expression> call(Position position,
                                      const FunctionDeclaration& function,
                                      std::vector<std::unique_ptr<Expression>> arguments);
-    bool determineCallCost(const FunctionDeclaration& function,
-                           const std::vector<std::unique_ptr<Expression>>& arguments,
-                           int* outCost);
+    int callCost(const FunctionDeclaration& function,
+                 const std::vector<std::unique_ptr<Expression>>& arguments);
     std::unique_ptr<Expression> call(Position position, std::unique_ptr<Expression> function,
                                      std::vector<std::unique_ptr<Expression>> arguments);
+    int coercionCost(const Expression& expr, const Type& type);
     std::unique_ptr<Expression> coerce(std::unique_ptr<Expression> expr, const Type& type);
     std::unique_ptr<Block> convertBlock(const ASTBlock& block);
     std::unique_ptr<Statement> convertBreak(const ASTBreakStatement& b);
diff --git a/src/sksl/ir/SkSLExpression.h b/src/sksl/ir/SkSLExpression.h
index 89a1a1e..286610f 100644
--- a/src/sksl/ir/SkSLExpression.h
+++ b/src/sksl/ir/SkSLExpression.h
@@ -85,6 +85,10 @@
         return nullptr;
     }
 
+    virtual int coercionCost(const Type& target) const {
+        return fType.coercionCost(target);
+    }
+
     const Kind fKind;
     const Type& fType;
 
diff --git a/src/sksl/ir/SkSLIntLiteral.h b/src/sksl/ir/SkSLIntLiteral.h
index d8eba55..6199f96 100644
--- a/src/sksl/ir/SkSLIntLiteral.h
+++ b/src/sksl/ir/SkSLIntLiteral.h
@@ -40,6 +40,13 @@
         return fValue == i.fValue;
     }
 
+    int coercionCost(const Type& target) const override {
+        if (target.isUnsigned()) {
+            return 0;
+        }
+        return INHERITED::coercionCost(target);
+    }
+
     const int64_t fValue;
 
     typedef Expression INHERITED;
diff --git a/src/sksl/ir/SkSLType.cpp b/src/sksl/ir/SkSLType.cpp
index 60d40cd..1fdc9bb 100644
--- a/src/sksl/ir/SkSLType.cpp
+++ b/src/sksl/ir/SkSLType.cpp
@@ -10,31 +10,37 @@
 
 namespace SkSL {
 
-bool Type::determineCoercionCost(const Type& other, int* outCost) const {
+int Type::coercionCost(const Type& other) const {
     if (*this == other) {
-        *outCost = 0;
-        return true;
+        return 0;
     }
     if (this->kind() == kVector_Kind && other.kind() == kVector_Kind) {
         if (this->columns() == other.columns()) {
-            return this->componentType().determineCoercionCost(other.componentType(), outCost);
+            return this->componentType().coercionCost(other.componentType());
         }
-        return false;
+        return INT_MAX;
     }
     if (this->kind() == kMatrix_Kind) {
-        if (this->columns() == other.columns() &&
-            this->rows() == other.rows()) {
-            return this->componentType().determineCoercionCost(other.componentType(), outCost);
+        if (this->columns() == other.columns() && this->rows() == other.rows()) {
+            return this->componentType().coercionCost(other.componentType());
         }
-        return false;
+        return INT_MAX;
+    }
+    if (this->isNumber() && other.isFloat()) {
+        return 1;
+    }
+    if (this->isSigned() && other.isSigned()) {
+        return 1;
+    }
+    if (this->isUnsigned() && other.isUnsigned()) {
+        return 1;
     }
     for (size_t i = 0; i < fCoercibleTypes.size(); i++) {
         if (*fCoercibleTypes[i] == other) {
-            *outCost = (int) i + 1;
-            return true;
+            return (int) i + 1;
         }
     }
-    return false;
+    return INT_MAX;
 }
 
 const Type& Type::toCompound(const Context& context, int columns, int rows) const {
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index ec91a1c..6ea4c56 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -52,37 +52,47 @@
         kOther_Kind
     };
 
+    enum NumberKind {
+        kFloat_NumberKind,
+        kSigned_NumberKind,
+        kUnsigned_NumberKind,
+        kNonnumeric_NumberKind
+    };
+
     // Create an "other" (special) type with the given name. These types cannot be directly
     // referenced from user code.
     Type(String name)
     : INHERITED(Position(), kType_Kind, std::move(name))
-    , fTypeKind(kOther_Kind) {}
+    , fTypeKind(kOther_Kind)
+    , fNumberKind(kNonnumeric_NumberKind) {}
 
     // Create a generic type which maps to the listed types.
     Type(String name, std::vector<const Type*> types)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kGeneric_Kind)
+    , fNumberKind(kNonnumeric_NumberKind)
     , fCoercibleTypes(std::move(types)) {}
 
     // Create a struct type with the given fields.
     Type(Position position, String name, std::vector<Field> fields)
     : INHERITED(position, kType_Kind, std::move(name))
     , fTypeKind(kStruct_Kind)
+    , fNumberKind(kNonnumeric_NumberKind)
     , fFields(std::move(fields)) {}
 
     // Create a scalar type.
-    Type(String name, bool isNumber)
+    Type(String name, NumberKind numberKind)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kScalar_Kind)
-    , fIsNumber(isNumber)
+    , fNumberKind(numberKind)
     , fColumns(1)
     , fRows(1) {}
 
     // Create a scalar type which can be coerced to the listed types.
-    Type(String name, bool isNumber, std::vector<const Type*> coercibleTypes)
+    Type(String name, NumberKind numberKind, std::vector<const Type*> coercibleTypes)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kScalar_Kind)
-    , fIsNumber(isNumber)
+    , fNumberKind(numberKind)
     , fCoercibleTypes(std::move(coercibleTypes))
     , fColumns(1)
     , fRows(1) {}
@@ -95,6 +105,7 @@
     Type(String name, Kind kind, const Type& componentType, int columns)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kind)
+    , fNumberKind(kNonnumeric_NumberKind)
     , fComponentType(&componentType)
     , fColumns(columns)
     , fRows(1)
@@ -104,6 +115,7 @@
     Type(String name, const Type& componentType, int columns, int rows)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kMatrix_Kind)
+    , fNumberKind(kNonnumeric_NumberKind)
     , fComponentType(&componentType)
     , fColumns(columns)
     , fRows(rows)
@@ -114,13 +126,14 @@
          bool isSampled)
     : INHERITED(Position(), kType_Kind, std::move(name))
     , fTypeKind(kSampler_Kind)
+    , fNumberKind(kNonnumeric_NumberKind)
     , fDimensions(dimensions)
     , fIsDepth(isDepth)
     , fIsArrayed(isArrayed)
     , fIsMultisampled(isMultisampled)
     , fIsSampled(isSampled) {}
 
-    String name() const {
+    const String& name() const {
         return fName;
     }
 
@@ -147,7 +160,35 @@
      * Returns true if this is a numeric scalar type.
      */
     bool isNumber() const {
-        return fIsNumber;
+        return fNumberKind != kNonnumeric_NumberKind;
+    }
+
+    /**
+     * Returns true if this is a floating-point scalar type (float, half, or double).
+     */
+    bool isFloat() const {
+        return fNumberKind == kFloat_NumberKind;
+    }
+
+    /**
+     * Returns true if this is a signed scalar type (int or short).
+     */
+    bool isSigned() const {
+        return fNumberKind == kSigned_NumberKind;
+    }
+
+    /**
+     * Returns true if this is an unsigned scalar type (uint or ushort).
+     */
+    bool isUnsigned() const {
+        return fNumberKind == kUnsigned_NumberKind;
+    }
+
+    /**
+     * Returns true if this is a signed or unsigned integer.
+     */
+    bool isInteger() const {
+        return isSigned() || isUnsigned();
     }
 
     /**
@@ -155,17 +196,15 @@
      * another type.
      */
     bool canCoerceTo(const Type& other) const {
-        int cost;
-        return determineCoercionCost(other, &cost);
+        return coercionCost(other) != INT_MAX;
     }
 
     /**
      * Determines the "cost" of coercing (implicitly converting) this type to another type. The cost
      * is a number with no particular meaning other than that lower costs are preferable to higher
-     * costs. Returns true if a conversion is possible, false otherwise. The value of the out
-     * parameter is undefined if false is returned.
+     * costs. Returns INT_MAX if the coercion is not possible.
      */
-    bool determineCoercionCost(const Type& other, int* outCost) const;
+    int coercionCost(const Type& other) const;
 
     /**
      * For matrices and vectors, returns the type of individual cells (e.g. mat2 has a component
@@ -245,7 +284,8 @@
     typedef Symbol INHERITED;
 
     const Kind fTypeKind;
-    const bool fIsNumber = false;
+    // always kNonnumeric_NumberKind for non-scalar values
+    const NumberKind fNumberKind;
     const Type* fComponentType = nullptr;
     const std::vector<const Type*> fCoercibleTypes;
     const int fColumns = -1;
diff --git a/src/sksl/sksl.include b/src/sksl/sksl.include
index 5d905e3..7b738d5 100644
--- a/src/sksl/sksl.include
+++ b/src/sksl/sksl.include
@@ -99,6 +99,8 @@
 $genType intBitsToFloat($genIType value);
 $genType uintBitsToFloat($genUType value);
 $genType fma($genType a, $genType b, $genType c);
+$genHType fma($genHType a, $genHType b, $genHType c);
+$genDType fma($genDType a, $genDType b, $genDType c);
 //$genDType fma($genDType a, $genDType b, $genDType c);
 $genType frexp($genType x, out $genIType exp);
 //$genDType frexp($genDType x, out $genIType exp);
@@ -117,22 +119,30 @@
 uint packHalf2x16(float2 v);
 float2 unpackHalf2x16(uint v);
 float length($genType x);
-//double length($genDType x);
+half length($genHType x);
+double length($genDType x);
 float distance($genType p0, $genType p1);
-//double distance($genDType p0, $genDType p1);
+half distance($genHType p0, $genHType p1);
+double distance($genDType p0, $genDType p1);
 float dot($genType x, $genType y);
-//double dot($genDType x, $genDType y);
+half dot($genHType x, $genHType y);
+double dot($genDType x, $genDType y);
 float3 cross(float3 x, float3 y);
-//double3 cross(double3 x, double3 y);
+half3 cross(half3 x, half3 y);
+double3 cross(double3 x, double3 y);
 $genType normalize($genType x);
-//$genDType normalize($genDType x);
+$genHType normalize($genHType x);
+$genDType normalize($genDType x);
 float4 ftransform();
 $genType faceforward($genType N, $genType I, $genType Nref);
-//$genDType faceforward($genDType N, $genDType I, $genDType Nref);
+$genHType faceforward($genHType N, $genHType I, $genHType Nref);
+$genDType faceforward($genDType N, $genDType I, $genDType Nref);
 $genType reflect($genType I, $genType N);
-//$genDType reflect($genDType I, $genDType N);
+$genHType reflect($genHType I, $genHType N);
+$genDType reflect($genDType I, $genDType N);
 $genType refract($genType I, $genType N, float eta);
-//$genDType refract($genDType I, $genDType N, float eta);
+$genHType refract($genHType I, $genHType N, float eta);
+$genDType refract($genDType I, $genDType N, float eta);
 $mat matrixCompMult($mat x, $mat y);
 float2x2 outerProduct(float2 c, float2 r);
 float3x3 outerProduct(float3 c, float3 r);
@@ -159,24 +169,48 @@
 float3x3 inverse(float3x3 m);
 float4x4 inverse(float4x4 m);
 $bvec lessThan($vec x, $vec y);
+$bvec lessThan($hvec x, $hvec y);
+$bvec lessThan($dvec x, $dvec y);
 $bvec lessThan($ivec x, $ivec y);
+$bvec lessThan($svec x, $svec y);
+$bvec lessThan($usvec x, $usvec y);
 $bvec lessThan($uvec x, $uvec y);
 $bvec lessThanEqual($vec x, $vec y);
+$bvec lessThanEqual($hvec x, $hvec y);
+$bvec lessThanEqual($dvec x, $dvec y);
 $bvec lessThanEqual($ivec x, $ivec y);
 $bvec lessThanEqual($uvec x, $uvec y);
+$bvec lessThanEqual($svec x, $svec y);
+$bvec lessThanEqual($usvec x, $usvec y);
 $bvec greaterThan($vec x, $vec y);
+$bvec greaterThan($hvec x, $hvec y);
+$bvec greaterThan($dvec x, $dvec y);
 $bvec greaterThan($ivec x, $ivec y);
 $bvec greaterThan($uvec x, $uvec y);
+$bvec greaterThan($svec x, $svec y);
+$bvec greaterThan($usvec x, $usvec y);
 $bvec greaterThanEqual($vec x, $vec y);
+$bvec greaterThanEqual($hvec x, $hvec y);
+$bvec greaterThanEqual($dvec x, $dvec y);
 $bvec greaterThanEqual($ivec x, $ivec y);
 $bvec greaterThanEqual($uvec x, $uvec y);
+$bvec greaterThanEqual($svec x, $svec y);
+$bvec greaterThanEqual($usvec x, $usvec y);
 $bvec equal($vec x, $vec y);
+$bvec equal($hvec x, $hvec y);
+$bvec equal($dvec x, $dvec y);
 $bvec equal($ivec x, $ivec y);
 $bvec equal($uvec x, $uvec y);
+$bvec equal($svec x, $svec y);
+$bvec equal($usvec x, $usvec y);
 $bvec equal($bvec x, $bvec y);
 $bvec notEqual($vec x, $vec y);
+$bvec notEqual($hvec x, $hvec y);
+$bvec notEqual($dvec x, $dvec y);
 $bvec notEqual($ivec x, $ivec y);
 $bvec notEqual($uvec x, $uvec y);
+$bvec notEqual($svec x, $svec y);
+$bvec notEqual($usvec x, $usvec y);
 $bvec notEqual($bvec x, $bvec y);
 bool any($bvec x);
 bool all($bvec x);