re-land of new SkSL precisions

Bug: skia:
Change-Id: Ic1deb3db2cbda6ca45f93dee99832971a36a2119
Reviewed-on: https://skia-review.googlesource.com/47841
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
diff --git a/src/sksl/SkSLCPP.h b/src/sksl/SkSLCPP.h
index 642f7c6..808e832 100644
--- a/src/sksl/SkSLCPP.h
+++ b/src/sksl/SkSLCPP.h
@@ -22,4 +22,6 @@
 
 inline SkPoint float2(float x, float y) { return SkPoint::Make(x, y); }
 
+#define half2 float2
+
 #endif
diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp
index e84954e..9d09a87 100644
--- a/src/sksl/SkSLCPPCodeGenerator.cpp
+++ b/src/sksl/SkSLCPPCodeGenerator.cpp
@@ -51,16 +51,14 @@
 void CPPCodeGenerator::writeHeader() {
 }
 
-void CPPCodeGenerator::writePrecisionModifier() {
+bool CPPCodeGenerator::usesPrecisionModifiers() const {
+    return false;
 }
 
-void CPPCodeGenerator::writeType(const Type& type) {
-    if (type.kind() == Type::kStruct_Kind) {
-        INHERITED::writeType(type);
-    } else {
-        this->write(type.fName);
-    }
+String CPPCodeGenerator::getTypeName(const Type& type) {
+    return type.name();
 }
+
 void CPPCodeGenerator::writeBinaryExpression(const BinaryExpression& b,
                                              Precedence parentPrecedence) {
     if (b.fOperator == Token::PERCENT) {
@@ -117,19 +115,16 @@
     INHERITED::writeIndexExpression(i);
 }
 
-static const char* default_value(const Type& type) {
-    if (type.fName == "float") {
-        return "0.0";
-    } else if (type.fName == "float2") {
-        return "float2(0.0)";
-    } else if (type.fName == "float3") {
-        return "float30.0)";
-    } else if (type.fName == "float4") {
-        return "float4(0.0)";
-    } else if (type.fName == "floatt4x4" || type.fName == "colorSpaceXform") {
+static String default_value(const Type& type) {
+    if (type.fName == "colorSpaceXform") {
         return "float4x4(1.0)";
     }
-    ABORT("unsupported default_value type\n");
+    switch (type.kind()) {
+        case Type::kScalar_Kind: return "0";
+        case Type::kVector_Kind: return type.name() + "(0)";
+        case Type::kMatrix_Kind: return type.name() + "(1)";
+        default: ABORT("unsupported default_value type\n");
+    }
 }
 
 static bool is_private(const Variable& var) {
@@ -140,7 +135,7 @@
 }
 
 void CPPCodeGenerator::writeRuntimeValue(const Type& type, const String& cppCode) {
-    if (type == *fContext.fFloat_Type) {
+    if (type.isFloat()) {
         this->write("%f");
         fFormatArgs.push_back(cppCode);
     } else if (type == *fContext.fInt_Type) {
@@ -149,12 +144,12 @@
     } else if (type == *fContext.fBool_Type) {
         this->write("%s");
         fFormatArgs.push_back("(" + cppCode + " ? \"true\" : \"false\")");
-    } else if (type == *fContext.fFloat2_Type) {
-        this->write("float2(%f, %f)");
+    } else if (type == *fContext.fFloat2_Type || type == *fContext.fHalf2_Type) {
+        this->write(type.name() + "(%f, %f)");
         fFormatArgs.push_back(cppCode + ".fX");
         fFormatArgs.push_back(cppCode + ".fY");
     } else {
-        this->write(type.fName);
+        this->write(type.name());
         this->write("\n");
         ABORT("unsupported runtime value type\n");
     }
@@ -189,7 +184,7 @@
     switch (ref.fVariable.fModifiers.fLayout.fBuiltin) {
         case SK_INCOLOR_BUILTIN:
             this->write("%s");
-            fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"float4(1)\""));
+            fFormatArgs.push_back(String("args.fInputColor ? args.fInputColor : \"half4(1)\""));
             break;
         case SK_OUTCOLOR_BUILTIN:
             this->write("%s");
@@ -211,7 +206,7 @@
                     var = String::printf("fColorSpaceHelper.isValid() ? "
                                          "args.fUniformHandler->getUniformCStr("
                                                   "fColorSpaceHelper.gamutXformUniform()) : \"%s\"",
-                           default_value(ref.fVariable.fType));
+                           default_value(ref.fVariable.fType).c_str());
                 } else {
                     var = String::printf("args.fUniformHandler->getUniformCStr(%sVar)",
                                          HCodeGenerator::FieldName(name.c_str()).c_str());
@@ -221,7 +216,7 @@
                     code = String::printf("%sVar.isValid() ? %s : \"%s\"",
                                           HCodeGenerator::FieldName(name.c_str()).c_str(),
                                           var.c_str(),
-                                          default_value(ref.fVariable.fType));
+                                          default_value(ref.fVariable.fType).c_str());
                 } else {
                     code = var;
                 }
@@ -253,7 +248,7 @@
 void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) {
     if (c.fFunction.fBuiltin && c.fFunction.fName == "COLORSPACE") {
         String tmpVar = "_tmpVar" + to_string(++fVarCount);
-        fFunctionHeader += "float4 " + tmpVar + ";";
+        fFunctionHeader += "half4 " + tmpVar + ";";
         ASSERT(c.fArguments.size() == 2);
         this->write("%s");
         fFormatArgs.push_back("fColorSpaceHelper.isValid() ? \"(" + tmpVar + " = \" : \"\"");
@@ -262,7 +257,7 @@
         String xform("args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform())");
         this->write("%s");
         fFormatArgs.push_back("fColorSpaceHelper.isValid() ? SkStringPrintf(\", "
-                              "float4(clamp((%s * float4(" + tmpVar + ".rgb, 1.0)).rgb, 0.0, " +
+                              "half4(clamp((%s * half4(" + tmpVar + ".rgb, 1.0)).rgb, 0.0, " +
                               tmpVar + ".a), " + tmpVar + ".a))\", " + xform + ").c_str() : \"\"");
         return;
     }
@@ -349,14 +344,22 @@
     }
     const char* type;
     if (var.fType == *fContext.fFloat_Type) {
-        type = "kFloat_GrSLType";
+        type = "kHighFloat_GrSLType";
+    } else if (var.fType == *fContext.fHalf_Type) {
+        type = "kHalf_GrSLType";
     } else if (var.fType == *fContext.fFloat2_Type) {
-        type = "kVec2f_GrSLType";
+        type = "kHighFloat2_GrSLType";
+    } else if (var.fType == *fContext.fHalf2_Type) {
+        type = "kHalf2_GrSLType";
     } else if (var.fType == *fContext.fFloat4_Type) {
-        type = "kVec4f_GrSLType";
+        type = "kHighFloat4_GrSLType";
+    } else if (var.fType == *fContext.fHalf4_Type) {
+        type = "kHalf4_GrSLType";
     } else if (var.fType == *fContext.fFloat4x4_Type ||
                var.fType == *fContext.fColorSpaceXform_Type) {
-        type = "kMat44f_GrSLType";
+        type = "kHighFloat4x4_GrSLType";
+    } else if (var.fType == *fContext.fHalf4x4_Type) {
+        type = "kHalf4x4_GrSLType";
     } else {
         ABORT("unsupported uniform type: %s %s;\n", String(var.fType.fName).c_str(),
               String(var.fName).c_str());
@@ -457,11 +460,12 @@
             }
             String nameString(u->fName);
             const char* name = nameString.c_str();
-            if (u->fType == *fContext.fFloat4_Type) {
+            if (u->fType == *fContext.fFloat4_Type || u->fType == *fContext.fHalf4_Type) {
                 this->writef("        const SkRect %sValue = _outer.%s();\n"
                              "        %s.set4fv(%sVar, 1, (float*) &%sValue);\n",
                              name, name, pdman, HCodeGenerator::FieldName(name).c_str(), name);
-            } else if (u->fType == *fContext.fFloat4x4_Type) {
+            } else if (u->fType == *fContext.fFloat4x4_Type ||
+                       u->fType == *fContext.fHalf4x4_Type) {
                 this->writef("        float %sValue[16];\n"
                              "        _outer.%s().asColMajorf(%sValue);\n"
                              "        %s.setMatrix4f(%sVar, %sValue);\n",
diff --git a/src/sksl/SkSLCPPCodeGenerator.h b/src/sksl/SkSLCPPCodeGenerator.h
index 27b434a..6727b9c 100644
--- a/src/sksl/SkSLCPPCodeGenerator.h
+++ b/src/sksl/SkSLCPPCodeGenerator.h
@@ -31,9 +31,9 @@
 
     void writeHeader() override;
 
-    void writePrecisionModifier() override;
+    bool usesPrecisionModifiers() const override;
 
-    void writeType(const Type& type) override;
+    String getTypeName(const Type& type) override;
 
     void writeBinaryExpression(const BinaryExpression& b, Precedence parentPrecedence) override;
 
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index 638e4d6..5373f9d 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -196,9 +196,8 @@
                                     *fContext.fSkArgs_Type, Variable::kGlobal_Storage);
     fIRGenerator->fSymbolTable->add(skArgsName, std::unique_ptr<Symbol>(skArgs));
 
-    Modifiers::Flag ignored1;
-    std::vector<std::unique_ptr<ProgramElement>> ignored2;
-    fIRGenerator->convertProgram(SKSL_INCLUDE, strlen(SKSL_INCLUDE), *fTypes, &ignored1, &ignored2);
+    std::vector<std::unique_ptr<ProgramElement>> ignored;
+    fIRGenerator->convertProgram(SKSL_INCLUDE, strlen(SKSL_INCLUDE), *fTypes, &ignored);
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
     if (fErrorCount) {
         printf("Unexpected errors: %s\n", fErrorText.c_str());
@@ -1134,31 +1133,28 @@
     fErrorCount = 0;
     fIRGenerator->start(&settings);
     std::vector<std::unique_ptr<ProgramElement>> elements;
-    Modifiers::Flag ignored;
     switch (kind) {
         case Program::kVertex_Kind:
             fIRGenerator->convertProgram(SKSL_VERT_INCLUDE, strlen(SKSL_VERT_INCLUDE), *fTypes,
-                                         &ignored, &elements);
+                                         &elements);
             break;
         case Program::kFragment_Kind:
             fIRGenerator->convertProgram(SKSL_FRAG_INCLUDE, strlen(SKSL_FRAG_INCLUDE), *fTypes,
-                                         &ignored, &elements);
+                                         &elements);
             break;
         case Program::kGeometry_Kind:
             fIRGenerator->convertProgram(SKSL_GEOM_INCLUDE, strlen(SKSL_GEOM_INCLUDE), *fTypes,
-                                         &ignored, &elements);
+                                         &elements);
             break;
         case Program::kFragmentProcessor_Kind:
             fIRGenerator->convertProgram(SKSL_FP_INCLUDE, strlen(SKSL_FP_INCLUDE), *fTypes,
-                                         &ignored, &elements);
+                                         &elements);
             break;
     }
     fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
-    Modifiers::Flag defaultPrecision;
     std::unique_ptr<String> textPtr(new String(std::move(text)));
     fSource = textPtr.get();
-    fIRGenerator->convertProgram(textPtr->c_str(), textPtr->size(), *fTypes, &defaultPrecision,
-                                 &elements);
+    fIRGenerator->convertProgram(textPtr->c_str(), textPtr->size(), *fTypes, &elements);
     if (!fErrorCount) {
         for (auto& element : elements) {
             if (element->fKind == ProgramElement::kFunction_Kind) {
@@ -1166,8 +1162,10 @@
             }
         }
     }
-    auto result = std::unique_ptr<Program>(new Program(kind, std::move(textPtr), settings,
-                                                       defaultPrecision, &fContext,
+    auto result = std::unique_ptr<Program>(new Program(kind,
+                                                       std::move(textPtr),
+                                                       settings,
+                                                       &fContext,
                                                        std::move(elements),
                                                        fIRGenerator->fSymbolTable,
                                                        fIRGenerator->fInputs));
diff --git a/src/sksl/SkSLCompiler.h b/src/sksl/SkSLCompiler.h
index 894ac41..1c8ef4f 100644
--- a/src/sksl/SkSLCompiler.h
+++ b/src/sksl/SkSLCompiler.h
@@ -16,6 +16,7 @@
 #include "SkSLCFGGenerator.h"
 #include "SkSLContext.h"
 #include "SkSLErrorReporter.h"
+#include "SkSLLexer.h"
 
 #define SK_FRAGCOLOR_BUILTIN           10001
 #define SK_IN_BUILTIN                  10002
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index e421695..862a777 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -21,47 +21,47 @@
     Context()
     : fInvalid_Type(new Type("<INVALID>"))
     , fVoid_Type(new Type("void"))
-    , fDouble_Type(new Type("double", Type::kFloat_NumberKind))
+    , fDouble_Type(new Type("double", Type::kFloat_NumberKind, 4))
     , fDouble2_Type(new Type("double2", *fDouble_Type, 2))
     , fDouble3_Type(new Type("double3", *fDouble_Type, 3))
     , fDouble4_Type(new Type("double4", *fDouble_Type, 4))
-    , fFloat_Type(new Type("float", Type::kFloat_NumberKind))
-    , fFloat2_Type(new Type("float2", *fFloat_Type, 2))
-    , fFloat3_Type(new Type("float3", *fFloat_Type, 3))
-    , fFloat4_Type(new Type("float4", *fFloat_Type, 4))
-    , fHalf_Type(new Type("half", Type::kFloat_NumberKind))
+    , fFloat_Type(new Type("highfloat", Type::kFloat_NumberKind, 3))
+    , fFloat2_Type(new Type("highfloat2", *fFloat_Type, 2))
+    , fFloat3_Type(new Type("highfloat3", *fFloat_Type, 3))
+    , fFloat4_Type(new Type("highfloat4", *fFloat_Type, 4))
+    , fHalf_Type(new Type("half", Type::kFloat_NumberKind, 2))
     , fHalf2_Type(new Type("half2", *fHalf_Type, 2))
     , fHalf3_Type(new Type("half3", *fHalf_Type, 3))
     , fHalf4_Type(new Type("half4", *fHalf_Type, 4))
-    , fUInt_Type(new Type("uint", Type::kUnsigned_NumberKind))
+    , fUInt_Type(new Type("uint", Type::kUnsigned_NumberKind, 1))
     , fUInt2_Type(new Type("uint2", *fUInt_Type, 2))
     , fUInt3_Type(new Type("uint3", *fUInt_Type, 3))
     , fUInt4_Type(new Type("uint4", *fUInt_Type, 4))
-    , fInt_Type(new Type("int", Type::kSigned_NumberKind))
+    , fInt_Type(new Type("int", Type::kSigned_NumberKind, 1))
     , fInt2_Type(new Type("int2", *fInt_Type, 2))
     , fInt3_Type(new Type("int3", *fInt_Type, 3))
     , fInt4_Type(new Type("int4", *fInt_Type, 4))
-    , fUShort_Type(new Type("ushort", Type::kUnsigned_NumberKind))
+    , fUShort_Type(new Type("ushort", Type::kUnsigned_NumberKind, 0))
     , fUShort2_Type(new Type("ushort2", *fUShort_Type, 2))
     , fUShort3_Type(new Type("ushort3", *fUShort_Type, 3))
     , fUShort4_Type(new Type("ushort4", *fUShort_Type, 4))
-    , fShort_Type(new Type("short", Type::kSigned_NumberKind))
+    , fShort_Type(new Type("short", Type::kSigned_NumberKind, 0))
     , fShort2_Type(new Type("short2", *fShort_Type, 2))
     , fShort3_Type(new Type("short3", *fShort_Type, 3))
     , fShort4_Type(new Type("short4", *fShort_Type, 4))
-    , fBool_Type(new Type("bool", Type::kNonnumeric_NumberKind))
+    , fBool_Type(new Type("bool", Type::kNonnumeric_NumberKind, -1))
     , fBool2_Type(new Type("bool2", *fBool_Type, 2))
     , fBool3_Type(new Type("bool3", *fBool_Type, 3))
     , fBool4_Type(new Type("bool4", *fBool_Type, 4))
-    , fFloat2x2_Type(new Type("float2x2", *fFloat_Type, 2, 2))
-    , fFloat2x3_Type(new Type("float2x3", *fFloat_Type, 2, 3))
-    , fFloat2x4_Type(new Type("float2x4", *fFloat_Type, 2, 4))
-    , fFloat3x2_Type(new Type("float3x2", *fFloat_Type, 3, 2))
-    , fFloat3x3_Type(new Type("float3x3", *fFloat_Type, 3, 3))
-    , fFloat3x4_Type(new Type("float3x4", *fFloat_Type, 3, 4))
-    , fFloat4x2_Type(new Type("float4x2", *fFloat_Type, 4, 2))
-    , fFloat4x3_Type(new Type("float4x3", *fFloat_Type, 4, 3))
-    , fFloat4x4_Type(new Type("float4x4", *fFloat_Type, 4, 4))
+    , fFloat2x2_Type(new Type("highfloat2x2", *fFloat_Type, 2, 2))
+    , fFloat2x3_Type(new Type("highfloat2x3", *fFloat_Type, 2, 3))
+    , fFloat2x4_Type(new Type("highfloat2x4", *fFloat_Type, 2, 4))
+    , fFloat3x2_Type(new Type("highfloat3x2", *fFloat_Type, 3, 2))
+    , fFloat3x3_Type(new Type("highfloat3x3", *fFloat_Type, 3, 3))
+    , fFloat3x4_Type(new Type("highfloat3x4", *fFloat_Type, 3, 4))
+    , fFloat4x2_Type(new Type("highfloat4x2", *fFloat_Type, 4, 2))
+    , fFloat4x3_Type(new Type("highfloat4x3", *fFloat_Type, 4, 3))
+    , fFloat4x4_Type(new Type("highfloat4x4", *fFloat_Type, 4, 4))
     , fHalf2x2_Type(new Type("half2x2", *fHalf_Type, 2, 2))
     , fHalf2x3_Type(new Type("half2x3", *fHalf_Type, 2, 3))
     , fHalf2x4_Type(new Type("half2x4", *fHalf_Type, 2, 4))
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 52a40f8..c6b4806 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -69,6 +69,87 @@
     this->writeLine(" : enable");
 }
 
+bool GLSLCodeGenerator::usesPrecisionModifiers() const {
+    return fProgram.fSettings.fCaps->usesPrecisionModifiers();
+}
+
+String GLSLCodeGenerator::getTypeName(const Type& type) {
+    switch (type.kind()) {
+        case Type::kVector_Kind: {
+            Type component = type.componentType();
+            String result;
+            if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
+                result = "vec";
+            }
+            else if (component == *fContext.fDouble_Type) {
+                result = "dvec";
+            }
+            else if (component == *fContext.fInt_Type || component == *fContext.fShort_Type) {
+                result = "ivec";
+            }
+            else if (component == *fContext.fUInt_Type || component == *fContext.fUShort_Type) {
+                result = "uvec";
+            }
+            else if (component == *fContext.fBool_Type) {
+                result = "bvec";
+            }
+            else {
+                ABORT("unsupported vector type");
+            }
+            result += to_string(type.columns());
+            return result;
+        }
+        case Type::kMatrix_Kind: {
+            String result;
+            Type component = type.componentType();
+            if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) {
+                result = "mat";
+            }
+            else if (component == *fContext.fDouble_Type) {
+                result = "dmat";
+            }
+            else {
+                ABORT("unsupported matrix type");
+            }
+            result += to_string(type.columns());
+            if (type.columns() != type.rows()) {
+                result += "x";
+                result += to_string(type.rows());
+            }
+            return result;
+        }
+        case Type::kArray_Kind: {
+            String result = this->getTypeName(type.componentType()) + "[";
+            if (type.columns() != -1) {
+                result += to_string(type.columns());
+            }
+            result += "]";
+            return result;
+        }
+        case Type::kScalar_Kind: {
+            if (type == *fContext.fHalf_Type) {
+                return "float";
+            }
+            else if (type == *fContext.fShort_Type) {
+                return "int";
+            }
+            else if (type == *fContext.fUShort_Type) {
+                return "uint";
+            }
+            else if (type == *fContext.fFloat_Type) {
+                // FIXME: temporary, this goes away when highfloat is renamed back to float
+                return "float";
+            }
+            else {
+                return type.name();
+            }
+            break;
+        }
+        default:
+            return type.name();
+    }
+}
+
 void GLSLCodeGenerator::writeType(const Type& type) {
     if (type.kind() == Type::kStruct_Kind) {
         for (const Type* search : fWrittenStructs) {
@@ -95,75 +176,7 @@
         fIndentation--;
         this->write("}");
     } else {
-        switch (type.kind()) {
-            case Type::kVector_Kind: {
-                Type component = type.componentType();
-                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 || component == *fContext.fShort_Type) {
-                    this->write("ivec");
-                }
-                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 || 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");
-                    this->write(to_string(type.rows()));
-                }
-                break;
-            }
-            case Type::kArray_Kind: {
-                this->writeType(type.componentType());
-                this->write("[");
-                if (type.columns() != -1) {
-                    this->write(to_string(type.columns()));
-                }
-                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.fName);
-                }
-                break;
-            }
-            default:
-                this->write(type.fName);
-        }
+        this->write(this->getTypeName(type));
     }
 }
 
@@ -176,7 +189,7 @@
             this->writeBoolLiteral((BoolLiteral&) expr);
             break;
         case Expression::kConstructor_Kind:
-            this->writeConstructor((Constructor&) expr);
+            this->writeConstructor((Constructor&) expr, parentPrecedence);
             break;
         case Expression::kIntLiteral_Kind:
             this->writeIntLiteral((IntLiteral&) expr);
@@ -229,8 +242,10 @@
     ASSERT(!fProgram.fSettings.fCaps->canUseMinAndAbsTogether());
     String tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
     String tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
-    this->fFunctionHeader += String("    ") + absExpr.fType.fName + " " + tmpVar1 + ";\n";
-    this->fFunctionHeader += String("    ") + otherExpr.fType.fName + " " + tmpVar2 + ";\n";
+    this->fFunctionHeader += String("    ") + this->getTypePrecision(absExpr.fType) +
+                             this->getTypeName(absExpr.fType) + " " + tmpVar1 + ";\n";
+    this->fFunctionHeader += String("    ") + this->getTypePrecision(otherExpr.fType) +
+                             this->getTypeName(otherExpr.fType) + " " + tmpVar2 + ";\n";
     this->write("((" + tmpVar1 + " = ");
     this->writeExpression(absExpr, kTopLevel_Precedence);
     this->write(") < (" + tmpVar2 + " = ");
@@ -358,7 +373,15 @@
     this->write(")");
 }
 
-void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
+void GLSLCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) {
+    if (c.fArguments.size() == 1 &&
+        this->getTypeName(c.fType) == this->getTypeName(c.fArguments[0]->fType)) {
+        // in cases like half(float), they're different types as far as SkSL is concerned but the
+        // same type as far as GLSL is concerned. We avoid a redundant float(float) by just writing
+        // out the inner expression here.
+        this->writeExpression(*c.fArguments[0], parentPrecedence);
+        return;
+    }
     this->writeType(c.fType);
     this->write("(");
     const char* separator = "";
@@ -395,16 +418,14 @@
             // depending on the surrounding code, accessing .xy with a uniform involved can
             // do the same thing. Copying gl_FragCoord.xy into a temp float2beforehand
             // (and only accessing .xy) seems to "fix" things.
-            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
-                                                                                       : "";
+            const char* precision = usesPrecisionModifiers() ? "highp " : "";
             fHeader.writeText("uniform ");
             fHeader.writeText(precision);
             fHeader.writeText("float " SKSL_RTHEIGHT_NAME ";\n");
             fSetupFragPositionGlobal = true;
         }
         if (!fSetupFragPositionLocal) {
-            const char* precision = fProgram.fSettings.fCaps->usesPrecisionModifiers() ? "highp "
-                                                                                       : "";
+            const char* precision = usesPrecisionModifiers() ? "highp " : "";
             fFunctionHeader += precision;
             fFunctionHeader += "    vec2 _sktmpCoord = gl_FragCoord.xy;\n";
             fFunctionHeader += precision;
@@ -591,6 +612,7 @@
 }
 
 void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
+    this->writeTypePrecision(f.fDeclaration.fReturnType);
     this->writeType(f.fDeclaration.fReturnType);
     this->write(" " + f.fDeclaration.fName + "(");
     const char* separator = "";
@@ -604,6 +626,7 @@
             sizes.push_back(type->columns());
             type = &type->componentType();
         }
+        this->writeTypePrecision(*type);
         this->writeType(*type);
         this->write(" " + param->fName);
         for (int s : sizes) {
@@ -682,7 +705,7 @@
     if (modifiers.fFlags & Modifiers::kConst_Flag) {
         this->write("const ");
     }
-    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
+    if (usesPrecisionModifiers()) {
         if (modifiers.fFlags & Modifiers::kLowp_Flag) {
             this->write("lowp ");
         }
@@ -732,23 +755,31 @@
     this->writeExpression(value, kTopLevel_Precedence);
 }
 
-void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
-    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
+const char* GLSLCodeGenerator::getTypePrecision(const Type& type) {
+    if (usesPrecisionModifiers()) {
         switch (type.kind()) {
             case Type::kScalar_Kind:
                 if (type == *fContext.fHalf_Type || type == *fContext.fShort_Type ||
                         type == *fContext.fUShort_Type) {
-                    this->write("mediump ");
+                    return fProgram.fSettings.fForceHighPrecision ? "highp " : "mediump ";
                 }
-                break;
+                if (type == *fContext.fFloat_Type || type == *fContext.fInt_Type ||
+                        type == *fContext.fUInt_Type) {
+                    return "highp ";
+                }
+                return "";
             case Type::kVector_Kind: // fall through
             case Type::kMatrix_Kind:
-                this->writeTypePrecision(type.componentType());
-                break;
+                return this->getTypePrecision(type.componentType());
             default:
                 break;
         }
     }
+    return "";
+}
+
+void GLSLCodeGenerator::writeTypePrecision(const Type& type) {
+    this->write(this->getTypePrecision(type));
 }
 
 void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
@@ -942,27 +973,6 @@
     }
 }
 
-void GLSLCodeGenerator::writePrecisionModifier() {
-    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
-        this->write("precision ");
-        switch (fProgram.fDefaultPrecision) {
-            case Modifiers::kLowp_Flag:
-                this->write("lowp");
-                break;
-            case Modifiers::kMediump_Flag:
-                this->write("mediump");
-                break;
-            case Modifiers::kHighp_Flag:
-                this->write("highp");
-                break;
-            default:
-                ASSERT(false);
-                this->write("<error>");
-        }
-        this->writeLine(" float;");
-    }
-}
-
 void GLSLCodeGenerator::writeProgramElement(const ProgramElement& e) {
     switch (e.fKind) {
         case ProgramElement::kExtension_Kind:
@@ -978,7 +988,7 @@
                 } else if (builtin == SK_FRAGCOLOR_BUILTIN &&
                            fProgram.fSettings.fCaps->mustDeclareFragmentShaderOutput()) {
                     this->write("out ");
-                    if (fProgram.fSettings.fCaps->usesPrecisionModifiers()) {
+                    if (usesPrecisionModifiers()) {
                         this->write("mediump ");
                     }
                     this->writeLine("vec4 sk_FragColor;");
@@ -1009,13 +1019,15 @@
     this->writeHeader();
     StringStream body;
     fOut = &body;
-    this->writePrecisionModifier();
     for (const auto& e : fProgram.fElements) {
         this->writeProgramElement(*e);
     }
     fOut = rawOut;
 
     write_stringstream(fHeader, *rawOut);
+    if (this->usesPrecisionModifiers()) {
+        this->writeLine("precision mediump float;");
+    }
     write_stringstream(body, *rawOut);
     return true;
 }
diff --git a/src/sksl/SkSLGLSLCodeGenerator.h b/src/sksl/SkSLGLSLCodeGenerator.h
index 353cd66..4813d0d 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.h
+++ b/src/sksl/SkSLGLSLCodeGenerator.h
@@ -96,9 +96,11 @@
 
     virtual void writeHeader();
 
-    virtual void writePrecisionModifier();
+    virtual bool usesPrecisionModifiers() const;
 
-    virtual void writeType(const Type& type);
+    virtual String getTypeName(const Type& type);
+
+    void writeType(const Type& type);
 
     void writeExtension(const Extension& ext);
 
@@ -118,6 +120,8 @@
 
     virtual void writeVarInitializer(const Variable& var, const Expression& value);
 
+    const char* getTypePrecision(const Type& type);
+
     void writeTypePrecision(const Type& type);
 
     void writeVarDeclarations(const VarDeclarations& decl, bool global);
@@ -134,7 +138,7 @@
 
     virtual void writeFunctionCall(const FunctionCall& c);
 
-    void writeConstructor(const Constructor& c);
+    void writeConstructor(const Constructor& c, Precedence parentPrecedence);
 
     void writeFieldAccess(const FieldAccess& f);
 
diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp
index 482020a..8203990 100644
--- a/src/sksl/SkSLHCodeGenerator.cpp
+++ b/src/sksl/SkSLHCodeGenerator.cpp
@@ -23,13 +23,15 @@
 , fSectionAndParameterHelper(*program, *errors) {}
 
 String HCodeGenerator::ParameterType(const Type& type) {
-    if (type.name() == "float2") {
+    if (type.name() == "highfloat" || type.name() == "half") {
+        return "float";
+    } else if (type.name() == "highfloat2" || type.name() == "half2") {
         return "SkPoint";
-    } else if (type.name() == "int4") {
+    } else if (type.name() == "int4" || type.name() == "short4") {
         return "SkIRect";
-    } else if (type.name() == "float4") {
+    } else if (type.name() == "highfloat4" || type.name() == "half4") {
         return "SkRect";
-    } else if (type.name() == "float4x4") {
+    } else if (type.name() == "highfloat4x4" || type.name() == "half4x4") {
         return "SkMatrix44";
     } else if (type.kind() == Type::kSampler_Kind) {
         return "sk_sp<GrTextureProxy>";
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 83ab993..2c6b9e3 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -17,7 +17,6 @@
 #include "ast/SkSLASTFloatLiteral.h"
 #include "ast/SkSLASTIndexSuffix.h"
 #include "ast/SkSLASTIntLiteral.h"
-#include "ast/SkSLASTPrecision.h"
 #include "ir/SkSLBinaryExpression.h"
 #include "ir/SkSLBoolLiteral.h"
 #include "ir/SkSLBreakStatement.h"
@@ -981,8 +980,15 @@
             *outResultType = context.fBool_Type.get();
             return left.canCoerceTo(*context.fBool_Type) &&
                    right.canCoerceTo(*context.fBool_Type);
-        case Token::STAR: // fall through
         case Token::STAREQ:
+            if (left.kind() == Type::kScalar_Kind) {
+                *outLeftType = &left;
+                *outRightType = &left;
+                *outResultType = &left;
+                return right.canCoerceTo(left);
+            }
+            // fall through
+        case Token::STAR:
             if (is_matrix_multiply(left, right)) {
                 // determine final component type
                 if (determine_binary_type(context, Token::STAR, left.componentType(),
@@ -1022,12 +1028,22 @@
             isLogical = false;
             validMatrixOrVectorOp = true;
             break;
+        case Token::PLUSEQ:
+        case Token::MINUSEQ:
+        case Token::SLASHEQ:
+        case Token::PERCENTEQ:
+        case Token::SHLEQ:
+        case Token::SHREQ:
+            if (left.kind() == Type::kScalar_Kind) {
+                *outLeftType = &left;
+                *outRightType = &left;
+                *outResultType = &left;
+                return right.canCoerceTo(left);
+            }
+            // fall through
         case Token::PLUS:    // fall through
-        case Token::PLUSEQ:  // fall through
         case Token::MINUS:   // fall through
-        case Token::MINUSEQ: // fall through
         case Token::SLASH:   // fall through
-        case Token::SLASHEQ: // fall through
             isLogical = false;
             validMatrixOrVectorOp = true;
             break;
@@ -1041,9 +1057,23 @@
             validMatrixOrVectorOp = false;
     }
     bool isVectorOrMatrix = left.kind() == Type::kVector_Kind || left.kind() == Type::kMatrix_Kind;
-    // FIXME: incorrect for shift
-    if (right.canCoerceTo(left) && (left.kind() == Type::kScalar_Kind ||
-                                   (isVectorOrMatrix && validMatrixOrVectorOp))) {
+    if (left.kind() == Type::kScalar_Kind && right.kind() == Type::kScalar_Kind &&
+            right.canCoerceTo(left)) {
+        if (left.priority() > right.priority()) {
+            *outLeftType = &left;
+            *outRightType = &left;
+        } else {
+            *outLeftType = &right;
+            *outRightType = &right;
+        }
+        if (isLogical) {
+            *outResultType = context.fBool_Type.get();
+        } else {
+            *outResultType = &left;
+        }
+        return true;
+    }
+    if (right.canCoerceTo(left) && isVectorOrMatrix && validMatrixOrVectorOp) {
         *outLeftType = &left;
         *outRightType = &left;
         if (isLogical) {
@@ -1480,18 +1510,17 @@
                               to_string((uint64_t) args.size()) + ")");
         return nullptr;
     }
-    if (type.isFloat() && args[0]->fType.isFloat()) {
+    if (type == args[0]->fType) {
         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::kFloatLiteral_Kind) {
+        double value = ((FloatLiteral&) *args[0]).fValue;
+        return std::unique_ptr<Expression>(new FloatLiteral(fContext, offset, value, &type));
     }
     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, offset, (double) value));
+        return std::unique_ptr<Expression>(new FloatLiteral(fContext, offset, (double) value,
+                                                            &type));
     }
     if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type ||
         type == *fContext.fUInt_Type)) {
@@ -1949,7 +1978,6 @@
 void IRGenerator::convertProgram(const char* text,
                                  size_t length,
                                  SymbolTable& types,
-                                 Modifiers::Flag* defaultPrecision,
                                  std::vector<std::unique_ptr<ProgramElement>>* out) {
     Parser parser(text, length, types, fErrors);
     std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
@@ -1957,7 +1985,6 @@
         printf("float type has name: '%s'\n", fContext.fFloat_Type->name().c_str());
         return;
     }
-    *defaultPrecision = Modifiers::kHighp_Flag;
     for (size_t i = 0; i < parsed.size(); i++) {
         ASTDeclaration& decl = *parsed[i];
         switch (decl.fKind) {
@@ -2004,10 +2031,6 @@
                 }
                 break;
             }
-            case ASTDeclaration::kPrecision_Kind: {
-                *defaultPrecision = ((ASTPrecision&) decl).fPrecision;
-                break;
-            }
             default:
                 ABORT("unsupported declaration: %s\n", decl.description().c_str());
         }
diff --git a/src/sksl/SkSLIRGenerator.h b/src/sksl/SkSLIRGenerator.h
index 3dda028..0a2979d 100644
--- a/src/sksl/SkSLIRGenerator.h
+++ b/src/sksl/SkSLIRGenerator.h
@@ -64,7 +64,6 @@
     void convertProgram(const char* text,
                         size_t length,
                         SymbolTable& types,
-                        Modifiers::Flag* defaultPrecision,
                         std::vector<std::unique_ptr<ProgramElement>>* result);
 
     /**
diff --git a/src/sksl/SkSLParser.cpp b/src/sksl/SkSLParser.cpp
index d8ecc61..9bfa62f 100644
--- a/src/sksl/SkSLParser.cpp
+++ b/src/sksl/SkSLParser.cpp
@@ -29,7 +29,6 @@
 #include "ast/SkSLASTIntLiteral.h"
 #include "ast/SkSLASTModifiersDeclaration.h"
 #include "ast/SkSLASTParameter.h"
-#include "ast/SkSLASTPrecision.h"
 #include "ast/SkSLASTPrefixExpression.h"
 #include "ast/SkSLASTReturnStatement.h"
 #include "ast/SkSLASTSection.h"
@@ -81,20 +80,13 @@
     fLexer.start(text, length);
 }
 
-/* (precision | directive | section | declaration)* END_OF_FILE */
+/* (directive | section | declaration)* END_OF_FILE */
 std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
     std::vector<std::unique_ptr<ASTDeclaration>> result;
     for (;;) {
         switch (this->peek().fKind) {
             case Token::END_OF_FILE:
                 return result;
-            case Token::PRECISION: {
-                std::unique_ptr<ASTDeclaration> precision = this->precision();
-                if (precision) {
-                    result.push_back(std::move(precision));
-                }
-                break;
-            }
             case Token::DIRECTIVE: {
                 std::unique_ptr<ASTDeclaration> decl = this->directive();
                 if (decl) {
@@ -196,36 +188,6 @@
     return nullptr != fTypes[name];
 }
 
-/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
-std::unique_ptr<ASTDeclaration> Parser::precision() {
-    if (!this->expect(Token::PRECISION, "'precision'")) {
-        return nullptr;
-    }
-    Modifiers::Flag result;
-    Token p = this->nextToken();
-    switch (p.fKind) {
-        case Token::LOWP:
-            result = Modifiers::kLowp_Flag;
-            break;
-        case Token::MEDIUMP:
-            result = Modifiers::kMediump_Flag;
-            break;
-        case Token::HIGHP:
-            result = Modifiers::kHighp_Flag;
-            break;
-        default:
-            this->error(p, "expected 'lowp', 'mediump', or 'highp', but found '" +
-                           this->text(p) + "'");
-            return nullptr;
-    }
-    // FIXME handle the type
-    if (!this->type()) {
-        return nullptr;
-    }
-    this->expect(Token::SEMICOLON, "';'");
-    return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fOffset, result));
-}
-
 /* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
    DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
 std::unique_ptr<ASTDeclaration> Parser::directive() {
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.cpp b/src/sksl/SkSLSPIRVCodeGenerator.cpp
index 7ae3252..ba80fb6 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.cpp
+++ b/src/sksl/SkSLSPIRVCodeGenerator.cpp
@@ -156,21 +156,22 @@
     if (type.kind() == Type::kVector_Kind) {
         return is_float(context, type.componentType());
     }
-    return type == *context.fFloat_Type || type == *context.fDouble_Type;
+    return type == *context.fFloat_Type || type == *context.fHalf_Type ||
+           type == *context.fDouble_Type;
 }
 
 static bool is_signed(const Context& context, const Type& type) {
     if (type.kind() == Type::kVector_Kind) {
         return is_signed(context, type.componentType());
     }
-    return type == *context.fInt_Type;
+    return type == *context.fInt_Type || type == *context.fShort_Type;
 }
 
 static bool is_unsigned(const Context& context, const Type& type) {
     if (type.kind() == Type::kVector_Kind) {
         return is_unsigned(context, type.componentType());
     }
-    return type == *context.fUInt_Type;
+    return type == *context.fUInt_Type || type == *context.fUShort_Type;
 }
 
 static bool is_bool(const Context& context, const Type& type) {
@@ -1036,11 +1037,36 @@
     }
 }
 
+Type SPIRVCodeGenerator::getActualType(const Type& type) {
+    if (type == *fContext.fHalf_Type) {
+        return *fContext.fFloat_Type;
+    }
+    if (type == *fContext.fShort_Type) {
+        return *fContext.fInt_Type;
+    }
+    if (type == *fContext.fUShort_Type) {
+        return *fContext.fUInt_Type;
+    }
+    if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
+        if (type.componentType() == *fContext.fHalf_Type) {
+            return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
+        }
+        if (type.componentType() == *fContext.fShort_Type) {
+            return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
+        }
+        if (type.componentType() == *fContext.fUShort_Type) {
+            return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
+        }
+    }
+    return type;
+}
+
 SpvId SPIRVCodeGenerator::getType(const Type& type) {
     return this->getType(type, fDefaultLayout);
 }
 
-SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
+SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
+    Type type = this->getActualType(rawType);
     String key = type.name() + to_string((int) layout.fStd);
     auto entry = fTypeMap.find(key);
     if (entry == fTypeMap.end()) {
@@ -1194,8 +1220,9 @@
     return this->getPointerType(type, fDefaultLayout, storageClass);
 }
 
-SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
+SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
                                          SpvStorageClass_ storageClass) {
+    Type type = this->getActualType(rawType);
     String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
     auto entry = fTypeMap.find(key);
     if (entry == fTypeMap.end()) {
@@ -1506,55 +1533,53 @@
 }
 
 SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
-    ASSERT(c.fType == *fContext.fFloat_Type);
+    ASSERT(c.fType.isFloat());
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
     SpvId result = this->nextId();
     SpvId parameter = this->writeExpression(*c.fArguments[0], out);
-    if (c.fArguments[0]->fType == *fContext.fInt_Type) {
+    if (c.fArguments[0]->fType.isSigned()) {
         this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
+    } else {
+        ASSERT(c.fArguments[0]->fType.isUnsigned());
         this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
-        return parameter;
     }
     return result;
 }
 
 SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
-    ASSERT(c.fType == *fContext.fInt_Type);
+    ASSERT(c.fType.isSigned());
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
     SpvId result = this->nextId();
     SpvId parameter = this->writeExpression(*c.fArguments[0], out);
-    if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
+    if (c.fArguments[0]->fType.isFloat()) {
         this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
+    }
+    else {
+        ASSERT(c.fArguments[0]->fType.isUnsigned());
         this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
-        return parameter;
     }
     return result;
 }
 
 SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
-    ASSERT(c.fType == *fContext.fUInt_Type);
+    ASSERT(c.fType.isUnsigned());
     ASSERT(c.fArguments.size() == 1);
     ASSERT(c.fArguments[0]->fType.isNumber());
     SpvId result = this->nextId();
     SpvId parameter = this->writeExpression(*c.fArguments[0], out);
-    if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
+    if (c.fArguments[0]->fType.isFloat()) {
         this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
+    } else {
+        ASSERT(c.fArguments[0]->fType.isSigned());
         this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
                                out);
-    } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
-        return parameter;
     }
     return result;
 }
@@ -1789,11 +1814,15 @@
 }
 
 SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
-    if (c.fType == *fContext.fFloat_Type) {
+    if (c.fArguments.size() == 1 &&
+        this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
+        return this->writeExpression(*c.fArguments[0], out);
+    }
+    if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
         return this->writeFloatConstructor(c, out);
-    } else if (c.fType == *fContext.fInt_Type) {
+    } else if (c.fType == *fContext.fInt_Type || c.fType == *fContext.fShort_Type) {
         return this->writeIntConstructor(c, out);
-    } else if (c.fType == *fContext.fUInt_Type) {
+    } else if (c.fType == *fContext.fUInt_Type || c.fType == *fContext.fUShort_Type) {
         return this->writeUIntConstructor(c, out);
     }
     switch (c.fType.kind()) {
@@ -2258,11 +2287,12 @@
     if (b.fOperator == Token::COMMA) {
         return rhs;
     }
+    Type tmp("<invalid>");
     // component type we are operating on: float, int, uint
     const Type* operandType;
     // IR allows mismatched types in expressions (e.g. float2* float), but they need special handling
     // in SPIR-V
-    if (b.fLeft->fType != b.fRight->fType) {
+    if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
         if (b.fLeft->fType.kind() == Type::kVector_Kind &&
             b.fRight->fType.isNumber()) {
             // promote number to vector
@@ -2326,8 +2356,9 @@
             ABORT("unsupported binary expression: %s", b.description().c_str());
         }
     } else {
-        operandType = &b.fLeft->fType;
-        ASSERT(*operandType == b.fRight->fType);
+        tmp = this->getActualType(b.fLeft->fType);
+        operandType = &tmp;
+        ASSERT(*operandType == this->getActualType(b.fRight->fType));
     }
     switch (b.fOperator) {
         case Token::EQEQ: {
@@ -2706,7 +2737,7 @@
 }
 
 SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
-    if (f.fType == *fContext.fFloat_Type) {
+    if (f.fType == *fContext.fFloat_Type || f.fType == *fContext.fHalf_Type) {
         float value = (float) f.fValue;
         auto entry = fFloatConstants.find(value);
         if (entry == fFloatConstants.end()) {
diff --git a/src/sksl/SkSLSPIRVCodeGenerator.h b/src/sksl/SkSLSPIRVCodeGenerator.h
index eb6ec40..368e6fb 100644
--- a/src/sksl/SkSLSPIRVCodeGenerator.h
+++ b/src/sksl/SkSLSPIRVCodeGenerator.h
@@ -98,6 +98,8 @@
 
     SpvId nextId();
 
+    Type getActualType(const Type& type);
+
     SpvId getType(const Type& type);
 
     SpvId getType(const Type& type, const MemoryLayout& layout);
diff --git a/src/sksl/ir/SkSLConstructor.h b/src/sksl/ir/SkSLConstructor.h
index 32fc0fb..cea5265 100644
--- a/src/sksl/ir/SkSLConstructor.h
+++ b/src/sksl/ir/SkSLConstructor.h
@@ -32,13 +32,15 @@
     std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator,
                                                   const DefinitionMap& definitions) override {
         if (fArguments.size() == 1 && fArguments[0]->fKind == Expression::kIntLiteral_Kind) {
-            if (fType == *irGenerator.fContext.fFloat_Type) {
+            if (fType == *irGenerator.fContext.fFloat_Type ||
+                fType == *irGenerator.fContext.fHalf_Type) {
                 // promote float(1) to 1.0
                 int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
                 return std::unique_ptr<Expression>(new FloatLiteral(irGenerator.fContext,
                                                                     fOffset,
                                                                     intValue));
-            } else if (fType == *irGenerator.fContext.fUInt_Type) {
+            } else if (fType == *irGenerator.fContext.fUInt_Type ||
+                       fType == *irGenerator.fContext.fUShort_Type) {
                 // promote uint(1) to 1u
                 int64_t intValue = ((IntLiteral&) *fArguments[0]).fValue;
                 return std::unique_ptr<Expression>(new IntLiteral(irGenerator.fContext,
diff --git a/src/sksl/ir/SkSLIRNode.h b/src/sksl/ir/SkSLIRNode.h
index 5ada506..20b901d 100644
--- a/src/sksl/ir/SkSLIRNode.h
+++ b/src/sksl/ir/SkSLIRNode.h
@@ -26,7 +26,7 @@
 
     // character offset of this element within the program being compiled, for error reporting
     // purposes
-    const int fOffset;
+    int fOffset;
 };
 
 } // namespace
diff --git a/src/sksl/ir/SkSLIndexExpression.h b/src/sksl/ir/SkSLIndexExpression.h
index 2daf1b5..803d5ff 100644
--- a/src/sksl/ir/SkSLIndexExpression.h
+++ b/src/sksl/ir/SkSLIndexExpression.h
@@ -26,8 +26,15 @@
                 case 4: return *context.fFloat4_Type;
                 default: ASSERT(false);
             }
+        } else if (type.componentType() == *context.fHalf_Type) {
+            switch (type.rows()) {
+                case 2: return *context.fHalf2_Type;
+                case 3: return *context.fHalf3_Type;
+                case 4: return *context.fHalf4_Type;
+                default: ASSERT(false);
+            }
         } else {
-            ASSERT(type.componentType() == *context.fDouble_Type);
+           ASSERT(type.componentType() == *context.fDouble_Type);
             switch (type.rows()) {
                 case 2: return *context.fDouble2_Type;
                 case 3: return *context.fDouble3_Type;
diff --git a/src/sksl/ir/SkSLProgram.h b/src/sksl/ir/SkSLProgram.h
index 639e09b..3184547 100644
--- a/src/sksl/ir/SkSLProgram.h
+++ b/src/sksl/ir/SkSLProgram.h
@@ -74,6 +74,8 @@
         // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their
         // constant equivalents during compilation
         bool fReplaceSettings = true;
+        // if true, all halfs are forced to be floats
+        bool fForceHighPrecision = false;
         std::unordered_map<String, Value> fArgs;
     };
 
@@ -105,7 +107,6 @@
     Program(Kind kind,
             std::unique_ptr<String> source,
             Settings settings,
-            Modifiers::Flag defaultPrecision,
             Context* context,
             std::vector<std::unique_ptr<ProgramElement>> elements,
             std::shared_ptr<SymbolTable> symbols,
@@ -113,7 +114,6 @@
     : fKind(kind)
     , fSource(std::move(source))
     , fSettings(settings)
-    , fDefaultPrecision(defaultPrecision)
     , fContext(context)
     , fSymbols(symbols)
     , fElements(std::move(elements))
@@ -122,8 +122,6 @@
     Kind fKind;
     std::unique_ptr<String> fSource;
     Settings fSettings;
-    // FIXME handle different types; currently it assumes this is for floats
-    Modifiers::Flag fDefaultPrecision;
     Context* fContext;
     // it's important to keep fElements defined after (and thus destroyed before) fSymbols,
     // because destroying elements can modify reference counts in symbols
diff --git a/src/sksl/ir/SkSLSwizzle.h b/src/sksl/ir/SkSLSwizzle.h
index 3256ef2..5512c85 100644
--- a/src/sksl/ir/SkSLSwizzle.h
+++ b/src/sksl/ir/SkSLSwizzle.h
@@ -32,6 +32,12 @@
             case 3: return *context.fFloat3_Type;
             case 4: return *context.fFloat4_Type;
         }
+    } else if (base == *context.fHalf_Type) {
+        switch (count) {
+            case 2: return *context.fHalf2_Type;
+            case 3: return *context.fHalf3_Type;
+            case 4: return *context.fHalf4_Type;
+        }
     } else if (base == *context.fDouble_Type) {
         switch (count) {
             case 2: return *context.fDouble2_Type;
@@ -44,12 +50,24 @@
             case 3: return *context.fInt3_Type;
             case 4: return *context.fInt4_Type;
         }
+    } else if (base == *context.fShort_Type) {
+        switch (count) {
+            case 2: return *context.fShort2_Type;
+            case 3: return *context.fShort3_Type;
+            case 4: return *context.fShort4_Type;
+        }
     } else if (base == *context.fUInt_Type) {
         switch (count) {
             case 2: return *context.fUInt2_Type;
             case 3: return *context.fUInt3_Type;
             case 4: return *context.fUInt4_Type;
         }
+    } else if (base == *context.fUShort_Type) {
+        switch (count) {
+            case 2: return *context.fUShort2_Type;
+            case 3: return *context.fUShort3_Type;
+            case 4: return *context.fUShort4_Type;
+        }
     } else if (base == *context.fBool_Type) {
         switch (count) {
             case 2: return *context.fBool2_Type;
diff --git a/src/sksl/ir/SkSLSymbol.h b/src/sksl/ir/SkSLSymbol.h
index f4c6753..4ec8f15 100644
--- a/src/sksl/ir/SkSLSymbol.h
+++ b/src/sksl/ir/SkSLSymbol.h
@@ -29,7 +29,7 @@
     , fKind(kind)
     , fName(name) {}
 
-    const Kind fKind;
+    Kind fKind;
     StringFragment fName;
 
     typedef IRNode INHERITED;
diff --git a/src/sksl/ir/SkSLType.cpp b/src/sksl/ir/SkSLType.cpp
index 1fdc9bb..19bc58e 100644
--- a/src/sksl/ir/SkSLType.cpp
+++ b/src/sksl/ir/SkSLType.cpp
@@ -80,6 +80,38 @@
                 }
             default: ABORT("unsupported row count (%d)", rows);
         }
+    } else if (*this == *context.fHalf_Type) {
+        switch (rows) {
+            case 1:
+                switch (columns) {
+                    case 2: return *context.fHalf2_Type;
+                    case 3: return *context.fHalf3_Type;
+                    case 4: return *context.fHalf4_Type;
+                    default: ABORT("unsupported vector column count (%d)", columns);
+                }
+            case 2:
+                switch (columns) {
+                    case 2: return *context.fHalf2x2_Type;
+                    case 3: return *context.fHalf3x2_Type;
+                    case 4: return *context.fHalf4x2_Type;
+                    default: ABORT("unsupported matrix column count (%d)", columns);
+                }
+            case 3:
+                switch (columns) {
+                    case 2: return *context.fHalf2x3_Type;
+                    case 3: return *context.fHalf3x3_Type;
+                    case 4: return *context.fHalf4x3_Type;
+                    default: ABORT("unsupported matrix column count (%d)", columns);
+                }
+            case 4:
+                switch (columns) {
+                    case 2: return *context.fHalf2x4_Type;
+                    case 3: return *context.fHalf3x4_Type;
+                    case 4: return *context.fHalf4x4_Type;
+                    default: ABORT("unsupported matrix column count (%d)", columns);
+                }
+            default: ABORT("unsupported row count (%d)", rows);
+        }
     } else if (*this == *context.fDouble_Type) {
         switch (rows) {
             case 1:
@@ -123,6 +155,17 @@
                 }
             default: ABORT("unsupported row count (%d)", rows);
         }
+    } else if (*this == *context.fShort_Type) {
+        switch (rows) {
+            case 1:
+                switch (columns) {
+                    case 2: return *context.fShort2_Type;
+                    case 3: return *context.fShort3_Type;
+                    case 4: return *context.fShort4_Type;
+                    default: ABORT("unsupported vector column count (%d)", columns);
+                }
+            default: ABORT("unsupported row count (%d)", rows);
+        }
     } else if (*this == *context.fUInt_Type) {
         switch (rows) {
             case 1:
@@ -134,6 +177,17 @@
                 }
             default: ABORT("unsupported row count (%d)", rows);
         }
+    } else if (*this == *context.fUShort_Type) {
+        switch (rows) {
+            case 1:
+                switch (columns) {
+                    case 2: return *context.fUShort2_Type;
+                    case 3: return *context.fUShort3_Type;
+                    case 4: return *context.fUShort4_Type;
+                    default: ABORT("unsupported vector column count (%d)", columns);
+                }
+            default: ABORT("unsupported row count (%d)", rows);
+        }
     } else if (*this == *context.fBool_Type) {
         switch (rows) {
             case 1:
diff --git a/src/sksl/ir/SkSLType.h b/src/sksl/ir/SkSLType.h
index b047421..ed5e076 100644
--- a/src/sksl/ir/SkSLType.h
+++ b/src/sksl/ir/SkSLType.h
@@ -93,11 +93,12 @@
     }
 
     // Create a scalar type.
-    Type(String name, NumberKind numberKind)
+    Type(String name, NumberKind numberKind, int priority)
     : INHERITED(-1, kType_Kind, StringFragment())
     , fNameString(std::move(name))
     , fTypeKind(kScalar_Kind)
     , fNumberKind(numberKind)
+    , fPriority(priority)
     , fColumns(1)
     , fRows(1) {
         fName.fChars = fNameString.c_str();
@@ -105,11 +106,12 @@
     }
 
     // Create a scalar type which can be coerced to the listed types.
-    Type(String name, NumberKind numberKind, std::vector<const Type*> coercibleTypes)
+    Type(String name, NumberKind numberKind, int priority, std::vector<const Type*> coercibleTypes)
     : INHERITED(-1, kType_Kind, StringFragment())
     , fNameString(std::move(name))
     , fTypeKind(kScalar_Kind)
     , fNumberKind(numberKind)
+    , fPriority(priority)
     , fCoercibleTypes(std::move(coercibleTypes))
     , fColumns(1)
     , fRows(1) {
@@ -224,6 +226,14 @@
     }
 
     /**
+     * Returns the "priority" of a number type, in order of double > float > half > int > short.
+     * When operating on two number types, the result is the higher-priority type.
+     */
+    int priority() const {
+        return fPriority;
+    }
+
+    /**
      * Returns true if an instance of this type can be freely coerced (implicitly converted) to
      * another type.
      */
@@ -315,20 +325,21 @@
 private:
     typedef Symbol INHERITED;
 
-    const String fNameString;
-    const Kind fTypeKind;
+    String fNameString;
+    Kind fTypeKind;
     // always kNonnumeric_NumberKind for non-scalar values
-    const NumberKind fNumberKind;
+    NumberKind fNumberKind;
+    int fPriority = -1;
     const Type* fComponentType = nullptr;
-    const std::vector<const Type*> fCoercibleTypes;
-    const int fColumns = -1;
-    const int fRows = -1;
-    const std::vector<Field> fFields;
-    const SpvDim_ fDimensions = SpvDim1D;
-    const bool fIsDepth = false;
-    const bool fIsArrayed = false;
-    const bool fIsMultisampled = false;
-    const bool fIsSampled = false;
+    std::vector<const Type*> fCoercibleTypes;
+    int fColumns = -1;
+    int fRows = -1;
+    std::vector<Field> fFields;
+    SpvDim_ fDimensions = SpvDim1D;
+    bool fIsDepth = false;
+    bool fIsArrayed = false;
+    bool fIsMultisampled = false;
+    bool fIsSampled = false;
 };
 
 } // namespace
diff --git a/src/sksl/sksl.include b/src/sksl/sksl.include
index 7b738d5..aab9930 100644
--- a/src/sksl/sksl.include
+++ b/src/sksl/sksl.include
@@ -43,14 +43,14 @@
 //$genDType ceil($genDType x);
 $genType fract($genType x);
 //$genDType fract($genDType x);
-$genType mod($genType x, float y);
+$genType mod($genType x, highfloat y);
 $genType mod($genType x, $genType y);
 //$genDType mod($genDType x, double y);
 //$genDType mod($genDType x, $genDType y);
 $genType modf($genType x, out $genType i);
 //$genDType modf($genDType x, out $genDType i);
 $genType min($genType x, $genType y);
-$genType min($genType x, float y);
+$genType min($genType x, highfloat y);
 //$genDType min($genDType x, $genDType y);
 //$genDType min($genDType x, double y);
 $genIType min($genIType x, $genIType y);
@@ -58,7 +58,7 @@
 //$genUType min($genUType x, $genUType y);
 //$genUType min($genUType x, uint y);
 $genType max($genType x, $genType y);
-$genType max($genType x, float y);
+$genType max($genType x, highfloat y);
 //$genDType max($genDType x, $genDType y);
 //$genDType max($genDType x, double y);
 $genIType max($genIType x, $genIType y);
@@ -66,7 +66,7 @@
 //$genUType max($genUType x, $genUType y);
 //$genUType max($genUType x, uint y);
 $genType clamp($genType x, $genType minVal, $genType maxVal);
-$genType clamp($genType x, float minVal, float maxVal);
+$genType clamp($genType x, highfloat minVal, highfloat maxVal);
 //$genDType clamp($genDType x, $genDType minVal, $genDType maxVal);
 //$genDType clamp($genDType x, double minVal, double maxVal);
 $genIType clamp($genIType x, $genIType minVal, $genIType maxVal);
@@ -74,7 +74,7 @@
 //$genUType clamp($genUType x, $genUType minVal, $genUType maxVal);
 //$genUType clamp($genUType x, uint minVal, uint maxVal);
 $genType mix($genType x, $genType y, $genType a);
-$genType mix($genType x, $genType y, float a);
+$genType mix($genType x, $genType y, highfloat a);
 //$genDType mix($genDType x, $genDType y, $genDType a);
 //$genDType mix($genDType x, $genDType y, double a);
 $genType mix($genType x, $genType y, $genBType a);
@@ -83,21 +83,21 @@
 //$genUType mix($genUType x, $genUType y, $genBType a);
 $genBType mix($genBType x, $genBType y, $genBType a);
 $genType step($genType edge, $genType x);
-$genType step(float edge, $genType x);
+$genType step(highfloat edge, $genType x);
 //$genDType step($genDType edge, $genDType x);
 //$genDType step(double edge, $genDType x);
 $genType smoothstep($genType edge0, $genType edge1, $genType x);
-$genType smoothstep(float edge0, float edge1, $genType x);
+$genType smoothstep(highfloat edge0, highfloat edge1, $genType x);
 //$genDType smoothstep($genDType edge0, $genDType edge1, $genDType x);
 //$genDType smoothstep(double edge0, double edge1, $genDType x);
 $genBType isnan($genType x);
 $genBType isnan($genDType x);
 $genBType isinf($genType x);
 $genBType isinf($genDType x);
-$genIType floatBitsToInt($genType value);
-//$genUType floatBitsToUint($genType value);
-$genType intBitsToFloat($genIType value);
-$genType uintBitsToFloat($genUType value);
+$genIType highfloatBitsToInt($genType value);
+//$genUType highfloatBitsToUint($genType value);
+$genType intBitsTohighfloat($genIType value);
+$genType uintBitsTohighfloat($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);
@@ -106,68 +106,68 @@
 //$genDType frexp($genDType x, out $genIType exp);
 $genType ldexp($genType x, in $genIType exp);
 //$genDType ldexp($genDType x, in $genIType exp);
-uint packUnorm2x16(float2 v);
-uint packSnorm2x16(float2 v);
-uint packUnorm4x8(float4 v);
-uint packSnorm4x8(float4 v);
-float2 unpackUnorm2x16(uint p);
-float2 unpackSnorm2x16(uint p);
-float4 unpackUnorm4x8(uint p);
-float4 unpackSnorm4x8(uint p);
+uint packUnorm2x16(highfloat2 v);
+uint packSnorm2x16(highfloat2 v);
+uint packUnorm4x8(highfloat4 v);
+uint packSnorm4x8(highfloat4 v);
+highfloat2 unpackUnorm2x16(uint p);
+highfloat2 unpackSnorm2x16(uint p);
+highfloat4 unpackUnorm4x8(uint p);
+highfloat4 unpackSnorm4x8(uint p);
 //double packDouble2x32(uint2 v);
 uint2 unpackDouble2x32(double v);
-uint packHalf2x16(float2 v);
-float2 unpackHalf2x16(uint v);
-float length($genType x);
+uint packHalf2x16(highfloat2 v);
+highfloat2 unpackHalf2x16(uint v);
+highfloat length($genType x);
 half length($genHType x);
 double length($genDType x);
-float distance($genType p0, $genType p1);
+highfloat distance($genType p0, $genType p1);
 half distance($genHType p0, $genHType p1);
 double distance($genDType p0, $genDType p1);
-float dot($genType x, $genType y);
+highfloat dot($genType x, $genType y);
 half dot($genHType x, $genHType y);
 double dot($genDType x, $genDType y);
-float3 cross(float3 x, float3 y);
+highfloat3 cross(highfloat3 x, highfloat3 y);
 half3 cross(half3 x, half3 y);
 double3 cross(double3 x, double3 y);
 $genType normalize($genType x);
 $genHType normalize($genHType x);
 $genDType normalize($genDType x);
-float4 ftransform();
+highfloat4 ftransform();
 $genType faceforward($genType N, $genType I, $genType Nref);
 $genHType faceforward($genHType N, $genHType I, $genHType Nref);
 $genDType faceforward($genDType N, $genDType I, $genDType Nref);
 $genType reflect($genType I, $genType N);
 $genHType reflect($genHType I, $genHType N);
 $genDType reflect($genDType I, $genDType N);
-$genType refract($genType I, $genType N, float eta);
-$genHType refract($genHType I, $genHType N, float eta);
-$genDType refract($genDType I, $genDType N, float eta);
+$genType refract($genType I, $genType N, highfloat eta);
+$genHType refract($genHType I, $genHType N, highfloat eta);
+$genDType refract($genDType I, $genDType N, highfloat eta);
 $mat matrixCompMult($mat x, $mat y);
-float2x2 outerProduct(float2 c, float2 r);
-float3x3 outerProduct(float3 c, float3 r);
-float4x3 outerProduct(float4 c, float4 r);
-float2x3 outerProduct(float3 c, float2 r);
-float3x2 outerProduct(float2 c, float3 r);
-float2x4 outerProduct(float4 c, float2 r);
-float4x2 outerProduct(float2 c, float4 r);
-float3x4 outerProduct(float4 c, float3 r);
-float4x3 outerProduct(float3 c, float4 r);
-float2x2 transpose(float2x2 m);
-float3x3 transpose(float3x3 m);
-float4x4 transpose(float4x4 m);
-float2x3 transpose(float3x2 m);
-float3x2 transpose(float2x3 m);
-float2x4 transpose(float4x2 m);
-float4x2 transpose(float2x4 m);
-float3x4 transpose(float4x3 m);
-float4x3 transpose(float3x4 m);
-float determinant(float2x2 m);
-float determinant(float3x3 m);
-float determinant(float4x4 m);
-float2x2 inverse(float2x2 m);
-float3x3 inverse(float3x3 m);
-float4x4 inverse(float4x4 m);
+highfloat2x2 outerProduct(highfloat2 c, highfloat2 r);
+highfloat3x3 outerProduct(highfloat3 c, highfloat3 r);
+highfloat4x3 outerProduct(highfloat4 c, highfloat4 r);
+highfloat2x3 outerProduct(highfloat3 c, highfloat2 r);
+highfloat3x2 outerProduct(highfloat2 c, highfloat3 r);
+highfloat2x4 outerProduct(highfloat4 c, highfloat2 r);
+highfloat4x2 outerProduct(highfloat2 c, highfloat4 r);
+highfloat3x4 outerProduct(highfloat4 c, highfloat3 r);
+highfloat4x3 outerProduct(highfloat3 c, highfloat4 r);
+highfloat2x2 transpose(highfloat2x2 m);
+highfloat3x3 transpose(highfloat3x3 m);
+highfloat4x4 transpose(highfloat4x4 m);
+highfloat2x3 transpose(highfloat3x2 m);
+highfloat3x2 transpose(highfloat2x3 m);
+highfloat2x4 transpose(highfloat4x2 m);
+highfloat4x2 transpose(highfloat2x4 m);
+highfloat3x4 transpose(highfloat4x3 m);
+highfloat4x3 transpose(highfloat3x4 m);
+highfloat determinant(highfloat2x2 m);
+highfloat determinant(highfloat3x3 m);
+highfloat determinant(highfloat4x4 m);
+highfloat2x2 inverse(highfloat2x2 m);
+highfloat3x3 inverse(highfloat3x3 m);
+highfloat4x4 inverse(highfloat4x4 m);
 $bvec lessThan($vec x, $vec y);
 $bvec lessThan($hvec x, $hvec y);
 $bvec lessThan($dvec x, $dvec y);
@@ -254,19 +254,19 @@
 int textureSize($gsamplerBuffer sampler);
 int2 textureSize($gsampler2DMS sampler);
 int3 textureSize($gsampler2DMSArray sampler);
-float2 textureQueryLod($gsampler1D sampler, float P);
-float2 textureQueryLod($gsampler2D sampler, float2 P);
-float2 textureQueryLod($gsampler3D sampler, float3 P);
-float2 textureQueryLod($gsamplerCube sampler, float3 P);
-float2 textureQueryLod($gsampler1DArray sampler, float P);
-float2 textureQueryLod($gsampler2DArray sampler, float2 P);
-float2 textureQueryLod($gsamplerCubeArray sampler, float3 P);
-float2 textureQueryLod(sampler1DShadow sampler, float P);
-float2 textureQueryLod(sampler2DShadow sampler, float2 P);
-float2 textureQueryLod(samplerCubeShadow sampler, float3 P);
-float2 textureQueryLod(sampler1DArrayShadow sampler, float P);
-float2 textureQueryLod(sampler2DArrayShadow sampler, float2 P);
-float2 textureQueryLod(samplerCubeArrayShadow sampler, float3 P);
+highfloat2 textureQueryLod($gsampler1D sampler, highfloat P);
+highfloat2 textureQueryLod($gsampler2D sampler, highfloat2 P);
+highfloat2 textureQueryLod($gsampler3D sampler, highfloat3 P);
+highfloat2 textureQueryLod($gsamplerCube sampler, highfloat3 P);
+highfloat2 textureQueryLod($gsampler1DArray sampler, highfloat P);
+highfloat2 textureQueryLod($gsampler2DArray sampler, highfloat2 P);
+highfloat2 textureQueryLod($gsamplerCubeArray sampler, highfloat3 P);
+highfloat2 textureQueryLod(sampler1DShadow sampler, highfloat P);
+highfloat2 textureQueryLod(sampler2DShadow sampler, highfloat2 P);
+highfloat2 textureQueryLod(samplerCubeShadow sampler, highfloat3 P);
+highfloat2 textureQueryLod(sampler1DArrayShadow sampler, highfloat P);
+highfloat2 textureQueryLod(sampler2DArrayShadow sampler, highfloat2 P);
+highfloat2 textureQueryLod(samplerCubeArrayShadow sampler, highfloat3 P);
 int textureQueryLevels($gsampler1D sampler);
 int textureQueryLevels($gsampler2D sampler);
 int textureQueryLevels($gsampler3D sampler);
@@ -282,50 +282,50 @@
 int textureQueryLevels(samplerCubeArrayShadow sampler);
 */
 
-$gfloat4 texture($gsampler1D sampler, float P);
-$gfloat4 texture($gsampler1D sampler, float P, float bias);
-$gfloat4 texture($gsampler2D sampler, float2 P);
+half4 texture($gsampler1D sampler, highfloat P);
+half4 texture($gsampler1D sampler, highfloat P, highfloat bias);
+half4 texture($gsampler2D sampler, highfloat2 P);
 // The above currently only expand to handle the float/fixed case. So we also declare this integer
 // version of texture().
-int4 texture(isampler2D sampler, float2 P);
-float4 texture(samplerExternalOES sampler, float2 P, float bias);
-float4 texture(samplerExternalOES sampler, float2 P);
+int4 texture(isampler2D sampler, highfloat2 P);
+half4 texture(samplerExternalOES sampler, highfloat2 P, highfloat bias);
+half4 texture(samplerExternalOES sampler, highfloat2 P);
 
 /*
-$gfloat4 texture($gsampler2D sampler, float2 P, float bias);
-$gfloat4 texture($gsampler3D sampler, float3 P);
-$gfloat4 texture($gsampler3D sampler, float3 P, float bias);
-$gfloat4 texture($gsamplerCube sampler, float3 P);
-$gfloat4 texture($gsamplerCube sampler, float3 P, float bias);
-float texture(sampler1DShadow sampler, float3 P);
-float texture(sampler1DShadow sampler, float3 P, float bias);
-float texture(sampler2DShadow sampler, float3 P);
-float texture(sampler2DShadow sampler, float3 P, float bias);
-float texture(samplerCubeShadow sampler, float4 P);
-float texture(samplerCubeShadow sampler, float4 P, float bias);
-$gfloat4 texture($gsampler1DArray sampler, float2 P);
-$gfloat4 texture($gsampler1DArray sampler, float2 P, float bias);
-$gfloat4 texture($gsampler2DArray sampler, float3 P);
-$gfloat4 texture($gsampler2DArray sampler, float3 P, float bias);
-$gfloat4 texture($gsamplerCubeArray sampler, float4 P);
-$gfloat4 texture($gsamplerCubeArray sampler, float4 P, float bias);
-float texture(sampler1DArrayShadow sampler, float3 P);
-float texture(sampler1DArrayShadow sampler, float3 P, float bias);
-float texture(sampler2DArrayShadow sampler, float4 P);
+$gfloat4 texture($gsampler2D sampler, highfloat2 P, highfloat bias);
+$gfloat4 texture($gsampler3D sampler, highfloat3 P);
+$gfloat4 texture($gsampler3D sampler, highfloat3 P, highfloat bias);
+$gfloat4 texture($gsamplerCube sampler, highfloat3 P);
+$gfloat4 texture($gsamplerCube sampler, highfloat3 P, highfloat bias);
+highfloat texture(sampler1DShadow sampler, highfloat3 P);
+highfloat texture(sampler1DShadow sampler, highfloat3 P, highfloat bias);
+highfloat texture(sampler2DShadow sampler, highfloat3 P);
+highfloat texture(sampler2DShadow sampler, highfloat3 P, highfloat bias);
+highfloat texture(samplerCubeShadow sampler, highfloat4 P);
+highfloat texture(samplerCubeShadow sampler, highfloat4 P, highfloat bias);
+$gfloat4 texture($gsampler1DArray sampler, highfloat2 P);
+$gfloat4 texture($gsampler1DArray sampler, highfloat2 P, highfloat bias);
+$gfloat4 texture($gsampler2DArray sampler, highfloat3 P);
+$gfloat4 texture($gsampler2DArray sampler, highfloat3 P, highfloat bias);
+$gfloat4 texture($gsamplerCubeArray sampler, highfloat4 P);
+$gfloat4 texture($gsamplerCubeArray sampler, highfloat4 P, highfloat bias);
+highfloat texture(sampler1DArrayShadow sampler, highfloat3 P);
+highfloat texture(sampler1DArrayShadow sampler, highfloat3 P, highfloat bias);
+highfloat texture(sampler2DArrayShadow sampler, highfloat4 P);
 */
 
-$gfloat4 texture($gsampler2DRect sampler, float2 P);
-$gfloat4 texture($gsampler2DRect sampler, float3 P);
+half4 texture($gsampler2DRect sampler, highfloat2 P);
+half4 texture($gsampler2DRect sampler, highfloat3 P);
 
 /*
-float texture(sampler2DRectShadow sampler, float3 P);
-float texture($gsamplerCubeArrayShadow sampler, float4 P, float compare);
+highfloat texture(sampler2DRectShadow sampler, highfloat3 P);
+highfloat texture($gsamplerCubeArrayShadow sampler, highfloat4 P, highfloat compare);
 */
 
 // Currently we do not support the generic types of loading subpassInput so we have some explicit
 // versions that we currently use
-float4 subpassLoad(subpassInput subpass);
-float4 subpassLoad(subpassInputMS subpass, int sample);
+highfloat4 subpassLoad(subpassInput subpass);
+highfloat4 subpassLoad(subpassInputMS subpass, int sample);
 /*
 $gfloat4subpassLoad(gsubpassInput subpass);
 $gfloat4subpassLoad(gsubpassInputMS subpass, int sample);
@@ -336,50 +336,50 @@
 
 STRINGIFY(
 
-$gfloat4 texture($gsampler1D sampler, float2 P);
-$gfloat4 texture($gsampler1D sampler, float2 P, float bias);
-$gfloat4 texture($gsampler2D sampler, float3 P);
-$gfloat4 texture($gsampler2D sampler, float3 P, float bias);
+half4 texture($gsampler1D sampler, highfloat2 P);
+half4 texture($gsampler1D sampler, highfloat2 P, highfloat bias);
+half4 texture($gsampler2D sampler, highfloat3 P);
+half4 texture($gsampler2D sampler, highfloat3 P, highfloat bias);
 /*
-$gfloat4 textureProj($gsampler3D sampler, float4 P);
-$gfloat4 textureProj($gsampler3D sampler, float4 P, float bias);
-float textureProj(sampler1DShadow sampler, float4 P);
-float textureProj(sampler1DShadow sampler, float4 P, float bias);
-float textureProj(sampler2DShadow sampler, float4 P);
-float textureProj(sampler2DShadow sampler, float4 P, float bias);
-$gfloat4 textureProj($gsampler2DRect sampler, float4 P);
-float textureProj(sampler2DRectShadow sampler, float4 P);
-$gfloat4 textureLod($gsampler1D sampler, float P, float lod);
-$gfloat4 textureLod($gsampler2D sampler, float2 P, float lod);
-$gfloat4 textureLod($gsampler3D sampler, float3 P, float lod);
-$gfloat4 textureLod($gsamplerCube sampler, float3 P, float lod);
-float textureLod(sampler1DShadow sampler, float3 P, float lod);
-float textureLod(sampler2DShadow sampler, float3 P, float lod);
-$gfloat4 textureLod($gsampler1DArray sampler, float2 P, float lod);
-$gfloat4 textureLod($gsampler2DArray sampler, float3 P, float lod);
-float textureLod(sampler1DArrayShadow sampler, float3 P, float lod);
-$gfloat4 textureLod($gsamplerCubeArray sampler, float4 P, float lod);
-$gfloat4 textureOffset($gsampler1D sampler, float P, int offset);
-$gfloat4 textureOffset($gsampler1D sampler, float P, int offset, float bias);
-$gfloat4 textureOffset($gsampler2D sampler, float2 P, int2 offset);
-$gfloat4 textureOffset($gsampler2D sampler, float2 P, int2 offset, float bias);
-$gfloat4 textureOffset($gsampler3D sampler, float3 P, int3 offset);
-$gfloat4 textureOffset($gsampler3D sampler, float3 P, int3 offset, float bias);
-$gfloat4 textureOffset($gsampler2DRect sampler, float2 P, int2 offset);
-float textureOffset(sampler2DRectShadow sampler, float3 P, int2 offset);
-float textureOffset(sampler1DShadow sampler, float3 P, int offset);
-float textureOffset(sampler1DShadow sampler, float3 P, int offset, float bias);
-float textureOffset(sampler2DShadow sampler, float3 P, int2 offset);
-float textureOffset(sampler2DShadow sampler, float3 P, int2 offset, float bias);
-$gfloat4 textureOffset($gsampler1DArray sampler, float2 P, int offset);
-$gfloat4 textureOffset($gsampler1DArray sampler, float2 P, int offset, float bias);
-$gfloat4 textureOffset($gsampler2DArray sampler, float3 P, int2 offset);
-$gfloat4 textureOffset($gsampler2DArray sampler, float3 P, int2 offset, float bias);
-float textureOffset(sampler1DArrayShadow sampler, float3 P, int offset);
-float textureOffset(sampler1DArrayShadow sampler, float3 P, int offset, float bias);
-float textureOffset(sampler2DArrayShadow sampler, float4 P, int2 offset);
+$gfloat4 textureProj($gsampler3D sampler, highfloat4 P);
+$gfloat4 textureProj($gsampler3D sampler, highfloat4 P, highfloat bias);
+highfloat textureProj(sampler1DShadow sampler, highfloat4 P);
+highfloat textureProj(sampler1DShadow sampler, highfloat4 P, highfloat bias);
+highfloat textureProj(sampler2DShadow sampler, highfloat4 P);
+highfloat textureProj(sampler2DShadow sampler, highfloat4 P, highfloat bias);
+$gfloat4 textureProj($gsampler2DRect sampler, highfloat4 P);
+highfloat textureProj(sampler2DRectShadow sampler, highfloat4 P);
+$gfloat4 textureLod($gsampler1D sampler, highfloat P, highfloat lod);
+$gfloat4 textureLod($gsampler2D sampler, highfloat2 P, highfloat lod);
+$gfloat4 textureLod($gsampler3D sampler, highfloat3 P, highfloat lod);
+$gfloat4 textureLod($gsamplerCube sampler, highfloat3 P, highfloat lod);
+highfloat textureLod(sampler1DShadow sampler, highfloat3 P, highfloat lod);
+highfloat textureLod(sampler2DShadow sampler, highfloat3 P, highfloat lod);
+$gfloat4 textureLod($gsampler1DArray sampler, highfloat2 P, highfloat lod);
+$gfloat4 textureLod($gsampler2DArray sampler, highfloat3 P, highfloat lod);
+highfloat textureLod(sampler1DArrayShadow sampler, highfloat3 P, highfloat lod);
+$gfloat4 textureLod($gsamplerCubeArray sampler, highfloat4 P, highfloat lod);
+$gfloat4 textureOffset($gsampler1D sampler, highfloat P, int offset);
+$gfloat4 textureOffset($gsampler1D sampler, highfloat P, int offset, highfloat bias);
+$gfloat4 textureOffset($gsampler2D sampler, highfloat2 P, int2 offset);
+$gfloat4 textureOffset($gsampler2D sampler, highfloat2 P, int2 offset, highfloat bias);
+$gfloat4 textureOffset($gsampler3D sampler, highfloat3 P, int3 offset);
+$gfloat4 textureOffset($gsampler3D sampler, highfloat3 P, int3 offset, highfloat bias);
+$gfloat4 textureOffset($gsampler2DRect sampler, highfloat2 P, int2 offset);
+highfloat textureOffset(sampler2DRectShadow sampler, highfloat3 P, int2 offset);
+highfloat textureOffset(sampler1DShadow sampler, highfloat3 P, int offset);
+highfloat textureOffset(sampler1DShadow sampler, highfloat3 P, int offset, highfloat bias);
+highfloat textureOffset(sampler2DShadow sampler, highfloat3 P, int2 offset);
+highfloat textureOffset(sampler2DShadow sampler, highfloat3 P, int2 offset, highfloat bias);
+$gfloat4 textureOffset($gsampler1DArray sampler, highfloat2 P, int offset);
+$gfloat4 textureOffset($gsampler1DArray sampler, highfloat2 P, int offset, highfloat bias);
+$gfloat4 textureOffset($gsampler2DArray sampler, highfloat3 P, int2 offset);
+$gfloat4 textureOffset($gsampler2DArray sampler, highfloat3 P, int2 offset, highfloat bias);
+highfloat textureOffset(sampler1DArrayShadow sampler, highfloat3 P, int offset);
+highfloat textureOffset(sampler1DArrayShadow sampler, highfloat3 P, int offset, highfloat bias);
+highfloat textureOffset(sampler2DArrayShadow sampler, highfloat4 P, int2 offset);
 */
-float4 texelFetch(samplerBuffer sampler, int P);
+highfloat4 texelFetch(samplerBuffer sampler, int P);
 
 $gfloat4 texelFetch($gsampler1D sampler, int P, int lod);
 $gfloat4 texelFetch($gsampler2D sampler, int2 P, int lod);
@@ -396,123 +396,123 @@
 $gfloat4 texelFetchOffset($gsampler2DRect sampler, int2 P, int2 offset);
 $gfloat4 texelFetchOffset($gsampler1DArray sampler, int2 P, int lod, int offset);
 $gfloat4 texelFetchOffset($gsampler2DArray sampler, int3 P, int lod, int2 offset);
-$gfloat4 textureProjOffset($gsampler1D sampler, float2 P, int offset);
-$gfloat4 textureProjOffset($gsampler1D sampler, float2 P, int offset, float bias);
-$gfloat4 textureProjOffset($gsampler1D sampler, float4 P, int offset);
-$gfloat4 textureProjOffset($gsampler1D sampler, float4 P, int offset, float bias);
-$gfloat4 textureProjOffset($gsampler2D sampler, float3 P, int2 offset);
-$gfloat4 textureProjOffset($gsampler2D sampler, float3 P, int2 offset, float bias);
-$gfloat4 textureProjOffset($gsampler2D sampler, float4 P, int2 offset);
-$gfloat4 textureProjOffset($gsampler2D sampler, float4 P, int2 offset, float bias);
-$gfloat4 textureProjOffset($gsampler3D sampler, float4 P, int3 offset);
-$gfloat4 textureProjOffset($gsampler3D sampler, float4 P, int3 offset, float bias);
-$gfloat4 textureProjOffset($gsampler2DRect sampler, float3 P, int2 offset);
-$gfloat4 textureProjOffset($gsampler2DRect sampler, float4 P, int2 offset);
-float textureProjOffset(sampler2DRectShadow sampler, float4 P, int2 offset);
-float textureProjOffset(sampler1DShadow sampler, float4 P, int offset);
-float textureProjOffset(sampler1DShadow sampler, float4 P, int offset, float bias);
-float textureProjOffset(sampler2DShadow sampler, float4 P, int2 offset);
-float textureProjOffset(sampler2DShadow sampler, float4 P, int2 offset, float bias);
-$gfloat4 textureLodOffset($gsampler1D sampler, float P, float lod, int offset);
-$gfloat4 textureLodOffset($gsampler2D sampler, float2 P, float lod, int2 offset);
-$gfloat4 textureLodOffset($gsampler3D sampler, float3 P, float lod, int3 offset);
-float textureLodOffset(sampler1DShadow sampler, float3 P, float lod, int offset);
-float textureLodOffset(sampler2DShadow sampler, float3 P, float lod, int2 offset);
-$gfloat4 textureLodOffset($gsampler1DArray sampler, float2 P, float lod, int offset);
-$gfloat4 textureLodOffset($gsampler2DArray sampler, float3 P, float lod, int2 offset);
-float textureLodOffset(sampler1DArrayShadow sampler, float3 P, float lod, int offset);
-$gfloat4 textureProjLod($gsampler1D sampler, float2 P, float lod);
-$gfloat4 textureProjLod($gsampler1D sampler, float4 P, float lod);
-$gfloat4 textureProjLod($gsampler2D sampler, float3 P, float lod);
-$gfloat4 textureProjLod($gsampler2D sampler, float4 P, float lod);
-$gfloat4 textureProjLod($gsampler3D sampler, float4 P, float lod);
-float textureProjLod(sampler1DShadow sampler, float4 P, float lod);
-float textureProjLod(sampler2DShadow sampler, float4 P, float lod);
-$gfloat4 textureProjLodOffset($gsampler1D sampler, float2 P, float lod, int offset);
-$gfloat4 textureProjLodOffset($gsampler1D sampler, float4 P, float lod, int offset);
-$gfloat4 textureProjLodOffset($gsampler2D sampler, float3 P, float lod, int2 offset);
-$gfloat4 textureProjLodOffset($gsampler2D sampler, float4 P, float lod, int2 offset);
-$gfloat4 textureProjLodOffset($gsampler3D sampler, float4 P, float lod, int3 offset);
-float textureProjLodOffset(sampler1DShadow sampler, float4 P, float lod, int offset);
-float textureProjLodOffset(sampler2DShadow sampler, float4 P, float lod, int2 offset);
-$gfloat4 textureGrad($gsampler1D sampler, float P, float dPdx, float dPdy);
-$gfloat4 textureGrad($gsampler2D sampler, float2 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureGrad($gsampler3D sampler, float3 P, float3 dPdx, float3 dPdy);
-$gfloat4 textureGrad($gsamplerCube sampler, float3 P, float3 dPdx, float3 dPdy);
-$gfloat4 textureGrad($gsampler2DRect sampler, float2 P, float2 dPdx, float2 dPdy);
-float textureGrad(sampler2DRectShadow sampler, float3 P, float2 dPdx, float2 dPdy);
-float textureGrad(sampler1DShadow sampler, float3 P, float dPdx, float dPdy);
-float textureGrad(sampler2DShadow sampler, float3 P, float2 dPdx, float2 dPdy);
-float textureGrad(samplerCubeShadow sampler, float4 P, float3 dPdx, float3 dPdy);
-$gfloat4 textureGrad($gsampler1DArray sampler, float2 P, float dPdx, float dPdy);
-$gfloat4 textureGrad($gsampler2DArray sampler, float3 P, float2 dPdx, float2 dPdy);
-float textureGrad(sampler1DArrayShadow sampler, float3 P, float dPdx, float dPdy);
-float textureGrad(sampler2DArrayShadow sampler, float4 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureGrad($gsamplerCubeArray sampler, float4 P, float3 dPdx, float3 dPdy);
-$gfloat4 textureGradOffset($gsampler1D sampler, float P, float dPdx, float dPdy, int offset);
-$gfloat4 textureGradOffset($gsampler2D sampler, float2 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureGradOffset($gsampler3D sampler, float3 P, float3 dPdx, float3 dPdy, int3 offset);
-$gfloat4 textureGradOffset($gsampler2DRect sampler, float2 P, float2 dPdx, float2 dPdy, int2 offset);
-float textureGradOffset(sampler2DRectShadow sampler, float3 P, float2 dPdx, float2 dPdy, int2 offset);
-float textureGradOffset(sampler1DShadow sampler, float3 P, float dPdx, float dPdy, int offset );
-float textureGradOffset(sampler2DShadow sampler, float3 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureGradOffset($gsampler1DArray sampler, float2 P, float dPdx, float dPdy, int offset);
-$gfloat4 textureGradOffset($gsampler2DArray sampler, float3 P, float2 dPdx, float2 dPdy, int2 offset);
-float textureGradOffset(sampler1DArrayShadow sampler, float3 P, float dPdx, float dPdy, int offset);
-float textureGradOffset(sampler2DArrayShadow sampler, float4 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureProjGrad($gsampler1D sampler, float2 P, float dPdx, float dPdy);
-$gfloat4 textureProjGrad($gsampler1D sampler, float4 P, float dPdx, float dPdy);
-$gfloat4 textureProjGrad($gsampler2D sampler, float3 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureProjGrad($gsampler2D sampler, float4 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureProjGrad($gsampler3D sampler, float4 P, float3 dPdx, float3 dPdy);
-$gfloat4 textureProjGrad($gsampler2DRect sampler, float3 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureProjGrad($gsampler2DRect sampler, float4 P, float2 dPdx, float2 dPdy);
-float textureProjGrad(sampler2DRectShadow sampler, float4 P, float2 dPdx, float2 dPdy);
-float textureProjGrad(sampler1DShadow sampler, float4 P, float dPdx, float dPdy);
-float textureProjGrad(sampler2DShadow sampler, float4 P, float2 dPdx, float2 dPdy);
-$gfloat4 textureProjGradOffset($gsampler1D sampler, float2 P, float dPdx, float dPdy, int offset);
-$gfloat4 textureProjGradOffset($gsampler1D sampler, float4 P, float dPdx, float dPdy, int offset);
-$gfloat4 textureProjGradOffset($gsampler2D sampler, float3 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureProjGradOffset($gsampler2D sampler, float4 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureProjGradOffset($gsampler2DRect sampler, float3 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureProjGradOffset($gsampler2DRect sampler, float4 P, float2 dPdx, float2 dPdy, int2 offset);
-float textureProjGradOffset(sampler2DRectShadow sampler, float4 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureProjGradOffset($gsampler3D sampler, float4 P, float3 dPdx, float3 dPdy, int3 offset);
-float textureProjGradOffset(sampler1DShadow sampler, float4 P, float dPdx, float dPdy, int offset);
-float textureProjGradOffset(sampler2DShadow sampler, float4 P, float2 dPdx, float2 dPdy, int2 offset);
-$gfloat4 textureGather($gsampler2D sampler, float2 P);
-$gfloat4 textureGather($gsampler2D sampler, float2 P, int comp);
-$gfloat4 textureGather($gsampler2DArray sampler, float3 P);
-$gfloat4 textureGather($gsampler2DArray sampler, float3 P, int comp);
-$gfloat4 textureGather($gsamplerCube sampler, float3 P);
-$gfloat4 textureGather($gsamplerCube sampler, float3 P, int comp);
-$gfloat4 textureGather($gsamplerCubeArray sampler, float4 P);
-$gfloat4 textureGather($gsamplerCubeArray sampler, float4 P, int comp);
-$gfloat4 textureGather($gsampler2DRect sampler, float2 P);
-$gfloat4 textureGather($gsampler2DRect sampler, float2 P, int comp);
-float4 textureGather(sampler2DShadow sampler, float2 P, float refZ);
-float4 textureGather(sampler2DArrayShadow sampler, float3 P, float refZ);
-float4 textureGather(samplerCubeShadow sampler, float3 P, float refZ);
-float4 textureGather(samplerCubeArrayShadow sampler, float4 P, float refZ);
-float4 textureGather(sampler2DRectShadow sampler, float2 P, float refZ);
-$gfloat4 textureGatherOffset($gsampler2D sampler, float2 P, int2 offset);
-$gfloat4 textureGatherOffset($gsampler2D sampler, float2 P, int2 offset, int comp);
-$gfloat4 textureGatherOffset($gsampler2DArray sampler, float3 P, int2 offset);
-$gfloat4 textureGatherOffset($gsampler2DArray sampler, float3 P, int2 offset, int comp);
-$gfloat4 textureGatherOffset($gsampler2DRect sampler, float2 P, int2 offset);
-$gfloat4 textureGatherOffset($gsampler2DRect sampler, float2 P, int2 offset, int comp);
-float4 textureGatherOffset(sampler2DShadow sampler, float2 P, float refZ, int2 offset);
-float4 textureGatherOffset(sampler2DArrayShadow sampler, float3 P, float refZ, int2 offset);
-float4 textureGatherOffset(sampler2DRectShadow sampler, float2 P, float refZ, int2 offset);
-$gfloat4 textureGatherOffsets($gsampler2D sampler, float2 P, int2 offsets[4]);
-$gfloat4 textureGatherOffsets($gsampler2D sampler, float2 P, int2 offsets[4], int comp);
-$gfloat4 textureGatherOffsets($gsampler2DArray sampler, float3 P, int2 offsets[4]);
-$gfloat4 textureGatherOffsets($gsampler2DArray sampler, float3 P, int2 offsets[4], int comp);
-$gfloat4 textureGatherOffsets($gsampler2DRect sampler, float2 P, int2 offsets[4]);
-$gfloat4 textureGatherOffsets($gsampler2DRect sampler, float2 P, int2 offsets[4], int comp);
-float4 textureGatherOffsets(sampler2DShadow sampler, float2 P, float refZ, int2 offsets[4]);
-float4 textureGatherOffsets(sampler2DArrayShadow sampler, float3 P, float refZ, int2 offsets[4]);
-float4 textureGatherOffsets(sampler2DRectShadow sampler, float2 P, float refZ, int2 offsets[4]);
+$gfloat4 textureProjOffset($gsampler1D sampler, highfloat2 P, int offset);
+$gfloat4 textureProjOffset($gsampler1D sampler, highfloat2 P, int offset, highfloat bias);
+$gfloat4 textureProjOffset($gsampler1D sampler, highfloat4 P, int offset);
+$gfloat4 textureProjOffset($gsampler1D sampler, highfloat4 P, int offset, highfloat bias);
+$gfloat4 textureProjOffset($gsampler2D sampler, highfloat3 P, int2 offset);
+$gfloat4 textureProjOffset($gsampler2D sampler, highfloat3 P, int2 offset, highfloat bias);
+$gfloat4 textureProjOffset($gsampler2D sampler, highfloat4 P, int2 offset);
+$gfloat4 textureProjOffset($gsampler2D sampler, highfloat4 P, int2 offset, highfloat bias);
+$gfloat4 textureProjOffset($gsampler3D sampler, highfloat4 P, int3 offset);
+$gfloat4 textureProjOffset($gsampler3D sampler, highfloat4 P, int3 offset, highfloat bias);
+$gfloat4 textureProjOffset($gsampler2DRect sampler, highfloat3 P, int2 offset);
+$gfloat4 textureProjOffset($gsampler2DRect sampler, highfloat4 P, int2 offset);
+highfloat textureProjOffset(sampler2DRectShadow sampler, highfloat4 P, int2 offset);
+highfloat textureProjOffset(sampler1DShadow sampler, highfloat4 P, int offset);
+highfloat textureProjOffset(sampler1DShadow sampler, highfloat4 P, int offset, highfloat bias);
+highfloat textureProjOffset(sampler2DShadow sampler, highfloat4 P, int2 offset);
+highfloat textureProjOffset(sampler2DShadow sampler, highfloat4 P, int2 offset, highfloat bias);
+$gfloat4 textureLodOffset($gsampler1D sampler, highfloat P, highfloat lod, int offset);
+$gfloat4 textureLodOffset($gsampler2D sampler, highfloat2 P, highfloat lod, int2 offset);
+$gfloat4 textureLodOffset($gsampler3D sampler, highfloat3 P, highfloat lod, int3 offset);
+highfloat textureLodOffset(sampler1DShadow sampler, highfloat3 P, highfloat lod, int offset);
+highfloat textureLodOffset(sampler2DShadow sampler, highfloat3 P, highfloat lod, int2 offset);
+$gfloat4 textureLodOffset($gsampler1DArray sampler, highfloat2 P, highfloat lod, int offset);
+$gfloat4 textureLodOffset($gsampler2DArray sampler, highfloat3 P, highfloat lod, int2 offset);
+highfloat textureLodOffset(sampler1DArrayShadow sampler, highfloat3 P, highfloat lod, int offset);
+$gfloat4 textureProjLod($gsampler1D sampler, highfloat2 P, highfloat lod);
+$gfloat4 textureProjLod($gsampler1D sampler, highfloat4 P, highfloat lod);
+$gfloat4 textureProjLod($gsampler2D sampler, highfloat3 P, highfloat lod);
+$gfloat4 textureProjLod($gsampler2D sampler, highfloat4 P, highfloat lod);
+$gfloat4 textureProjLod($gsampler3D sampler, highfloat4 P, highfloat lod);
+highfloat textureProjLod(sampler1DShadow sampler, highfloat4 P, highfloat lod);
+highfloat textureProjLod(sampler2DShadow sampler, highfloat4 P, highfloat lod);
+$gfloat4 textureProjLodOffset($gsampler1D sampler, highfloat2 P, highfloat lod, int offset);
+$gfloat4 textureProjLodOffset($gsampler1D sampler, highfloat4 P, highfloat lod, int offset);
+$gfloat4 textureProjLodOffset($gsampler2D sampler, highfloat3 P, highfloat lod, int2 offset);
+$gfloat4 textureProjLodOffset($gsampler2D sampler, highfloat4 P, highfloat lod, int2 offset);
+$gfloat4 textureProjLodOffset($gsampler3D sampler, highfloat4 P, highfloat lod, int3 offset);
+highfloat textureProjLodOffset(sampler1DShadow sampler, highfloat4 P, highfloat lod, int offset);
+highfloat textureProjLodOffset(sampler2DShadow sampler, highfloat4 P, highfloat lod, int2 offset);
+$gfloat4 textureGrad($gsampler1D sampler, highfloat P, highfloat dPdx, highfloat dPdy);
+$gfloat4 textureGrad($gsampler2D sampler, highfloat2 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureGrad($gsampler3D sampler, highfloat3 P, highfloat3 dPdx, highfloat3 dPdy);
+$gfloat4 textureGrad($gsamplerCube sampler, highfloat3 P, highfloat3 dPdx, highfloat3 dPdy);
+$gfloat4 textureGrad($gsampler2DRect sampler, highfloat2 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureGrad(sampler2DRectShadow sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureGrad(sampler1DShadow sampler, highfloat3 P, highfloat dPdx, highfloat dPdy);
+highfloat textureGrad(sampler2DShadow sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureGrad(samplerCubeShadow sampler, highfloat4 P, highfloat3 dPdx, highfloat3 dPdy);
+$gfloat4 textureGrad($gsampler1DArray sampler, highfloat2 P, highfloat dPdx, highfloat dPdy);
+$gfloat4 textureGrad($gsampler2DArray sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureGrad(sampler1DArrayShadow sampler, highfloat3 P, highfloat dPdx, highfloat dPdy);
+highfloat textureGrad(sampler2DArrayShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureGrad($gsamplerCubeArray sampler, highfloat4 P, highfloat3 dPdx, highfloat3 dPdy);
+$gfloat4 textureGradOffset($gsampler1D sampler, highfloat P, highfloat dPdx, highfloat dPdy, int offset);
+$gfloat4 textureGradOffset($gsampler2D sampler, highfloat2 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureGradOffset($gsampler3D sampler, highfloat3 P, highfloat3 dPdx, highfloat3 dPdy, int3 offset);
+$gfloat4 textureGradOffset($gsampler2DRect sampler, highfloat2 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+highfloat textureGradOffset(sampler2DRectShadow sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+highfloat textureGradOffset(sampler1DShadow sampler, highfloat3 P, highfloat dPdx, highfloat dPdy, int offset );
+highfloat textureGradOffset(sampler2DShadow sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureGradOffset($gsampler1DArray sampler, highfloat2 P, highfloat dPdx, highfloat dPdy, int offset);
+$gfloat4 textureGradOffset($gsampler2DArray sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+highfloat textureGradOffset(sampler1DArrayShadow sampler, highfloat3 P, highfloat dPdx, highfloat dPdy, int offset);
+highfloat textureGradOffset(sampler2DArrayShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureProjGrad($gsampler1D sampler, highfloat2 P, highfloat dPdx, highfloat dPdy);
+$gfloat4 textureProjGrad($gsampler1D sampler, highfloat4 P, highfloat dPdx, highfloat dPdy);
+$gfloat4 textureProjGrad($gsampler2D sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureProjGrad($gsampler2D sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureProjGrad($gsampler3D sampler, highfloat4 P, highfloat3 dPdx, highfloat3 dPdy);
+$gfloat4 textureProjGrad($gsampler2DRect sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureProjGrad($gsampler2DRect sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureProjGrad(sampler2DRectShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy);
+highfloat textureProjGrad(sampler1DShadow sampler, highfloat4 P, highfloat dPdx, highfloat dPdy);
+highfloat textureProjGrad(sampler2DShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy);
+$gfloat4 textureProjGradOffset($gsampler1D sampler, highfloat2 P, highfloat dPdx, highfloat dPdy, int offset);
+$gfloat4 textureProjGradOffset($gsampler1D sampler, highfloat4 P, highfloat dPdx, highfloat dPdy, int offset);
+$gfloat4 textureProjGradOffset($gsampler2D sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureProjGradOffset($gsampler2D sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureProjGradOffset($gsampler2DRect sampler, highfloat3 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureProjGradOffset($gsampler2DRect sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+highfloat textureProjGradOffset(sampler2DRectShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureProjGradOffset($gsampler3D sampler, highfloat4 P, highfloat3 dPdx, highfloat3 dPdy, int3 offset);
+highfloat textureProjGradOffset(sampler1DShadow sampler, highfloat4 P, highfloat dPdx, highfloat dPdy, int offset);
+highfloat textureProjGradOffset(sampler2DShadow sampler, highfloat4 P, highfloat2 dPdx, highfloat2 dPdy, int2 offset);
+$gfloat4 textureGather($gsampler2D sampler, highfloat2 P);
+$gfloat4 textureGather($gsampler2D sampler, highfloat2 P, int comp);
+$gfloat4 textureGather($gsampler2DArray sampler, highfloat3 P);
+$gfloat4 textureGather($gsampler2DArray sampler, highfloat3 P, int comp);
+$gfloat4 textureGather($gsamplerCube sampler, highfloat3 P);
+$gfloat4 textureGather($gsamplerCube sampler, highfloat3 P, int comp);
+$gfloat4 textureGather($gsamplerCubeArray sampler, highfloat4 P);
+$gfloat4 textureGather($gsamplerCubeArray sampler, highfloat4 P, int comp);
+$gfloat4 textureGather($gsampler2DRect sampler, highfloat2 P);
+$gfloat4 textureGather($gsampler2DRect sampler, highfloat2 P, int comp);
+highfloat4 textureGather(sampler2DShadow sampler, highfloat2 P, highfloat refZ);
+highfloat4 textureGather(sampler2DArrayShadow sampler, highfloat3 P, highfloat refZ);
+highfloat4 textureGather(samplerCubeShadow sampler, highfloat3 P, highfloat refZ);
+highfloat4 textureGather(samplerCubeArrayShadow sampler, highfloat4 P, highfloat refZ);
+highfloat4 textureGather(sampler2DRectShadow sampler, highfloat2 P, highfloat refZ);
+$gfloat4 textureGatherOffset($gsampler2D sampler, highfloat2 P, int2 offset);
+$gfloat4 textureGatherOffset($gsampler2D sampler, highfloat2 P, int2 offset, int comp);
+$gfloat4 textureGatherOffset($gsampler2DArray sampler, highfloat3 P, int2 offset);
+$gfloat4 textureGatherOffset($gsampler2DArray sampler, highfloat3 P, int2 offset, int comp);
+$gfloat4 textureGatherOffset($gsampler2DRect sampler, highfloat2 P, int2 offset);
+$gfloat4 textureGatherOffset($gsampler2DRect sampler, highfloat2 P, int2 offset, int comp);
+highfloat4 textureGatherOffset(sampler2DShadow sampler, highfloat2 P, highfloat refZ, int2 offset);
+highfloat4 textureGatherOffset(sampler2DArrayShadow sampler, highfloat3 P, highfloat refZ, int2 offset);
+highfloat4 textureGatherOffset(sampler2DRectShadow sampler, highfloat2 P, highfloat refZ, int2 offset);
+$gfloat4 textureGatherOffsets($gsampler2D sampler, highfloat2 P, int2 offsets[4]);
+$gfloat4 textureGatherOffsets($gsampler2D sampler, highfloat2 P, int2 offsets[4], int comp);
+$gfloat4 textureGatherOffsets($gsampler2DArray sampler, highfloat3 P, int2 offsets[4]);
+$gfloat4 textureGatherOffsets($gsampler2DArray sampler, highfloat3 P, int2 offsets[4], int comp);
+$gfloat4 textureGatherOffsets($gsampler2DRect sampler, highfloat2 P, int2 offsets[4]);
+$gfloat4 textureGatherOffsets($gsampler2DRect sampler, highfloat2 P, int2 offsets[4], int comp);
+highfloat4 textureGatherOffsets(sampler2DShadow sampler, highfloat2 P, highfloat refZ, int2 offsets[4]);
+highfloat4 textureGatherOffsets(sampler2DArrayShadow sampler, highfloat3 P, highfloat refZ, int2 offsets[4]);
+highfloat4 textureGatherOffsets(sampler2DRectShadow sampler, highfloat2 P, highfloat refZ, int2 offsets[4]);
 uint atomicCounterIncrement(atomic_uint c);
 uint atomicCounter(atomic_uint c);
 uint atomicAdd(inout uint mem, uint data);
@@ -534,18 +534,18 @@
 */
 // section 8.12 Additional Image Functions will go here if and when we add
 // support for them
-float4 imageLoad(image2D image, int2 P);
+highfloat4 imageLoad(image2D image, int2 P);
 int4 imageLoad(iimage2D image, int2 P);
 $genType dFdx($genType p);
 $genType dFdy($genType p);
-float interpolateAtSample(float interpolant, int sample);
-float2 interpolateAtSample(float2 interpolant, int sample);
-float3 interpolateAtSample(float3 interpolant, int sample);
-float4 interpolateAtSample(float4 interpolant, int sample);
-float interpolateAtOffset(float interpolant, float2 offset);
-float2 interpolateAtOffset(float2 interpolant, float2 offset);
-float3 interpolateAtOffset(float3 interpolant, float2 offset);
-float4 interpolateAtOffset(float4 interpolant, float2 offset);
+highfloat interpolateAtSample(highfloat interpolant, int sample);
+highfloat2 interpolateAtSample(highfloat2 interpolant, int sample);
+highfloat3 interpolateAtSample(highfloat3 interpolant, int sample);
+highfloat4 interpolateAtSample(highfloat4 interpolant, int sample);
+highfloat interpolateAtOffset(highfloat interpolant, highfloat2 offset);
+highfloat2 interpolateAtOffset(highfloat2 interpolant, highfloat2 offset);
+highfloat3 interpolateAtOffset(highfloat3 interpolant, highfloat2 offset);
+highfloat4 interpolateAtOffset(highfloat4 interpolant, highfloat2 offset);
 
 /*
 $genType fwidth($genType p);
diff --git a/src/sksl/sksl_fp.include b/src/sksl/sksl_fp.include
index 4d6b94d..8aed48e 100644
--- a/src/sksl/sksl_fp.include
+++ b/src/sksl/sksl_fp.include
@@ -2,24 +2,24 @@
 
 // defines built-in interfaces supported by SkiaSL fragment shaders
 
-layout(builtin=15) in float4 sk_FragCoord;
-layout(builtin=3) float sk_ClipDistance[1];
+layout(builtin=15) in highfloat4 sk_FragCoord;
+layout(builtin=3) highfloat sk_ClipDistance[1];
 
 // 9999 is a temporary value that causes us to ignore these declarations beyond
 // adding them to the symbol table. This works fine in GLSL (where they do not
 // require any further handling) but will fail in SPIR-V. We'll have a better
 // solution for this soon.
-layout(builtin=9999) float4 gl_LastFragData[1];
-layout(builtin=9999) float4 gl_LastFragColor;
-layout(builtin=9999) float4 gl_LastFragColorARM;
+layout(builtin=9999) highfloat4 gl_LastFragData[1];
+layout(builtin=9999) half4 gl_LastFragColor;
+layout(builtin=9999) half4 gl_LastFragColorARM;
 layout(builtin=9999) int gl_SampleMaskIn[1];
 layout(builtin=9999) out int gl_SampleMask[1];
-layout(builtin=9999) float4 gl_SecondaryFragColorEXT;
+layout(builtin=9999) half4 gl_SecondaryFragColorEXT;
 
-layout(builtin=10003) float4 sk_InColor;
-layout(builtin=10004) out float4 sk_OutColor;
-layout(builtin=10005) float2[] sk_TransformedCoords2D;
+layout(builtin=10003) half4 sk_InColor;
+layout(builtin=10004) out half4 sk_OutColor;
+layout(builtin=10005) highfloat2[] sk_TransformedCoords2D;
 layout(builtin=10006) sampler2D[] sk_TextureSamplers;
 
-float4 COLORSPACE(float4 color, colorSpaceXform colorSpace);
+half4 COLORSPACE(half4 color, colorSpaceXform colorSpace);
 )
diff --git a/src/sksl/sksl_frag.include b/src/sksl/sksl_frag.include
index 2cd1e52..c5f9ffe 100644
--- a/src/sksl/sksl_frag.include
+++ b/src/sksl/sksl_frag.include
@@ -2,20 +2,20 @@
 
 // defines built-in interfaces supported by SkiaSL fragment shaders
 
-layout(builtin=15) in float4 sk_FragCoord;
-layout(builtin=3) float sk_ClipDistance[1];
+layout(builtin=15) in highfloat4 sk_FragCoord;
+layout(builtin=3) highfloat sk_ClipDistance[1];
 
 // 9999 is a temporary value that causes us to ignore these declarations beyond
 // adding them to the symbol table. This works fine in GLSL (where they do not
 // require any further handling) but will fail in SPIR-V. We'll have a better
 // solution for this soon.
-layout(builtin=9999) float4 gl_LastFragData[1];
-layout(builtin=9999) float4 gl_LastFragColor;
-layout(builtin=9999) float4 gl_LastFragColorARM;
+layout(builtin=9999) highfloat4 gl_LastFragData[1];
+layout(builtin=9999) half4 gl_LastFragColor;
+layout(builtin=9999) half4 gl_LastFragColorARM;
 layout(builtin=9999) int gl_SampleMaskIn[1];
 layout(builtin=9999) out int gl_SampleMask[1];
-layout(builtin=9999) out float4 gl_SecondaryFragColorEXT;
+layout(builtin=9999) out half4 gl_SecondaryFragColorEXT;
 
-layout(location=0,index=0,builtin=10001) out float4 sk_FragColor;
+layout(location=0,index=0,builtin=10001) out half4 sk_FragColor;
 
 )
diff --git a/src/sksl/sksl_geom.include b/src/sksl/sksl_geom.include
index f1b3604..b1c05d1 100644
--- a/src/sksl/sksl_geom.include
+++ b/src/sksl/sksl_geom.include
@@ -3,15 +3,15 @@
 // defines built-in interfaces supported by SkiaSL geometry shaders
 
 layout(builtin=10002) in sk_PerVertex {
-  layout(builtin=0) float4 gl_Position;
-  layout(builtin=1) float gl_PointSize;
-  layout(builtin=3) float sk_ClipDistance[];
+  layout(builtin=0) highfloat4 gl_Position;
+  layout(builtin=1) highfloat gl_PointSize;
+  layout(builtin=3) highfloat sk_ClipDistance[];
 } sk_in[];
 
 out sk_PerVertex {
-    layout(builtin=0) float4 gl_Position;
-    layout(builtin=1) float gl_PointSize;
-    layout(builtin=3) float sk_ClipDistance[];
+    layout(builtin=0) highfloat4 gl_Position;
+    layout(builtin=1) highfloat gl_PointSize;
+    layout(builtin=3) highfloat sk_ClipDistance[];
 };
 
 layout(builtin=8) int sk_InvocationID;
diff --git a/src/sksl/sksl_vert.include b/src/sksl/sksl_vert.include
index 976877c..e7f8419 100644
--- a/src/sksl/sksl_vert.include
+++ b/src/sksl/sksl_vert.include
@@ -3,9 +3,9 @@
 // defines built-in interfaces supported by SkiaSL vertex shaders
 
 out sk_PerVertex {
-    layout(builtin=0) float4 gl_Position;
-    layout(builtin=1) float gl_PointSize;
-    layout(builtin=3) float sk_ClipDistance[1];
+    layout(builtin=0) highfloat4 gl_Position;
+    layout(builtin=1) highfloat gl_PointSize;
+    layout(builtin=3) highfloat sk_ClipDistance[1];
 };
 
 layout(builtin=5) in int sk_VertexID;