Replace TCache with static TType instances

Replaces TCache with (static generation + static/dynamic lookups) of
TType instances, using compile-time template and constexpr magic.

Work started by jmadill here: https://crrev.com/c/776280
With more contributions from jmadill here: https://crrev.com/c/801494

Bug: angleproject:1432
Change-Id: I07181543f8fee4b2606cdd2d0738351e83d4ce57
Reviewed-on: https://chromium-review.googlesource.com/786317
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/compiler/translator/BaseTypes.h b/src/compiler/translator/BaseTypes.h
index b2070f3..31b7325 100644
--- a/src/compiler/translator/BaseTypes.h
+++ b/src/compiler/translator/BaseTypes.h
@@ -129,58 +129,95 @@
     EbtLast
 };
 
-inline TBasicType convertGImageToFloatImage(TBasicType type)
+constexpr const char *GetBasicMangledName(TBasicType t)
 {
-    switch (type)
+    switch (t)
     {
-        case EbtGImage2D:
-            return EbtImage2D;
-        case EbtGImage3D:
-            return EbtImage3D;
-        case EbtGImage2DArray:
-            return EbtImage2DArray;
-        case EbtGImageCube:
-            return EbtImageCube;
+        case EbtFloat:
+            return "f";
+        case EbtInt:
+            return "i";
+        case EbtUInt:
+            return "u";
+        case EbtBool:
+            return "b";
+        case EbtYuvCscStandardEXT:
+            return "ycs";
+        case EbtSampler2D:
+            return "s2";
+        case EbtSampler3D:
+            return "s3";
+        case EbtSamplerCube:
+            return "sC";
+        case EbtSampler2DArray:
+            return "s2a";
+        case EbtSamplerExternalOES:
+            return "sext";
+        case EbtSamplerExternal2DY2YEXT:
+            return "sext2y2y";
+        case EbtSampler2DRect:
+            return "s2r";
+        case EbtSampler2DMS:
+            return "s2ms";
+        case EbtISampler2D:
+            return "is2";
+        case EbtISampler3D:
+            return "is3";
+        case EbtISamplerCube:
+            return "isC";
+        case EbtISampler2DArray:
+            return "is2a";
+        case EbtISampler2DMS:
+            return "is2ms";
+        case EbtUSampler2D:
+            return "us2";
+        case EbtUSampler3D:
+            return "us3";
+        case EbtUSamplerCube:
+            return "usC";
+        case EbtUSampler2DArray:
+            return "us2a";
+        case EbtUSampler2DMS:
+            return "us2ms";
+        case EbtSampler2DShadow:
+            return "s2s";
+        case EbtSamplerCubeShadow:
+            return "sCs";
+        case EbtSampler2DArrayShadow:
+            return "s2as";
+        case EbtImage2D:
+            return "im2";
+        case EbtIImage2D:
+            return "iim2";
+        case EbtUImage2D:
+            return "uim2";
+        case EbtImage3D:
+            return "im3";
+        case EbtIImage3D:
+            return "iim3";
+        case EbtUImage3D:
+            return "uim3";
+        case EbtImage2DArray:
+            return "im2a";
+        case EbtIImage2DArray:
+            return "iim2a";
+        case EbtUImage2DArray:
+            return "uim2a";
+        case EbtImageCube:
+            return "imc";
+        case EbtIImageCube:
+            return "iimc";
+        case EbtUImageCube:
+            return "uimc";
+        case EbtAtomicCounter:
+            return "ac";
+        case EbtStruct:
+        case EbtInterfaceBlock:
+            return nullptr;
         default:
-            UNREACHABLE();
+            // EbtVoid, EbtAddress and non types
+            return "";
     }
-    return EbtLast;
-}
-
-inline TBasicType convertGImageToIntImage(TBasicType type)
-{
-    switch (type)
-    {
-        case EbtGImage2D:
-            return EbtIImage2D;
-        case EbtGImage3D:
-            return EbtIImage3D;
-        case EbtGImage2DArray:
-            return EbtIImage2DArray;
-        case EbtGImageCube:
-            return EbtIImageCube;
-        default:
-            UNREACHABLE();
-    }
-    return EbtLast;
-}
-
-inline TBasicType convertGImageToUnsignedImage(TBasicType type)
-{
-    switch (type)
-    {
-        case EbtGImage2D:
-            return EbtUImage2D;
-        case EbtGImage3D:
-            return EbtUImage3D;
-        case EbtGImage2DArray:
-            return EbtUImage2DArray;
-        case EbtGImageCube:
-            return EbtUImageCube;
-        default:
-            UNREACHABLE();
-    }
-    return EbtLast;
 }
 
 const char *getBasicString(TBasicType t);
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index 905e634..5e772eb 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -6,9 +6,9 @@
 
 #include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "angle_gl.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/StaticType.h"
 
 namespace sh
 {
@@ -286,19 +286,19 @@
 
 FunctionId::FunctionId()
     : mOp(EOpNull),
-      mParam1(TCache::getType(EbtVoid)),
-      mParam2(TCache::getType(EbtVoid)),
-      mParam3(TCache::getType(EbtVoid)),
-      mParam4(TCache::getType(EbtVoid))
+      mParam1(StaticType::GetBasic<EbtVoid>()),
+      mParam2(StaticType::GetBasic<EbtVoid>()),
+      mParam3(StaticType::GetBasic<EbtVoid>()),
+      mParam4(StaticType::GetBasic<EbtVoid>())
 {
 }
 
 FunctionId::FunctionId(TOperator op, const TType *param)
     : mOp(op),
       mParam1(param),
-      mParam2(TCache::getType(EbtVoid)),
-      mParam3(TCache::getType(EbtVoid)),
-      mParam4(TCache::getType(EbtVoid))
+      mParam2(StaticType::GetBasic<EbtVoid>()),
+      mParam3(StaticType::GetBasic<EbtVoid>()),
+      mParam4(StaticType::GetBasic<EbtVoid>())
 {
 }
 
@@ -306,13 +306,17 @@
     : mOp(op),
       mParam1(param1),
       mParam2(param2),
-      mParam3(TCache::getType(EbtVoid)),
-      mParam4(TCache::getType(EbtVoid))
+      mParam3(StaticType::GetBasic<EbtVoid>()),
+      mParam4(StaticType::GetBasic<EbtVoid>())
 {
 }
 
 FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3)
-    : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(TCache::getType(EbtVoid))
+    : mOp(op),
+      mParam1(param1),
+      mParam2(param2),
+      mParam3(param3),
+      mParam4(StaticType::GetBasic<EbtVoid>())
 {
 }
 
diff --git a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
index 27ee04d..b6d998b 100644
--- a/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -4,11 +4,11 @@
 // found in the LICENSE file.
 //
 
+#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulator.h"
-#include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/StaticType.h"
 #include "compiler/translator/VersionGLSL.h"
 
 namespace sh
@@ -19,7 +19,7 @@
 {
     if (shaderType == GL_VERTEX_SHADER)
     {
-        const TType *int1 = TCache::getType(EbtInt);
+        const TType *int1 = StaticType::GetBasic<EbtInt>();
         emu->addEmulatedFunction(EOpAbs, int1, "int abs_emu(int x) { return x * sign(x); }");
     }
 }
@@ -31,10 +31,10 @@
     if (targetGLSLVersion < GLSL_VERSION_130)
         return;
 
-    const TType *float1 = TCache::getType(EbtFloat);
-    const TType *float2 = TCache::getType(EbtFloat, 2);
-    const TType *float3 = TCache::getType(EbtFloat, 3);
-    const TType *float4 = TCache::getType(EbtFloat, 4);
+    const TType *float1 = StaticType::GetBasic<EbtFloat>();
+    const TType *float2 = StaticType::GetBasic<EbtFloat, 2>();
+    const TType *float3 = StaticType::GetBasic<EbtFloat, 3>();
+    const TType *float4 = StaticType::GetBasic<EbtFloat, 4>();
 
     // !(x > 0.0 || x < 0.0 || x == 0.0) will be optimized and always equal to false.
     emu->addEmulatedFunction(
@@ -77,7 +77,7 @@
 
 void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu)
 {
-    const TType *float1 = TCache::getType(EbtFloat);
+    const TType *float1 = StaticType::GetBasic<EbtFloat>();
     auto floatFuncId    = emu->addEmulatedFunction(
         EOpAtan, float1, float1,
         "emu_precision float atan_emu(emu_precision float y, emu_precision "
@@ -88,9 +88,16 @@
         "    else if (x < 0.0 && y < 0.0) return atan(y / x) - 3.14159265;\n"
         "    else return 1.57079632 * sign(y);\n"
         "}\n");
+    static const std::array<const TType *, 5> floatVecs = {
+        nullptr,
+        nullptr,
+        StaticType::GetBasic<EbtFloat, 2>(),
+        StaticType::GetBasic<EbtFloat, 3>(),
+        StaticType::GetBasic<EbtFloat, 4>(),
+    };
     for (int dim = 2; dim <= 4; ++dim)
     {
-        const TType *floatVec = TCache::getType(EbtFloat, static_cast<unsigned char>(dim));
+        const TType *floatVec = floatVecs[dim];
         std::stringstream ss;
         ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim
            << " y, emu_precision vec" << dim << " x)\n"
@@ -120,8 +127,8 @@
     // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
     if (targetGLSLVersion < GLSL_VERSION_410)
     {
-        const TType *float2 = TCache::getType(EbtFloat, 2);
-        const TType *uint1  = TCache::getType(EbtUInt);
+        const TType *float2 = StaticType::GetBasic<EbtFloat, 2>();
+        const TType *uint1  = StaticType::GetBasic<EbtUInt>();
 
         // clang-format off
         emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
@@ -146,8 +153,8 @@
     // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
     if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
     {
-        const TType *float2 = TCache::getType(EbtFloat, 2);
-        const TType *uint1  = TCache::getType(EbtUInt);
+        const TType *float2 = StaticType::GetBasic<EbtFloat, 2>();
+        const TType *uint1  = StaticType::GetBasic<EbtUInt>();
 
         // clang-format off
         emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
diff --git a/src/compiler/translator/Cache.cpp b/src/compiler/translator/Cache.cpp
deleted file mode 100644
index 417e824..0000000
--- a/src/compiler/translator/Cache.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// Cache.cpp: Implements a cache for various commonly created objects.
-
-#include <limits>
-
-#include "common/angleutils.h"
-#include "common/debug.h"
-#include "compiler/translator/Cache.h"
-
-namespace sh
-{
-
-namespace
-{
-
-class TScopedAllocator : angle::NonCopyable
-{
-  public:
-    TScopedAllocator(TPoolAllocator *allocator) : mPreviousAllocator(GetGlobalPoolAllocator())
-    {
-        SetGlobalPoolAllocator(allocator);
-    }
-    ~TScopedAllocator() { SetGlobalPoolAllocator(mPreviousAllocator); }
-
-  private:
-    TPoolAllocator *mPreviousAllocator;
-};
-
-}  // namespace
-
-TCache::TypeKey::TypeKey(TBasicType basicType,
-                         TPrecision precision,
-                         TQualifier qualifier,
-                         unsigned char primarySize,
-                         unsigned char secondarySize)
-{
-    static_assert(sizeof(components) <= sizeof(value), "TypeKey::value is too small");
-
-    const size_t MaxEnumValue = std::numeric_limits<EnumComponentType>::max();
-
-    // TODO: change to static_assert() once we deprecate MSVC 2013 support
-    ASSERT(MaxEnumValue >= EbtLast && MaxEnumValue >= EbpLast && MaxEnumValue >= EvqLast &&
-           "TypeKey::EnumComponentType is too small");
-
-    value                    = 0;
-    components.basicType     = static_cast<EnumComponentType>(basicType);
-    components.precision     = static_cast<EnumComponentType>(precision);
-    components.qualifier     = static_cast<EnumComponentType>(qualifier);
-    components.primarySize   = primarySize;
-    components.secondarySize = secondarySize;
-}
-
-TCache *TCache::sCache = nullptr;
-
-TCache::TCache()
-{
-}
-
-void TCache::initialize()
-{
-    if (sCache == nullptr)
-    {
-        sCache = new TCache();
-    }
-}
-
-void TCache::destroy()
-{
-    SafeDelete(sCache);
-}
-
-const TType *TCache::getType(TBasicType basicType,
-                             TPrecision precision,
-                             TQualifier qualifier,
-                             unsigned char primarySize,
-                             unsigned char secondarySize)
-{
-    TypeKey key(basicType, precision, qualifier, primarySize, secondarySize);
-    auto it = sCache->mTypes.find(key);
-    if (it != sCache->mTypes.end())
-    {
-        return it->second;
-    }
-
-    TScopedAllocator scopedAllocator(&sCache->mAllocator);
-
-    TType *type = new TType(basicType, precision, qualifier, primarySize, secondarySize);
-    type->realize();
-    sCache->mTypes.insert(std::make_pair(key, type));
-
-    return type;
-}
-
-}  // namespace sh
diff --git a/src/compiler/translator/Cache.h b/src/compiler/translator/Cache.h
deleted file mode 100644
index a182b07..0000000
--- a/src/compiler/translator/Cache.h
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-// Cache.h: Implements a cache for various commonly created objects.
-
-#ifndef COMPILER_TRANSLATOR_CACHE_H_
-#define COMPILER_TRANSLATOR_CACHE_H_
-
-#include <stdint.h>
-#include <string.h>
-#include <map>
-
-#include "compiler/translator/Types.h"
-#include "compiler/translator/PoolAlloc.h"
-
-namespace sh
-{
-
-class TCache
-{
-  public:
-    static void initialize();
-    static void destroy();
-
-    static const TType *getType(TBasicType basicType, TPrecision precision)
-    {
-        return getType(basicType, precision, EvqTemporary, 1, 1);
-    }
-    static const TType *getType(TBasicType basicType,
-                                unsigned char primarySize   = 1,
-                                unsigned char secondarySize = 1)
-    {
-        return getType(basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize);
-    }
-    static const TType *getType(TBasicType basicType,
-                                TQualifier qualifier,
-                                unsigned char primarySize   = 1,
-                                unsigned char secondarySize = 1)
-    {
-        return getType(basicType, EbpUndefined, qualifier, primarySize, secondarySize);
-    }
-    static const TType *getType(TBasicType basicType,
-                                TPrecision precision,
-                                TQualifier qualifier,
-                                unsigned char primarySize,
-                                unsigned char secondarySize);
-
-  private:
-    TCache();
-
-    union TypeKey {
-        TypeKey(TBasicType basicType,
-                TPrecision precision,
-                TQualifier qualifier,
-                unsigned char primarySize,
-                unsigned char secondarySize);
-
-        typedef uint8_t EnumComponentType;
-        struct
-        {
-            EnumComponentType basicType;
-            EnumComponentType precision;
-            EnumComponentType qualifier;
-            unsigned char primarySize;
-            unsigned char secondarySize;
-        } components;
-        uint64_t value;
-
-        bool operator<(const TypeKey &other) const { return value < other.value; }
-    };
-    typedef std::map<TypeKey, const TType *> TypeMap;
-
-    TypeMap mTypes;
-    TPoolAllocator mAllocator;
-
-    static TCache *sCache;
-};
-
-}  // namespace sh
-
-#endif  // COMPILER_TRANSLATOR_CACHE_H_
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index f0df223..abb60cc 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -11,7 +11,6 @@
 #include "angle_gl.h"
 #include "common/utilities.h"
 #include "compiler/translator/AddAndTrueToLoopCondition.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/CallDAG.h"
 #include "compiler/translator/ClampPointSize.h"
 #include "compiler/translator/CollectVariables.h"
diff --git a/src/compiler/translator/Initialize.cpp b/src/compiler/translator/Initialize.cpp
index d637ed0..8a43539 100644
--- a/src/compiler/translator/Initialize.cpp
+++ b/src/compiler/translator/Initialize.cpp
@@ -11,7 +11,7 @@
 //
 
 #include "compiler/translator/Initialize.h"
-#include "compiler/translator/Cache.h"
+#include "compiler/translator/StaticType.h"
 
 #include "compiler/translator/IntermNode.h"
 #include "angle_gl.h"
@@ -24,20 +24,20 @@
                             const ShBuiltInResources &resources,
                             TSymbolTable &symbolTable)
 {
-    const TType *voidType = TCache::getType(EbtVoid);
-    const TType *float1   = TCache::getType(EbtFloat);
-    const TType *float2   = TCache::getType(EbtFloat, 2);
-    const TType *float3   = TCache::getType(EbtFloat, 3);
-    const TType *float4   = TCache::getType(EbtFloat, 4);
-    const TType *int1     = TCache::getType(EbtInt);
-    const TType *int2     = TCache::getType(EbtInt, 2);
-    const TType *int3     = TCache::getType(EbtInt, 3);
-    const TType *uint1    = TCache::getType(EbtUInt);
-    const TType *bool1    = TCache::getType(EbtBool);
-    const TType *genType  = TCache::getType(EbtGenType);
-    const TType *genIType = TCache::getType(EbtGenIType);
-    const TType *genUType = TCache::getType(EbtGenUType);
-    const TType *genBType = TCache::getType(EbtGenBType);
+    const TType *voidType = StaticType::GetBasic<EbtVoid>();
+    const TType *float1   = StaticType::GetBasic<EbtFloat>();
+    const TType *float2   = StaticType::GetBasic<EbtFloat, 2>();
+    const TType *float3   = StaticType::GetBasic<EbtFloat, 3>();
+    const TType *float4   = StaticType::GetBasic<EbtFloat, 4>();
+    const TType *int1     = StaticType::GetBasic<EbtInt>();
+    const TType *int2     = StaticType::GetBasic<EbtInt, 2>();
+    const TType *int3     = StaticType::GetBasic<EbtInt, 3>();
+    const TType *uint1    = StaticType::GetBasic<EbtUInt>();
+    const TType *bool1    = StaticType::GetBasic<EbtBool>();
+    const TType *genType  = StaticType::GetBasic<EbtGenType>();
+    const TType *genIType = StaticType::GetBasic<EbtGenIType>();
+    const TType *genUType = StaticType::GetBasic<EbtGenUType>();
+    const TType *genBType = StaticType::GetBasic<EbtGenBType>();
 
     //
     // Angle and Trigonometric Functions.
@@ -110,8 +110,8 @@
     symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSmoothStep, genType, genType, genType, genType);
     symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpSmoothStep, genType, float1, float1, genType);
 
-    const TType *outGenType = TCache::getType(EbtGenType, EvqOut);
-    const TType *outGenIType = TCache::getType(EbtGenIType, EvqOut);
+    const TType *outGenType  = StaticType::GetQualified<EbtGenType, EvqOut>();
+    const TType *outGenIType = StaticType::GetQualified<EbtGenIType, EvqOut>();
 
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpModf, genType, genType, outGenType);
 
@@ -150,15 +150,15 @@
     symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpReflect, genType, genType, genType);
     symbolTable.insertBuiltInOp(COMMON_BUILTINS, EOpRefract, genType, genType, genType, float1);
 
-    const TType *mat2   = TCache::getType(EbtFloat, 2, 2);
-    const TType *mat3   = TCache::getType(EbtFloat, 3, 3);
-    const TType *mat4   = TCache::getType(EbtFloat, 4, 4);
-    const TType *mat2x3 = TCache::getType(EbtFloat, 2, 3);
-    const TType *mat3x2 = TCache::getType(EbtFloat, 3, 2);
-    const TType *mat2x4 = TCache::getType(EbtFloat, 2, 4);
-    const TType *mat4x2 = TCache::getType(EbtFloat, 4, 2);
-    const TType *mat3x4 = TCache::getType(EbtFloat, 3, 4);
-    const TType *mat4x3 = TCache::getType(EbtFloat, 4, 3);
+    const TType *mat2   = StaticType::GetBasic<EbtFloat, 2, 2>();
+    const TType *mat3   = StaticType::GetBasic<EbtFloat, 3, 3>();
+    const TType *mat4   = StaticType::GetBasic<EbtFloat, 4, 4>();
+    const TType *mat2x3 = StaticType::GetBasic<EbtFloat, 2, 3>();
+    const TType *mat3x2 = StaticType::GetBasic<EbtFloat, 3, 2>();
+    const TType *mat2x4 = StaticType::GetBasic<EbtFloat, 2, 4>();
+    const TType *mat4x2 = StaticType::GetBasic<EbtFloat, 4, 2>();
+    const TType *mat3x4 = StaticType::GetBasic<EbtFloat, 3, 4>();
+    const TType *mat4x3 = StaticType::GetBasic<EbtFloat, 4, 3>();
 
     //
     // Matrix Functions.
@@ -201,10 +201,10 @@
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpInverse, mat3, mat3);
     symbolTable.insertBuiltInOp(ESSL3_BUILTINS, EOpInverse, mat4, mat4);
 
-    const TType *vec  = TCache::getType(EbtVec);
-    const TType *ivec = TCache::getType(EbtIVec);
-    const TType *uvec = TCache::getType(EbtUVec);
-    const TType *bvec = TCache::getType(EbtBVec);
+    const TType *vec  = StaticType::GetBasic<EbtVec>();
+    const TType *ivec = StaticType::GetBasic<EbtIVec>();
+    const TType *uvec = StaticType::GetBasic<EbtUVec>();
+    const TType *bvec = StaticType::GetBasic<EbtBVec>();
 
     //
     // Vector relational functions.
@@ -237,7 +237,7 @@
     //
     // Integer functions
     //
-    const TType *outGenUType = TCache::getType(EbtGenUType, EvqOut);
+    const TType *outGenUType = StaticType::GetQualified<EbtGenUType, EvqOut>();
 
     symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpBitfieldExtract, genIType, genIType, int1,
                                 int1);
@@ -264,8 +264,8 @@
     symbolTable.insertBuiltInOp(ESSL3_1_BUILTINS, EOpImulExtended, voidType, genIType, genIType,
                                 outGenIType, outGenIType);
 
-    const TType *sampler2D   = TCache::getType(EbtSampler2D);
-    const TType *samplerCube = TCache::getType(EbtSamplerCube);
+    const TType *sampler2D   = StaticType::GetBasic<EbtSampler2D>();
+    const TType *samplerCube = StaticType::GetBasic<EbtSamplerCube>();
 
     //
     // Texture Functions for GLSL ES 1.0
@@ -277,7 +277,7 @@
 
     if (resources.OES_EGL_image_external || resources.NV_EGL_stream_consumer_external)
     {
-        const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+        const TType *samplerExternalOES = StaticType::GetBasic<EbtSamplerExternalOES>();
 
         symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2D", samplerExternalOES, float2);
         symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DProj", samplerExternalOES,
@@ -288,7 +288,7 @@
 
     if (resources.ARB_texture_rectangle)
     {
-        const TType *sampler2DRect = TCache::getType(EbtSampler2DRect);
+        const TType *sampler2DRect = StaticType::GetBasic<EbtSampler2DRect>();
 
         symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRect", sampler2DRect, float2);
         symbolTable.insertBuiltIn(ESSL1_BUILTINS, float4, "texture2DRectProj", sampler2DRect,
@@ -357,13 +357,13 @@
                                   float1);
     }
 
-    const TType *gvec4 = TCache::getType(EbtGVec4);
+    const TType *gvec4 = StaticType::GetBasic<EbtGVec4>();
 
-    const TType *gsampler2D      = TCache::getType(EbtGSampler2D);
-    const TType *gsamplerCube    = TCache::getType(EbtGSamplerCube);
-    const TType *gsampler3D      = TCache::getType(EbtGSampler3D);
-    const TType *gsampler2DArray = TCache::getType(EbtGSampler2DArray);
-    const TType *gsampler2DMS    = TCache::getType(EbtGSampler2DMS);
+    const TType *gsampler2D      = StaticType::GetBasic<EbtGSampler2D>();
+    const TType *gsamplerCube    = StaticType::GetBasic<EbtGSamplerCube>();
+    const TType *gsampler3D      = StaticType::GetBasic<EbtGSampler3D>();
+    const TType *gsampler2DArray = StaticType::GetBasic<EbtGSampler2DArray>();
+    const TType *gsampler2DMS    = StaticType::GetBasic<EbtGSampler2DMS>();
 
     //
     // Texture Functions for GLSL ES 3.0
@@ -382,7 +382,7 @@
 
     if (resources.OES_EGL_image_external_essl3)
     {
-        const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+        const TType *samplerExternalOES = StaticType::GetBasic<EbtSamplerExternalOES>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2);
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "textureProj", samplerExternalOES,
@@ -393,7 +393,8 @@
 
     if (resources.EXT_YUV_target)
     {
-        const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT);
+        const TType *samplerExternal2DY2YEXT =
+            StaticType::GetBasic<EbtSamplerExternal2DY2YEXT>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texture",
                                   samplerExternal2DY2YEXT, float2);
@@ -402,7 +403,7 @@
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "textureProj",
                                   samplerExternal2DY2YEXT, float4);
 
-        const TType *yuvCscStandardEXT = TCache::getType(EbtYuvCscStandardEXT);
+        const TType *yuvCscStandardEXT = StaticType::GetBasic<EbtYuvCscStandardEXT>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float3, "rgb_2_yuv",
                                   float3, yuvCscStandardEXT);
@@ -423,7 +424,7 @@
 
         if (resources.OES_EGL_image_external_essl3)
         {
-            const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+            const TType *samplerExternalOES = StaticType::GetBasic<EbtSamplerExternalOES>();
 
             symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texture", samplerExternalOES, float2,
                                       float1);
@@ -435,7 +436,8 @@
 
         if (resources.EXT_YUV_target)
         {
-            const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT);
+            const TType *samplerExternal2DY2YEXT =
+                StaticType::GetBasic<EbtSamplerExternal2DY2YEXT>();
 
             symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texture",
                                       samplerExternal2DY2YEXT, float2, float1);
@@ -446,9 +448,9 @@
         }
     }
 
-    const TType *sampler2DShadow      = TCache::getType(EbtSampler2DShadow);
-    const TType *samplerCubeShadow    = TCache::getType(EbtSamplerCubeShadow);
-    const TType *sampler2DArrayShadow = TCache::getType(EbtSampler2DArrayShadow);
+    const TType *sampler2DShadow      = StaticType::GetBasic<EbtSampler2DShadow>();
+    const TType *samplerCubeShadow    = StaticType::GetBasic<EbtSamplerCubeShadow>();
+    const TType *sampler2DArrayShadow = StaticType::GetBasic<EbtSampler2DArrayShadow>();
 
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", sampler2DShadow, float3);
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "texture", samplerCubeShadow, float4);
@@ -478,14 +480,15 @@
 
     if (resources.OES_EGL_image_external_essl3)
     {
-        const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+        const TType *samplerExternalOES = StaticType::GetBasic<EbtSamplerExternalOES>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, int2, "textureSize", samplerExternalOES, int1);
     }
 
     if (resources.EXT_YUV_target)
     {
-        const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT);
+        const TType *samplerExternal2DY2YEXT =
+            StaticType::GetBasic<EbtSamplerExternal2DY2YEXT>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, int2, "textureSize",
                                   samplerExternal2DY2YEXT, int1);
@@ -565,7 +568,7 @@
 
     if (resources.OES_EGL_image_external_essl3)
     {
-        const TType *samplerExternalOES = TCache::getType(EbtSamplerExternalOES);
+        const TType *samplerExternalOES = StaticType::GetBasic<EbtSamplerExternalOES>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, float4, "texelFetch", samplerExternalOES, int2,
                                   int1);
@@ -573,7 +576,8 @@
 
     if (resources.EXT_YUV_target)
     {
-        const TType *samplerExternal2DY2YEXT = TCache::getType(EbtSamplerExternal2DY2YEXT);
+        const TType *samplerExternal2DY2YEXT =
+            StaticType::GetBasic<EbtSamplerExternal2DY2YEXT>();
 
         symbolTable.insertBuiltIn(ESSL3_BUILTINS, TExtension::EXT_YUV_target, float4, "texelFetch",
                                   samplerExternal2DY2YEXT, int2, int1);
@@ -630,14 +634,14 @@
     symbolTable.insertBuiltIn(ESSL3_BUILTINS, float1, "textureProjGradOffset", sampler2DShadow,
                               float4, float2, float2, int2);
 
-    const TType *atomicCounter = TCache::getType(EbtAtomicCounter);
+    const TType *atomicCounter = StaticType::GetBasic<EbtAtomicCounter>();
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounter", atomicCounter);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounterIncrement", atomicCounter);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCounterDecrement", atomicCounter);
 
     // Insert all atomic memory functions
-    const TType *int1InOut  = TCache::getType(EbtInt, EvqInOut);
-    const TType *uint1InOut = TCache::getType(EbtUInt, EvqInOut);
+    const TType *int1InOut  = StaticType::GetQualified<EbtInt, EvqInOut>();
+    const TType *uint1InOut = StaticType::GetQualified<EbtUInt, EvqInOut>();
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicAdd", uint1InOut, uint1);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicAdd", int1InOut, int1);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicMin", uint1InOut, uint1);
@@ -655,10 +659,10 @@
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, uint1, "atomicCompSwap", uint1InOut, uint1, uint1);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, int1, "atomicCompSwap", int1InOut, int1, int1);
 
-    const TType *gimage2D      = TCache::getType(EbtGImage2D);
-    const TType *gimage3D      = TCache::getType(EbtGImage3D);
-    const TType *gimage2DArray = TCache::getType(EbtGImage2DArray);
-    const TType *gimageCube    = TCache::getType(EbtGImageCube);
+    const TType *gimage2D      = StaticType::GetBasic<EbtGImage2D>();
+    const TType *gimage3D      = StaticType::GetBasic<EbtGImage3D>();
+    const TType *gimage2DArray = StaticType::GetBasic<EbtGImage2DArray>();
+    const TType *gimageCube    = StaticType::GetBasic<EbtGImageCube>();
 
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage2D, int2, gvec4);
     symbolTable.insertBuiltIn(ESSL3_1_BUILTINS, voidType, "imageStore", gimage3D, int3, gvec4);
diff --git a/src/compiler/translator/InitializeDll.cpp b/src/compiler/translator/InitializeDll.cpp
index 43c215f..0698364 100644
--- a/src/compiler/translator/InitializeDll.cpp
+++ b/src/compiler/translator/InitializeDll.cpp
@@ -4,7 +4,6 @@
 // found in the LICENSE file.
 //
 
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/InitializeDll.h"
 #include "compiler/translator/InitializeGlobals.h"
 
@@ -23,15 +22,12 @@
         return false;
     }
 
-    TCache::initialize();
-
     return true;
 }
 
 void DetachProcess()
 {
     FreePoolIndex();
-    TCache::destroy();
 }
 
 }  // namespace sh
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index cc13901..17831fd 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -11,9 +11,9 @@
 
 #include "common/mathutil.h"
 #include "compiler/preprocessor/SourceLocation.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/Declarator.h"
 #include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/StaticType.h"
 #include "compiler/translator/ValidateGlobalInitializer.h"
 #include "compiler/translator/ValidateSwitch.h"
 #include "compiler/translator/glslang.h"
@@ -3457,7 +3457,7 @@
 
 TFunction *TParseContext::addNonConstructorFunc(const TString *name, const TSourceLoc &loc)
 {
-    const TType *returnType = TCache::getType(EbtVoid, EbpUndefined);
+    const TType *returnType = StaticType::GetQualified<EbtVoid, EvqTemporary>();
     return new TFunction(&symbolTable, name, returnType);
 }
 
diff --git a/src/compiler/translator/StaticType.cpp b/src/compiler/translator/StaticType.cpp
new file mode 100644
index 0000000..1f30755
--- /dev/null
+++ b/src/compiler/translator/StaticType.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Compile-time instances of many common TType values. These are looked up
+// (statically or dynamically) through the methods defined in the namespace.
+//
+
+#include "compiler/translator/StaticType.h"
+
+namespace sh
+{
+
+namespace StaticType
+{
+
+const TType *GetForFloatImage(TBasicType basicType)
+{
+    switch (basicType)
+    {
+        case EbtGImage2D:
+            return Get<EbtImage2D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage3D:
+            return Get<EbtImage3D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage2DArray:
+            return Get<EbtImage2DArray, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImageCube:
+            return Get<EbtImageCube, EbpUndefined, EvqGlobal, 1, 1>();
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+const TType *GetForIntImage(TBasicType basicType)
+{
+    switch (basicType)
+    {
+        case EbtGImage2D:
+            return Get<EbtIImage2D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage3D:
+            return Get<EbtIImage3D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage2DArray:
+            return Get<EbtIImage2DArray, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImageCube:
+            return Get<EbtIImageCube, EbpUndefined, EvqGlobal, 1, 1>();
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+const TType *GetForUintImage(TBasicType basicType)
+{
+    switch (basicType)
+    {
+        case EbtGImage2D:
+            return Get<EbtUImage2D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage3D:
+            return Get<EbtUImage3D, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImage2DArray:
+            return Get<EbtUImage2DArray, EbpUndefined, EvqGlobal, 1, 1>();
+        case EbtGImageCube:
+            return Get<EbtUImageCube, EbpUndefined, EvqGlobal, 1, 1>();
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+}  // namespace StaticType
+
+}  // namespace sh
diff --git a/src/compiler/translator/StaticType.h b/src/compiler/translator/StaticType.h
new file mode 100644
index 0000000..e26e5ff
--- /dev/null
+++ b/src/compiler/translator/StaticType.h
@@ -0,0 +1,235 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Compile-time instances of many common TType values. These are looked up
+// (statically or dynamically) through the methods defined in the namespace.
+//
+
+#ifndef COMPILER_TRANSLATOR_STATIC_TYPE_H_
+#define COMPILER_TRANSLATOR_STATIC_TYPE_H_
+
+#include "compiler/translator/Types.h"
+
+namespace sh
+{
+
+namespace StaticType
+{
+
+namespace Helpers
+{
+
+//
+// Generation and static allocation of type mangled name values.
+//
+
+// Size of the maximum possible constexpr-generated mangled name.
+// If this value is too small, the compiler will produce errors.
+static constexpr size_t kStaticMangledNameMaxLength = 10;
+
+// Type which holds the mangled names for constexpr-generated TTypes.
+// This simple struct is needed so that a char array can be returned by value.
+struct StaticMangledName
+{
+    // If this array is too small, the compiler will produce errors.
+    char name[kStaticMangledNameMaxLength + 1] = {};
+};
+
+// Generates a mangled name for a TType given its parameters.
+constexpr StaticMangledName BuildStaticMangledName(TBasicType basicType,
+                                                   TPrecision precision,
+                                                   TQualifier qualifier,
+                                                   unsigned char primarySize,
+                                                   unsigned char secondarySize)
+{
+    StaticMangledName name = {};
+    // When this function is executed constexpr (should be always),
+    // name.name[at] is guaranteed by the compiler to never go out of bounds.
+    size_t at = 0;
+
+    bool isMatrix = primarySize > 1 && secondarySize > 1;
+    bool isVector = primarySize > 1 && secondarySize == 1;
+
+    if (isMatrix)
+    {
+        name.name[at++] = 'm';
+    }
+    else if (isVector)
+    {
+        name.name[at++] = 'v';
+    }
+
+    {
+        const char *basicMangledName = GetBasicMangledName(basicType);
+        for (size_t i = 0; basicMangledName[i] != '\0'; ++i)
+        {
+            name.name[at++] = basicMangledName[i];
+        }
+    }
+
+    name.name[at++] = '0' + primarySize;
+    if (isMatrix)
+    {
+        name.name[at++] = 'x';
+        name.name[at++] = '0' + secondarySize;
+    }
+
+    name.name[at++] = ';';
+
+    name.name[at] = '\0';
+    return name;
+}
+
+// This "variable" contains the mangled names for every constexpr-generated TType.
+// If kMangledNameInstance<B, P, Q, PS, SS> is used anywhere (specifally
+// in kInstance, below), this is where the appropriate type will be stored.
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char primarySize,
+          unsigned char secondarySize>
+static constexpr StaticMangledName kMangledNameInstance =
+    BuildStaticMangledName(basicType, precision, qualifier, primarySize, secondarySize);
+
+//
+// Generation and static allocation of TType values.
+//
+
+// This "variable" contains every constexpr-generated TType.
+// If kInstance<B, P, Q, PS, SS> is used anywhere (specifally
+// in Get, below), this is where the appropriate type will be stored.
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char primarySize,
+          unsigned char secondarySize>
+static constexpr TType kInstance =
+    TType(basicType,
+          precision,
+          qualifier,
+          primarySize,
+          secondarySize,
+          kMangledNameInstance<basicType, precision, qualifier, primarySize, secondarySize>.name);
+
+}  // namespace Helpers
+
+//
+// Fully-qualified type lookup.
+//
+
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char primarySize,
+          unsigned char secondarySize>
+constexpr const TType *Get()
+{
+    static_assert(1 <= primarySize && primarySize <= 4, "primarySize out of bounds");
+    static_assert(1 <= secondarySize && secondarySize <= 4, "secondarySize out of bounds");
+    return &Helpers::kInstance<basicType, precision, qualifier, primarySize, secondarySize>;
+}
+
+//
+// Overloads
+//
+
+template <TBasicType basicType, unsigned char primarySize = 1, unsigned char secondarySize = 1>
+constexpr const TType *GetBasic()
+{
+    return Get<basicType, EbpUndefined, EvqGlobal, primarySize, secondarySize>();
+}
+
+template <TBasicType basicType,
+          TQualifier qualifier,
+          unsigned char primarySize   = 1,
+          unsigned char secondarySize = 1>
+const TType *GetQualified()
+{
+    return Get<basicType, EbpUndefined, qualifier, primarySize, secondarySize>();
+}
+
+// Dynamic lookup methods (convert runtime values to template args)
+
+namespace Helpers
+{
+
+// Helper which takes secondarySize statically but primarySize dynamically.
+template <TBasicType basicType,
+          TPrecision precision,
+          TQualifier qualifier,
+          unsigned char secondarySize>
+const TType *GetForVecMatHelper(unsigned char primarySize)
+{
+    static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
+                      basicType == EbtBool,
+                  "unsupported basicType");
+    switch (primarySize)
+    {
+        case 1:
+            return Get<basicType, precision, qualifier, 1, secondarySize>();
+        case 2:
+            return Get<basicType, precision, qualifier, 2, secondarySize>();
+        case 3:
+            return Get<basicType, precision, qualifier, 3, secondarySize>();
+        case 4:
+            return Get<basicType, precision, qualifier, 4, secondarySize>();
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+}  // namespace Helpers
+
+template <TBasicType basicType,
+          TPrecision precision = EbpUndefined,
+          TQualifier qualifier = EvqGlobal>
+const TType *GetForVecMat(unsigned char primarySize, unsigned char secondarySize = 1)
+{
+    static_assert(basicType == EbtFloat || basicType == EbtInt || basicType == EbtUInt ||
+                      basicType == EbtBool,
+                  "unsupported basicType");
+    switch (secondarySize)
+    {
+        case 1:
+            return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 1>(primarySize);
+        case 2:
+            return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 2>(primarySize);
+        case 3:
+            return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 3>(primarySize);
+        case 4:
+            return Helpers::GetForVecMatHelper<basicType, precision, qualifier, 4>(primarySize);
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+template <TBasicType basicType, TPrecision precision = EbpUndefined>
+const TType *GetForVec(TQualifier qualifier, unsigned char size)
+{
+    switch (qualifier)
+    {
+        case EvqGlobal:
+            return Helpers::GetForVecMatHelper<basicType, precision, EvqGlobal, 1>(size);
+        case EvqOut:
+            return Helpers::GetForVecMatHelper<basicType, precision, EvqOut, 1>(size);
+        default:
+            UNREACHABLE();
+            return GetBasic<EbtVoid>();
+    }
+}
+
+const TType *GetForFloatImage(TBasicType basicType);
+
+const TType *GetForIntImage(TBasicType basicType);
+
+const TType *GetForUintImage(TBasicType basicType);
+
+}  // namespace StaticType
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_STATIC_TYPE_H_
diff --git a/src/compiler/translator/SymbolTable.cpp b/src/compiler/translator/SymbolTable.cpp
index 39f4f54..62bd3ba 100644
--- a/src/compiler/translator/SymbolTable.cpp
+++ b/src/compiler/translator/SymbolTable.cpp
@@ -13,8 +13,8 @@
 
 #include "compiler/translator/SymbolTable.h"
 
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/IntermNode.h"
+#include "compiler/translator/StaticType.h"
 
 #include <stdio.h>
 #include <algorithm>
@@ -249,7 +249,7 @@
     return false;
 }
 
-const TType *SpecificType(const TType *type, int size)
+constexpr const TType *SpecificType(const TType *type, int size)
 {
     ASSERT(size >= 1 && size <= 4);
 
@@ -263,20 +263,23 @@
     switch (type->getBasicType())
     {
         case EbtGenType:
-            return TCache::getType(EbtFloat, type->getQualifier(),
-                                   static_cast<unsigned char>(size));
+            return StaticType::GetForVec<EbtFloat>(type->getQualifier(),
+                                                            static_cast<unsigned char>(size));
         case EbtGenIType:
-            return TCache::getType(EbtInt, type->getQualifier(), static_cast<unsigned char>(size));
+            return StaticType::GetForVec<EbtInt>(type->getQualifier(),
+                                                          static_cast<unsigned char>(size));
         case EbtGenUType:
-            return TCache::getType(EbtUInt, type->getQualifier(), static_cast<unsigned char>(size));
+            return StaticType::GetForVec<EbtUInt>(type->getQualifier(),
+                                                           static_cast<unsigned char>(size));
         case EbtGenBType:
-            return TCache::getType(EbtBool, type->getQualifier(), static_cast<unsigned char>(size));
+            return StaticType::GetForVec<EbtBool>(type->getQualifier(),
+                                                           static_cast<unsigned char>(size));
         default:
             return type;
     }
 }
 
-const TType *VectorType(const TType *type, int size)
+constexpr const TType *VectorType(const TType *type, int size)
 {
     ASSERT(size >= 2 && size <= 4);
 
@@ -290,13 +293,13 @@
     switch (type->getBasicType())
     {
         case EbtVec:
-            return TCache::getType(EbtFloat, static_cast<unsigned char>(size));
+            return StaticType::GetForVecMat<EbtFloat>(static_cast<unsigned char>(size));
         case EbtIVec:
-            return TCache::getType(EbtInt, static_cast<unsigned char>(size));
+            return StaticType::GetForVecMat<EbtInt>(static_cast<unsigned char>(size));
         case EbtUVec:
-            return TCache::getType(EbtUInt, static_cast<unsigned char>(size));
+            return StaticType::GetForVecMat<EbtUInt>(static_cast<unsigned char>(size));
         case EbtBVec:
-            return TCache::getType(EbtBool, static_cast<unsigned char>(size));
+            return StaticType::GetForVecMat<EbtBool>(static_cast<unsigned char>(size));
         default:
             return type;
     }
@@ -398,70 +401,71 @@
     {
         insertUnmangledBuiltInName(name, level);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name,
-                      TCache::getType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name,
-                      TCache::getType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name,
-                      TCache::getType(EbtUSampler2D), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtSampler2D>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtISampler2D>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtUSampler2D>(), ptype2, ptype3, ptype4, ptype5);
     }
     else if (ptype1->getBasicType() == EbtGSampler3D)
     {
         insertUnmangledBuiltInName(name, level);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name,
-                      TCache::getType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name,
-                      TCache::getType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name,
-                      TCache::getType(EbtUSampler3D), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtSampler3D>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtISampler3D>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtUSampler3D>(), ptype2, ptype3, ptype4, ptype5);
     }
     else if (ptype1->getBasicType() == EbtGSamplerCube)
     {
         insertUnmangledBuiltInName(name, level);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name,
-                      TCache::getType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name,
-                      TCache::getType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name,
-                      TCache::getType(EbtUSamplerCube), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtSamplerCube>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtISamplerCube>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtUSamplerCube>(), ptype2, ptype3, ptype4, ptype5);
     }
     else if (ptype1->getBasicType() == EbtGSampler2DArray)
     {
         insertUnmangledBuiltInName(name, level);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name,
-                      TCache::getType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name,
-                      TCache::getType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name,
-                      TCache::getType(EbtUSampler2DArray), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtSampler2DArray>(), ptype2, ptype3, ptype4,
+                      ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtISampler2DArray>(), ptype2, ptype3, ptype4,
+                      ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtUSampler2DArray>(), ptype2, ptype3, ptype4,
+                      ptype5);
     }
     else if (ptype1->getBasicType() == EbtGSampler2DMS)
     {
         insertUnmangledBuiltInName(name, level);
         bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtFloat, 4) : rvalue, name,
-                      TCache::getType(EbtSampler2DMS), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtInt, 4) : rvalue, name,
-                      TCache::getType(EbtISampler2DMS), ptype2, ptype3, ptype4, ptype5);
-        insertBuiltIn(level, gvec4 ? TCache::getType(EbtUInt, 4) : rvalue, name,
-                      TCache::getType(EbtUSampler2DMS), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtFloat, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtSampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtISampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
+        insertBuiltIn(level, gvec4 ? StaticType::GetBasic<EbtUInt, 4>() : rvalue, name,
+                      StaticType::GetBasic<EbtUSampler2DMS>(), ptype2, ptype3, ptype4, ptype5);
     }
     else if (IsGImage(ptype1->getBasicType()))
     {
         insertUnmangledBuiltInName(name, level);
 
-        const TType *floatType    = TCache::getType(EbtFloat, 4);
-        const TType *intType      = TCache::getType(EbtInt, 4);
-        const TType *unsignedType = TCache::getType(EbtUInt, 4);
+        const TType *floatType    = StaticType::GetBasic<EbtFloat, 4>();
+        const TType *intType      = StaticType::GetBasic<EbtInt, 4>();
+        const TType *unsignedType = StaticType::GetBasic<EbtUInt, 4>();
 
-        const TType *floatImage =
-            TCache::getType(convertGImageToFloatImage(ptype1->getBasicType()));
-        const TType *intImage = TCache::getType(convertGImageToIntImage(ptype1->getBasicType()));
-        const TType *unsignedImage =
-            TCache::getType(convertGImageToUnsignedImage(ptype1->getBasicType()));
+        const TType *floatImage    = StaticType::GetForFloatImage(ptype1->getBasicType());
+        const TType *intImage      = StaticType::GetForIntImage(ptype1->getBasicType());
+        const TType *unsignedImage = StaticType::GetForUintImage(ptype1->getBasicType());
 
         // GLSL ES 3.10, Revision 4, 8.12 Image Functions
         if (rvalue->getBasicType() == EbtGVec4)
diff --git a/src/compiler/translator/Types.cpp b/src/compiler/translator/Types.cpp
index 2c0a649..812ab68 100644
--- a/src/compiler/translator/Types.cpp
+++ b/src/compiler/translator/Types.cpp
@@ -463,138 +463,30 @@
     else if (isVector())
         mangledName += 'v';
 
-    switch (type)
+    const char *basicMangledName = GetBasicMangledName(type);
+    if (basicMangledName != nullptr)
     {
-        case EbtFloat:
-            mangledName += 'f';
-            break;
-        case EbtInt:
-            mangledName += 'i';
-            break;
-        case EbtUInt:
-            mangledName += 'u';
-            break;
-        case EbtBool:
-            mangledName += 'b';
-            break;
-        case EbtYuvCscStandardEXT:
-            mangledName += "ycs";
-            break;
-        case EbtSampler2D:
-            mangledName += "s2";
-            break;
-        case EbtSampler3D:
-            mangledName += "s3";
-            break;
-        case EbtSamplerCube:
-            mangledName += "sC";
-            break;
-        case EbtSampler2DArray:
-            mangledName += "s2a";
-            break;
-        case EbtSamplerExternalOES:
-            mangledName += "sext";
-            break;
-        case EbtSamplerExternal2DY2YEXT:
-            mangledName += "sext2y2y";
-            break;
-        case EbtSampler2DRect:
-            mangledName += "s2r";
-            break;
-        case EbtSampler2DMS:
-            mangledName += "s2ms";
-            break;
-        case EbtISampler2D:
-            mangledName += "is2";
-            break;
-        case EbtISampler3D:
-            mangledName += "is3";
-            break;
-        case EbtISamplerCube:
-            mangledName += "isC";
-            break;
-        case EbtISampler2DArray:
-            mangledName += "is2a";
-            break;
-        case EbtISampler2DMS:
-            mangledName += "is2ms";
-            break;
-        case EbtUSampler2D:
-            mangledName += "us2";
-            break;
-        case EbtUSampler3D:
-            mangledName += "us3";
-            break;
-        case EbtUSamplerCube:
-            mangledName += "usC";
-            break;
-        case EbtUSampler2DArray:
-            mangledName += "us2a";
-            break;
-        case EbtUSampler2DMS:
-            mangledName += "us2ms";
-            break;
-        case EbtSampler2DShadow:
-            mangledName += "s2s";
-            break;
-        case EbtSamplerCubeShadow:
-            mangledName += "sCs";
-            break;
-        case EbtSampler2DArrayShadow:
-            mangledName += "s2as";
-            break;
-        case EbtImage2D:
-            mangledName += "im2";
-            break;
-        case EbtIImage2D:
-            mangledName += "iim2";
-            break;
-        case EbtUImage2D:
-            mangledName += "uim2";
-            break;
-        case EbtImage3D:
-            mangledName += "im3";
-            break;
-        case EbtIImage3D:
-            mangledName += "iim3";
-            break;
-        case EbtUImage3D:
-            mangledName += "uim3";
-            break;
-        case EbtImage2DArray:
-            mangledName += "im2a";
-            break;
-        case EbtIImage2DArray:
-            mangledName += "iim2a";
-            break;
-        case EbtUImage2DArray:
-            mangledName += "uim2a";
-            break;
-        case EbtImageCube:
-            mangledName += "imc";
-            break;
-        case EbtIImageCube:
-            mangledName += "iimc";
-            break;
-        case EbtUImageCube:
-            mangledName += "uimc";
-            break;
-        case EbtAtomicCounter:
-            mangledName += "ac";
-            break;
-        case EbtStruct:
-            mangledName += "struct-";
-            mangledName += mStructure->name();
-            mangledName += mStructure->mangledFieldList();
-            break;
-        case EbtInterfaceBlock:
-            mangledName += "iblock-";
-            mangledName += mInterfaceBlock->name();
-            mangledName += mInterfaceBlock->mangledFieldList();
-            break;
-        default:
-            // EbtVoid, EbtAddress and non types
-            break;
+        mangledName += basicMangledName;
+    }
+    else
+    {
+        ASSERT(type == EbtStruct || type == EbtInterfaceBlock);
+        switch (type)
+        {
+            case EbtStruct:
+                mangledName += "struct-";
+                mangledName += mStructure->name();
+                mangledName += mStructure->mangledFieldList();
+                break;
+            case EbtInterfaceBlock:
+                mangledName += "iblock-";
+                mangledName += mInterfaceBlock->name();
+                mangledName += mInterfaceBlock->mangledFieldList();
+                break;
+            default:
+                UNREACHABLE();
+                break;
+        }
     }
 
     if (isMatrix())
diff --git a/src/compiler/translator/Types.h b/src/compiler/translator/Types.h
index 380c374..4401e07 100644
--- a/src/compiler/translator/Types.h
+++ b/src/compiler/translator/Types.h
@@ -126,6 +126,45 @@
     TType(const TType &t);
     TType &operator=(const TType &t);
 
+    constexpr TType(TBasicType t,
+                    TPrecision p,
+                    TQualifier q,
+                    unsigned char ps,
+                    unsigned char ss,
+                    const char *mangledName)
+        : type(t),
+          precision(p),
+          qualifier(q),
+          invariant(false),
+          memoryQualifier(TMemoryQualifier::Create()),
+          layoutQualifier(TLayoutQualifier::Create()),
+          primarySize(ps),
+          secondarySize(ss),
+          mArraySizes(nullptr),
+          mInterfaceBlock(nullptr),
+          mStructure(nullptr),
+          mIsStructSpecifier(false),
+          mMangledName(mangledName)
+    {
+    }
+
+    constexpr TType(TType &&t)
+        : type(t.type),
+          precision(t.precision),
+          qualifier(t.qualifier),
+          invariant(t.invariant),
+          memoryQualifier(t.memoryQualifier),
+          layoutQualifier(t.layoutQualifier),
+          primarySize(t.primarySize),
+          secondarySize(t.secondarySize),
+          mArraySizes(t.mArraySizes),
+          mInterfaceBlock(t.mInterfaceBlock),
+          mStructure(t.mStructure),
+          mIsStructSpecifier(t.mIsStructSpecifier),
+          mMangledName(t.mMangledName)
+    {
+    }
+
     TBasicType getBasicType() const { return type; }
     void setBasicType(TBasicType t);
 
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index eda7d35..e06e59b 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -39,7 +39,6 @@
 #endif
 
 #include "angle_gl.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/Declarator.h"
 #include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/ParseContext.h"
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index 2751f30..5b8c233 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -89,7 +89,6 @@
 #endif
 
 #include "angle_gl.h"
-#include "compiler/translator/Cache.h"
 #include "compiler/translator/Declarator.h"
 #include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/ParseContext.h"