Merge mozilla-central to autoland. a=merge CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Thu, 24 May 2018 18:51:10 +0300
changeset 476430 6c9812ad14dcce232ed605831ceee0e2b3de76db
parent 476429 40eeaf5f1230f959b1d3116214ecb2b03e0d6f8d (current diff)
parent 476412 ff8505d177b9fcba44b040ccd9b6bb709e238e84 (diff)
child 476431 e211ce684becae0de9f483570f3fde8187734cb4
push id1757
push userffxbld-merge
push dateFri, 24 Aug 2018 17:02:43 +0000
treeherdermozilla-release@736023aebdb1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland. a=merge CLOSED TREE
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/shared/customizableui/panelUI.inc.css
gfx/angle/checkout/src/common/FixedVector.h
gfx/angle/checkout/src/compiler/translator/ParseContext_autogen.h
gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.cpp
gfx/angle/checkout/src/compiler/translator/SymbolTable_autogen.h
gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/AddAndTrueToLoopCondition.h
gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/AddDefaultReturnStatements.h
gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/ArrayReturnValueToOutParameter.h
gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/BreakVariableAliasingInInnerLoops.h
gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/ClampFragDepth.h
gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/ClampPointSize.h
gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h
gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/DeferGlobalInitializers.h
gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h
gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/EmulatePrecision.h
gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/ExpandIntegerPowExpressions.h
gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/FoldExpressions.h
gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/InitializeVariables.h
gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/PruneEmptyCases.h
gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/PruneNoOps.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RecordConstantPrecision.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RegenerateStructNames.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveArrayLengthMethod.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveDynamicIndexing.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveInvariantDeclaration.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemovePow.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveSwitchFallThrough.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RemoveUnreferencedVariables.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteDoWhile.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteElseBlocks.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteTexelFetchOffset.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorFloat.h
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/RewriteUnaryMinusOperatorInt.h
gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayConstructorStatements.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateArrayInitialization.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateDeclarations.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateExpressionsReturningArrays.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SimplifyLoopConditions.h
gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/SplitSequenceOperator.h
gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitAST.h
gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/UnfoldShortCircuitToIf.h
gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/UseInterfaceBlockFields.h
gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h
gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.cpp
gfx/angle/checkout/src/compiler/translator/tree_ops/WrapSwitchStatementsInBlocks.h
gfx/angle/checkout/src/compiler/translator/tree_util/BuiltIn_autogen.h
gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/FindMain.h
gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/FindSymbolNode.h
gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/IntermNodePatternMatcher.h
gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/IntermNode_util.h
gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/IntermTraverse.h
gfx/angle/checkout/src/compiler/translator/tree_util/NodeSearch.h
gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/ReplaceVariable.h
gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.cpp
gfx/angle/checkout/src/compiler/translator/tree_util/RunAtTheEndOfShader.h
gfx/angle/checkout/src/libANGLE/Context_gles_1_0.cpp
gfx/angle/checkout/src/libANGLE/Context_gles_1_0_autogen.h
gfx/angle/checkout/src/libANGLE/GLES1State.cpp
gfx/angle/checkout/src/libANGLE/GLES1State.h
gfx/angle/checkout/src/libANGLE/Observer.cpp
gfx/angle/checkout/src/libANGLE/Observer.h
gfx/angle/checkout/src/libANGLE/PackedGLEnums.cpp
gfx/angle/checkout/src/libANGLE/renderer/RenderTargetCache.h
gfx/angle/cherry_picks.txt
js/src/jit/JitCompartment.h
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -789,17 +789,17 @@ you can use these alternative items. Oth
 <!ENTITY identity.disableMixedContentBlocking.accesskey "D">
 <!ENTITY identity.learnMore "Learn More">
 
 <!ENTITY identity.removeCertException.label "Remove Exception">
 <!ENTITY identity.removeCertException.accesskey "R">
 
 <!ENTITY identity.moreInfoLinkText2 "More Information">
 
-<!ENTITY identity.clearSiteData "Clear Cookies and Site Data">
+<!ENTITY identity.clearSiteData "Clear Cookies and Site Data…">
 
 <!ENTITY identity.permissions "Permissions">
 <!ENTITY identity.permissionsEmpty "You have not granted this site any special permissions.">
 <!ENTITY identity.permissionsReloadHint "You may need to reload the page for changes to apply.">
 
 <!-- Name for the tabs toolbar as spoken by screen readers.
      The word "toolbar" is appended automatically and should not be contained below! -->
 <!ENTITY tabsToolbar.label "Browser tabs">
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -604,17 +604,17 @@ toolbarbutton[constrain-size="true"][cui
 .PanelUI-remotetabs-instruction-label {
   /* If you change the margin here, the min-height of the synced tabs panel
     (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, etc) may
     need adjusting (see bug 1248506) */
   margin: 0;
   text-align: center;
   text-shadow: none;
   max-width: 15em;
-  color: rgba(12, 12, 13, 0.5);
+  color: GrayText;
 }
 
 /* The boxes with "instructions" get extra top and bottom padding for space
    around the illustration and buttons */
 .PanelUI-remotetabs-instruction-box {
   /* If you change the padding here, the min-height of the synced tabs panel
     (e.g. #PanelUI-remotetabs[mainview] #PanelUI-remotetabs-setupsync, etc) may
     need adjusting (see bug 1248506) */
--- a/caps/ExpandedPrincipal.cpp
+++ b/caps/ExpandedPrincipal.cpp
@@ -8,20 +8,22 @@
 #include "nsIClassInfoImpl.h"
 
 using namespace mozilla;
 
 NS_IMPL_CLASSINFO(ExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY,
                   NS_EXPANDEDPRINCIPAL_CID)
 NS_IMPL_QUERY_INTERFACE_CI(ExpandedPrincipal,
                            nsIPrincipal,
-                           nsIExpandedPrincipal)
+                           nsIExpandedPrincipal,
+                           nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER(ExpandedPrincipal,
                             nsIPrincipal,
-                            nsIExpandedPrincipal)
+                            nsIExpandedPrincipal,
+                            nsISerializable)
 
 struct OriginComparator
 {
   bool LessThan(nsIPrincipal* a, nsIPrincipal* b) const
   {
     nsAutoCString originA;
     DebugOnly<nsresult> rv = a->GetOrigin(originA);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
@@ -49,16 +51,21 @@ ExpandedPrincipal::ExpandedPrincipal(nsT
   // We force the principals to be sorted by origin so that ExpandedPrincipal
   // origins can have a canonical form.
   OriginComparator c;
   for (size_t i = 0; i < aWhiteList.Length(); ++i) {
     mPrincipals.InsertElementSorted(aWhiteList[i], c);
   }
 }
 
+ExpandedPrincipal::ExpandedPrincipal()
+  : BasePrincipal(eExpandedPrincipal)
+{
+}
+
 ExpandedPrincipal::~ExpandedPrincipal()
 { }
 
 already_AddRefed<ExpandedPrincipal>
 ExpandedPrincipal::Create(nsTArray<nsCOMPtr<nsIPrincipal>>& aWhiteList,
                           const OriginAttributes& aAttrs)
 {
   RefPtr<ExpandedPrincipal> ep = new ExpandedPrincipal(aWhiteList);
@@ -229,19 +236,76 @@ ExpandedPrincipal::GetScriptLocation(nsA
   aStr.AppendLiteral("]]");
   return NS_OK;
 }
 
 //////////////////////////////////////////
 // Methods implementing nsISerializable //
 //////////////////////////////////////////
 
+// We've had way too many issues with unversioned serializations, so
+// explicitly version this one.
+static const uint32_t kSerializationVersion = 1;
+
 NS_IMETHODIMP
 ExpandedPrincipal::Read(nsIObjectInputStream* aStream)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  uint32_t version;
+  nsresult rv = aStream->Read32(&version);
+  if (version != kSerializationVersion) {
+    MOZ_ASSERT(false,
+               "We really need to add handling of the old(?) version here");
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  uint32_t count;
+  rv = aStream->Read32(&count);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  if (!mPrincipals.SetCapacity(count, fallible)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  OriginComparator c;
+  for (uint32_t i = 0; i < count; ++i) {
+    nsCOMPtr<nsISupports> read;
+    rv = aStream->ReadObject(true, getter_AddRefs(read));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(read);
+    if (!principal) {
+      return NS_ERROR_UNEXPECTED;
+    }
+
+    // Play it safe and InsertElementSorted, in case the sort order
+    // changed for some bizarre reason.
+    mPrincipals.InsertElementSorted(Move(principal), c);
+  }
+
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 ExpandedPrincipal::Write(nsIObjectOutputStream* aStream)
 {
-  return NS_ERROR_NOT_IMPLEMENTED;
+  nsresult rv = aStream->Write32(kSerializationVersion);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  rv = aStream->Write32(mPrincipals.Length());
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  for (auto& principal : mPrincipals) {
+    rv = aStream->WriteObject(principal, true);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+  }
+
+  return NS_OK;
 }
--- a/caps/ExpandedPrincipal.h
+++ b/caps/ExpandedPrincipal.h
@@ -17,16 +17,20 @@ class ExpandedPrincipal : public nsIExpa
 {
 public:
   static already_AddRefed<ExpandedPrincipal>
   Create(nsTArray<nsCOMPtr<nsIPrincipal>>& aWhiteList,
          const mozilla::OriginAttributes& aAttrs);
 
   static PrincipalKind Kind() { return eExpandedPrincipal; }
 
+  // For use from the XPCOM factory constructor only.  Do not ever use this
+  // constructor by hand!
+  ExpandedPrincipal();
+
   NS_DECL_NSIEXPANDEDPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
   NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); };
   NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); };
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
   NS_IMETHOD GetHashValue(uint32_t* aHashValue) override;
   NS_IMETHOD GetURI(nsIURI** aURI) override;
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -4952,17 +4952,17 @@ support-files = always-fail.html
                 checkout/test-guidelines.md
                 checkout/webgl-conformance-tests.html
                 iframe-passthrough.css
                 mochi-single.html
 
 [generated/test_..__always-fail.html]
 fail-if = 1
 [generated/test_2_conformance2__attribs__gl-bindAttribLocation-aliasing-inactive.html]
-fail-if = (os != 'win')
+fail-if = 1
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__attribs__gl-vertex-attrib-i-render.html]
 skip-if = (os == 'win') || (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__attribs__gl-vertex-attrib-normalized-int.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__attribs__gl-vertex-attrib.html]
 skip-if = (os == 'win') || (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__attribs__gl-vertexattribipointer-offsets.html]
@@ -5090,18 +5090,20 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__shader-with-invalid-characters.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__shader-with-mis-matching-uniform-block.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__short-circuiting-in-loop-condition.html]
 skip-if = (os == 'win' && os_version == '6.1') || (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__switch-case.html]
+fail-if = (os == 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__texture-offset-non-constant-offset.html]
+fail-if = (os == 'win')
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__texture-offset-out-of-range.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__texture-offset-uniform-texture-coordinate.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__glsl3__tricky-loop-conditions.html]
 fail-if = (os == 'win')
 skip-if = (os == 'android' || os == 'linux')
@@ -7272,17 +7274,18 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__non-existent-varying.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__simultaneous_binding.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__switching-objects.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__too-small-buffers.html]
-skip-if = 1 || (os == 'android' || os == 'linux')
+fail-if = 1
+skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__transform_feedback.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__two-unreferenced-varyings.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__transform_feedback__unwritten-output-defaults-to-zero.html]
 skip-if = (os == 'android' || os == 'linux')
 [generated/test_2_conformance2__uniforms__dependent-buffer-change.html]
 skip-if = (os == 'android' || os == 'linux')
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -84,22 +84,21 @@ skip-if = (os == 'win')
 skip-if = 1
 [generated/test_2_conformance2__rendering__depth-stencil-feedback-loop.html]
 fail-if = 1
 [generated/test_2_conformance2__rendering__instanced-arrays.html]
 fail-if = 1
 [generated/test_2_conformance2__rendering__read-draw-when-missing-image.html]
 fail-if = 1
 [generated/test_2_conformance2__transform_feedback__too-small-buffers.html]
-# ABORT_ON_ERROR
-skip-if = 1
+fail-if = 1
 [generated/test_2_conformance2__uniforms__incompatible-texture-type-for-sampler.html]
 fail-if = 1
 [generated/test_2_conformance2__attribs__gl-bindAttribLocation-aliasing-inactive.html]
-fail-if = (os != 'win')
+fail-if = 1
 
 [generated/test_conformance__rendering__texture-switch-performance.html]
 # Frequent orange on linux+asan, but likely intermittant:
 # Texture switching significantly hurt performance - achieved 77 frames in 2.016 seconds (0.79 times baseline performance)
 skip-if = 1
 [generated/test_2_conformance__rendering__texture-switch-performance.html]
 # Orange on win10+debug
 # Texture switching significantly hurt performance - achieved 3 frames in 2.164
@@ -1165,16 +1164,20 @@ fail-if = (os == 'win')
 [generated/test_2_conformance__rendering__preservedrawingbuffer-leak.html]
 skip-if = (os == 'win')
 [generated/test_conformance__context__context-size-change.html]
 skip-if = (os == 'win')
 [generated/test_conformance__rendering__preservedrawingbuffer-leak.html]
 skip-if = (os == 'win')
 [generated/test_2_conformance2__glsl3__array-initialize-with-same-name-array.html]
 fail-if = (os == 'win')
+[generated/test_2_conformance2__glsl3__switch-case.html]
+fail-if = (os == 'win')
+[generated/test_2_conformance2__glsl3__texture-offset-non-constant-offset.html]
+fail-if = (os == 'win')
 [generated/test_2_conformance__misc__webgl-specific-stencil-settings.html]
 # [gl:0D6DE000] mozilla::gl::GLContext::raw_fDrawArrays: Generated unexpected GL_INVALID_OPERATION error. (0x0502)
 # ERR: gl::ValidateDrawBase(2519): This ANGLE implementation does not support separate front/back stencil writemasks, reference values, or stencil mask values.
 # Hit MOZ_CRASH(Unexpected error with MOZ_GL_DEBUG_ABORT_ON_ERROR. (Run with MOZ_GL_DEBUG_ABORT_ON_ERROR=0 to disable)) at z:/build/build/src/gfx/gl/GLContext.cpp:3030
 skip-if = (os == 'win')
 [generated/test_conformance__misc__webgl-specific-stencil-settings.html]
 skip-if = (os == 'win')
 [generated/test_conformance__textures__misc__tex-video-using-tex-unit-non-zero.html]
--- a/gfx/angle/checkout/include/EGL/eglext_angle.h
+++ b/gfx/angle/checkout/include/EGL/eglext_angle.h
@@ -170,16 +170,11 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCach
 #define EGL_ANGLE_iosurface_client_buffer 1
 #define EGL_IOSURFACE_ANGLE 0x3454
 #define EGL_IOSURFACE_PLANE_ANGLE 0x345A
 #define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B
 #define EGL_TEXTURE_TYPE_ANGLE 0x345C
 #define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
 #endif /* EGL_ANGLE_iosurface_client_buffer */
 
-#ifndef EGL_ANGLE_create_context_extensions_enabled
-#define EGL_ANGLE_create_context_extensions_enabled 1
-#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
-#endif /* EGL_ANGLE_create_context_extensions_enabled */
-
 // clang-format on
 
 #endif  // INCLUDE_EGL_EGLEXT_ANGLE_
--- a/gfx/angle/checkout/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/checkout/include/GLSLANG/ShaderLang.h
@@ -20,17 +20,17 @@
 // and the shading language compiler.
 //
 
 // Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
 #include "ShaderVars.h"
 
 // Version number for shader translation API.
 // It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 197
+#define ANGLE_SH_VERSION 196
 
 enum ShShaderSpec
 {
     SH_GLES2_SPEC,
     SH_WEBGL_SPEC,
 
     SH_GLES3_SPEC,
     SH_WEBGL2_SPEC,
--- a/gfx/angle/checkout/include/GLSLANG/ShaderVars.h
+++ b/gfx/angle/checkout/include/GLSLANG/ShaderVars.h
@@ -121,22 +121,17 @@ struct ShaderVariable
     // Offset of this variable in parent arrays. In case the parent is an array of arrays, the
     // offset is outerArrayElement * innerArraySize + innerArrayElement.
     // For example, if there's a variable declared as size 3 array of size 4 array of int:
     //   int a[3][4];
     // then the flattenedOffsetInParentArrays of a[2] would be 2.
     // and flattenedOffsetInParentArrays of a[2][1] would be 2*4 + 1 = 9.
     unsigned int flattenedOffsetInParentArrays;
 
-    // Static use means that the variable is accessed somewhere in the shader source.
     bool staticUse;
-    // A variable is active unless the compiler determined that it is not accessed by the shader.
-    // All active variables are statically used, but not all statically used variables are
-    // necessarily active. GLES 3.0.5 section 2.12.6. GLES 3.1 section 7.3.1.
-    bool active;
     std::vector<ShaderVariable> fields;
     std::string structName;
 
   protected:
     bool isSameVariableAtLinkTime(const ShaderVariable &other,
                                   bool matchPrecision,
                                   bool matchName) const;
 
@@ -279,17 +274,16 @@ struct InterfaceBlock
     BlockLayoutType layout;
 
     // Deprecated. Matrix packing should only be queried from individual fields of the block.
     // TODO(oetuaho): Remove this once it is no longer used in Chromium.
     bool isRowMajorLayout;
 
     int binding;
     bool staticUse;
-    bool active;
     BlockType blockType;
     std::vector<InterfaceBlockField> fields;
 };
 
 struct WorkGroupSize
 {
     // Must have a trivial default constructor since it is used in YYSTYPE.
     WorkGroupSize() = default;
--- a/gfx/angle/checkout/include/KHR/khrplatform.h
+++ b/gfx/angle/checkout/include/KHR/khrplatform.h
@@ -1,13 +1,13 @@
 #ifndef __khrplatform_h_
 #define __khrplatform_h_
 
 /*
-** Copyright (c) 2008-2018 The Khronos Group Inc.
+** Copyright (c) 2008-2009 The Khronos Group Inc.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a
 ** copy of this software and/or associated documentation files (the
 ** "Materials"), to deal in the Materials without restriction, including
 ** without limitation the rights to use, copy, modify, merge, publish,
 ** distribute, sublicense, and/or sell copies of the Materials, and to
 ** permit persons to whom the Materials are furnished to do so, subject to
 ** the following conditions:
@@ -21,26 +21,28 @@
 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 */
 
 /* Khronos platform-specific types and definitions.
  *
- * The master copy of khrplatform.h is maintained in the Khronos EGL
- * Registry repository at https://github.com/KhronosGroup/EGL-Registry
- * The last semantic modification to khrplatform.h was at commit ID:
- *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
+ * $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
  *
  * Adopters may modify this file to suit their platform. Adopters are
  * encouraged to submit platform specific modifications to the Khronos
  * group so that they can be included in future versions of this file.
- * Please submit changes by filing pull requests or issues on
- * the EGL Registry repository linked above.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
  *
  *
  * See the Implementer's Guidelines for information about where this file
  * should be located on your system and for more details of its use:
  *    http://www.khronos.org/registry/implementers_guide.pdf
  *
  * This file should be included as
  *        #include <KHR/khrplatform.h>
@@ -95,17 +97,18 @@
  *-------------------------------------------------------------------------
  * This precedes the return type of the function in the function prototype.
  */
 #if defined(_WIN32) && !defined(__SCITECH_SNAP__)
 #   define KHRONOS_APICALL __declspec(dllimport)
 #elif defined (__SYMBIAN32__)
 #   define KHRONOS_APICALL IMPORT_C
 #elif defined(__ANDROID__)
-#   define KHRONOS_APICALL __attribute__((visibility("default")))
+#   include <sys/cdefs.h>
+#   define KHRONOS_APICALL __attribute__((visibility("default"))) __NDK_FPABI__
 #else
 #   define KHRONOS_APICALL
 #endif
 
 /*-------------------------------------------------------------------------
  * Definition of KHRONOS_APIENTRY
  *-------------------------------------------------------------------------
  * This follows the return type of the function  and precedes the function
@@ -274,9 +277,9 @@ typedef khronos_int64_t        khronos_s
  * comparisons should not be made against KHRONOS_TRUE.
  */
 typedef enum {
     KHRONOS_FALSE = 0,
     KHRONOS_TRUE  = 1,
     KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
 } khronos_boolean_enum_t;
 
-#endif /* __khrplatform_h_ */
+#endif /* __khrplatform_h_ */
\ No newline at end of file
--- a/gfx/angle/checkout/out/gen/angle/id/commit.h
+++ b/gfx/angle/checkout/out/gen/angle/id/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "2426b097472f"
+#define ANGLE_COMMIT_HASH "fcbca0e873c3"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2018-05-22 15:14:46 -0700"
+#define ANGLE_COMMIT_DATE "2018-04-20 16:07:35 -0700"
--- a/gfx/angle/checkout/src/common/Color.h
+++ b/gfx/angle/checkout/src/common/Color.h
@@ -10,26 +10,23 @@
 #define COMMON_COLOR_H_
 
 namespace angle
 {
 
 template <typename T>
 struct Color
 {
-    Color();
-    Color(T r, T g, T b, T a);
-
-    const T *data() const { return &red; }
-    T *ptr() { return &red; }
-
     T red;
     T green;
     T blue;
     T alpha;
+
+    Color();
+    Color(T r, T g, T b, T a);
 };
 
 template <typename T>
 bool operator==(const Color<T> &a, const Color<T> &b);
 
 template <typename T>
 bool operator!=(const Color<T> &a, const Color<T> &b);
 
deleted file mode 100644
--- a/gfx/angle/checkout/src/common/FixedVector.h
+++ /dev/null
@@ -1,331 +0,0 @@
-//
-// Copyright 2018 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.
-//
-// FixedVector.h:
-//   A vector class with a maximum size and fixed storage.
-//
-
-#ifndef COMMON_FIXEDVECTOR_H_
-#define COMMON_FIXEDVECTOR_H_
-
-#include "common/debug.h"
-
-#include <algorithm>
-#include <array>
-#include <initializer_list>
-
-namespace angle
-{
-template <class T, size_t N, class Storage = std::array<T, N>>
-class FixedVector final
-{
-  public:
-    using value_type             = typename Storage::value_type;
-    using size_type              = typename Storage::size_type;
-    using reference              = typename Storage::reference;
-    using const_reference        = typename Storage::const_reference;
-    using pointer                = typename Storage::pointer;
-    using const_pointer          = typename Storage::const_pointer;
-    using iterator               = typename Storage::iterator;
-    using const_iterator         = typename Storage::const_iterator;
-    using reverse_iterator       = typename Storage::reverse_iterator;
-    using const_reverse_iterator = typename Storage::const_reverse_iterator;
-
-    FixedVector();
-    FixedVector(size_type count, const value_type &value);
-    FixedVector(size_type count);
-
-    FixedVector(const FixedVector<T, N, Storage> &other);
-    FixedVector(FixedVector<T, N, Storage> &&other);
-    FixedVector(std::initializer_list<value_type> init);
-
-    FixedVector<T, N, Storage> &operator=(const FixedVector<T, N, Storage> &other);
-    FixedVector<T, N, Storage> &operator=(FixedVector<T, N, Storage> &&other);
-    FixedVector<T, N, Storage> &operator=(std::initializer_list<value_type> init);
-
-    ~FixedVector();
-
-    reference at(size_type pos);
-    const_reference at(size_type pos) const;
-
-    reference operator[](size_type pos);
-    const_reference operator[](size_type pos) const;
-
-    pointer data();
-    const_pointer data() const;
-
-    iterator begin();
-    const_iterator begin() const;
-
-    iterator end();
-    const_iterator end() const;
-
-    bool empty() const;
-    size_type size() const;
-    size_type max_size() const;
-
-    void clear();
-
-    void push_back(const value_type &value);
-    void push_back(value_type &&value);
-
-    void pop_back();
-    reference back();
-    const_reference back() const;
-
-    void swap(FixedVector<T, N, Storage> &other);
-
-    void resize(size_type count);
-    void resize(size_type count, const value_type &value);
-
-    bool full() const;
-
-  private:
-    void assign_from_initializer_list(std::initializer_list<value_type> init);
-
-    Storage mStorage;
-    size_type mSize = 0;
-};
-
-template <class T, size_t N, class Storage>
-bool operator==(const FixedVector<T, N, Storage> &a, const FixedVector<T, N, Storage> &b)
-{
-    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
-}
-
-template <class T, size_t N, class Storage>
-bool operator!=(const FixedVector<T, N, Storage> &a, const FixedVector<T, N, Storage> &b)
-{
-    return !(a == b);
-}
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector() = default;
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector(size_type count, const value_type &value) : mSize(count)
-{
-    ASSERT(count <= N);
-    std::fill(mStorage.begin(), mStorage.begin() + count, value);
-}
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector(size_type count) : mSize(count)
-{
-    ASSERT(count <= N);
-}
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector(const FixedVector<T, N, Storage> &other) = default;
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector(FixedVector<T, N, Storage> &&other) = default;
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::FixedVector(std::initializer_list<value_type> init)
-{
-    ASSERT(init.size() <= N);
-    assign_from_initializer_list(init);
-}
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=(
-    const FixedVector<T, N, Storage> &other) = default;
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=(
-    FixedVector<T, N, Storage> &&other) = default;
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage> &FixedVector<T, N, Storage>::operator=(
-    std::initializer_list<value_type> init)
-{
-    clear();
-    ASSERT(init.size() <= N);
-    assign_from_initializer_list(init);
-    return this;
-}
-
-template <class T, size_t N, class Storage>
-FixedVector<T, N, Storage>::~FixedVector()
-{
-    clear();
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::at(size_type pos)
-{
-    ASSERT(pos < N);
-    return mStorage.at(pos);
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::at(
-    size_type pos) const
-{
-    ASSERT(pos < N);
-    return mStorage.at(pos);
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::operator[](size_type pos)
-{
-    ASSERT(pos < N);
-    return mStorage[pos];
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::operator[](
-    size_type pos) const
-{
-    ASSERT(pos < N);
-    return mStorage[pos];
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_pointer angle::FixedVector<T, N, Storage>::data() const
-{
-    return mStorage.data();
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::pointer angle::FixedVector<T, N, Storage>::data()
-{
-    return mStorage.data();
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::iterator FixedVector<T, N, Storage>::begin()
-{
-    return mStorage.begin();
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_iterator FixedVector<T, N, Storage>::begin() const
-{
-    return mStorage.begin();
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::iterator FixedVector<T, N, Storage>::end()
-{
-    return mStorage.begin() + mSize;
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_iterator FixedVector<T, N, Storage>::end() const
-{
-    return mStorage.begin() + mSize;
-}
-
-template <class T, size_t N, class Storage>
-bool FixedVector<T, N, Storage>::empty() const
-{
-    return mSize == 0;
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::size_type FixedVector<T, N, Storage>::size() const
-{
-    return mSize;
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::size_type FixedVector<T, N, Storage>::max_size() const
-{
-    return N;
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::clear()
-{
-    resize(0);
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::push_back(const value_type &value)
-{
-    ASSERT(mSize < N);
-    mStorage[mSize] = value;
-    mSize++;
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::push_back(value_type &&value)
-{
-    ASSERT(mSize < N);
-    mStorage[mSize] = std::move(value);
-    mSize++;
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::pop_back()
-{
-    ASSERT(mSize > 0);
-    mSize--;
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::reference FixedVector<T, N, Storage>::back()
-{
-    ASSERT(mSize > 0);
-    return mStorage[mSize - 1];
-}
-
-template <class T, size_t N, class Storage>
-typename FixedVector<T, N, Storage>::const_reference FixedVector<T, N, Storage>::back() const
-{
-    ASSERT(mSize > 0);
-    return mStorage[mSize - 1];
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::swap(FixedVector<T, N, Storage> &other)
-{
-    std::swap(mSize, other.mSize);
-    std::swap(mStorage, other.mStorage);
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::resize(size_type count)
-{
-    resize(count, value_type());
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::resize(size_type count, const value_type &value)
-{
-    ASSERT(count <= N);
-    while (mSize > count)
-    {
-        mSize--;
-        mStorage[mSize] = T();
-    }
-    while (mSize < count)
-    {
-        mStorage[mSize] = value;
-        mSize++;
-    }
-}
-
-template <class T, size_t N, class Storage>
-void FixedVector<T, N, Storage>::assign_from_initializer_list(
-    std::initializer_list<value_type> init)
-{
-    for (auto element : init)
-    {
-        mStorage[mSize] = std::move(element);
-        mSize++;
-    }
-}
-
-template <class T, size_t N, class Storage>
-bool FixedVector<T, N, Storage>::full() const
-{
-    return (mSize == N);
-}
-}  // namespace angle
-
-#endif  // COMMON_FIXEDVECTOR_H_
--- a/gfx/angle/checkout/src/common/angleutils.h
+++ b/gfx/angle/checkout/src/common/angleutils.h
@@ -186,17 +186,16 @@ std::string ToString(const T &value)
     return o.str();
 }
 
 // snprintf is not defined with MSVC prior to to msvc14
 #if defined(_MSC_VER) && _MSC_VER < 1900
 #define snprintf _snprintf
 #endif
 
-#define GL_A1RGB5_ANGLEX 0x6AC5
 #define GL_BGRX8_ANGLEX 0x6ABA
 #define GL_BGR565_ANGLEX 0x6ABB
 #define GL_BGRA4_ANGLEX 0x6ABC
 #define GL_BGR5_A1_ANGLEX 0x6ABD
 #define GL_INT_64_ANGLEX 0x6ABE
 #define GL_UINT_64_ANGLEX 0x6ABF
 #define GL_BGRA8_SRGB_ANGLEX 0x6AC0
 
--- a/gfx/angle/checkout/src/common/bitset_utils.h
+++ b/gfx/angle/checkout/src/common/bitset_utils.h
@@ -35,20 +35,20 @@ class BitSetT final
             mParent->set(mBit, x);
             return *this;
         }
         explicit operator bool() const { return mParent->test(mBit); }
 
       private:
         friend class BitSetT;
 
-        Reference(BitSetT *parent, ParamT bit) : mParent(parent), mBit(bit) {}
+        Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {}
 
         BitSetT *mParent;
-        ParamT mBit;
+        std::size_t mBit;
     };
 
     class Iterator final
     {
       public:
         Iterator(const BitSetT &bits);
         Iterator &operator++();
 
@@ -59,17 +59,18 @@ class BitSetT final
       private:
         std::size_t getNextBit();
 
         BitSetT mBitsCopy;
         std::size_t mCurrentBit;
     };
 
     BitSetT();
-    constexpr explicit BitSetT(BitsT value);
+    BitSetT(BitsT value);
+    ~BitSetT();
 
     BitSetT(const BitSetT &other);
     BitSetT &operator=(const BitSetT &other);
 
     bool operator==(const BitSetT &other) const;
     bool operator!=(const BitSetT &other) const;
 
     constexpr bool operator[](ParamT pos) const;
@@ -84,20 +85,16 @@ class BitSetT final
 
     constexpr std::size_t size() const { return N; }
 
     BitSetT &operator&=(const BitSetT &other);
     BitSetT &operator|=(const BitSetT &other);
     BitSetT &operator^=(const BitSetT &other);
     BitSetT operator~() const;
 
-    BitSetT &operator&=(BitsT value);
-    BitSetT &operator|=(BitsT value);
-    BitSetT &operator^=(BitsT value);
-
     BitSetT operator<<(std::size_t pos) const;
     BitSetT &operator<<=(std::size_t pos);
     BitSetT operator>>(std::size_t pos) const;
     BitSetT &operator>>=(std::size_t pos);
 
     BitSetT &set();
     BitSetT &set(ParamT pos, bool value = true);
 
@@ -113,21 +110,17 @@ class BitSetT final
     Iterator begin() const { return Iterator(*this); }
     Iterator end() const { return Iterator(BitSetT()); }
 
   private:
     constexpr static BitsT Bit(ParamT x)
     {
         return (static_cast<BitsT>(1) << static_cast<size_t>(x));
     }
-    // Produces a mask of ones up to the "x"th bit.
-    constexpr static BitsT Mask(std::size_t x)
-    {
-        return ((Bit(static_cast<ParamT>(x - 1)) - 1) << 1) + 1;
-    }
+    constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
 
     BitsT mBits;
 };
 
 template <size_t N>
 class IterableBitSet : public std::bitset<N>
 {
   public:
@@ -215,17 +208,22 @@ unsigned long IterableBitSet<N>::Iterato
 template <size_t N, typename BitsT, typename ParamT>
 BitSetT<N, BitsT, ParamT>::BitSetT() : mBits(0)
 {
     static_assert(N > 0, "Bitset type cannot support zero bits.");
     static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
 }
 
 template <size_t N, typename BitsT, typename ParamT>
-constexpr BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
+BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
+{
+}
+
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::~BitSetT()
 {
 }
 
 template <size_t N, typename BitsT, typename ParamT>
 BitSetT<N, BitsT, ParamT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
 {
 }
 
@@ -310,37 +308,16 @@ BitSetT<N, BitsT, ParamT> &BitSetT<N, Bi
 
 template <size_t N, typename BitsT, typename ParamT>
 BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator~() const
 {
     return BitSetT<N, BitsT, ParamT>(~mBits & Mask(N));
 }
 
 template <size_t N, typename BitsT, typename ParamT>
-BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(BitsT value)
-{
-    mBits &= value;
-    return *this;
-}
-
-template <size_t N, typename BitsT, typename ParamT>
-BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(BitsT value)
-{
-    mBits |= value;
-    return *this;
-}
-
-template <size_t N, typename BitsT, typename ParamT>
-BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(BitsT value)
-{
-    mBits ^= value;
-    return *this;
-}
-
-template <size_t N, typename BitsT, typename ParamT>
 BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator<<(std::size_t pos) const
 {
     return BitSetT<N, BitsT, ParamT>((mBits << pos) & Mask(N));
 }
 
 template <size_t N, typename BitsT, typename ParamT>
 BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator<<=(std::size_t pos)
 {
--- a/gfx/angle/checkout/src/common/mathutil.h
+++ b/gfx/angle/checkout/src/common/mathutil.h
@@ -4,59 +4,57 @@
 // found in the LICENSE file.
 //
 
 // mathutil.h: Math and bit manipulation functions.
 
 #ifndef COMMON_MATHUTIL_H_
 #define COMMON_MATHUTIL_H_
 
+#include <limits>
+#include <algorithm>
 #include <math.h>
+#include <string.h>
 #include <stdint.h>
 #include <stdlib.h>
-#include <string.h>
-#include <algorithm>
-#include <limits>
 
 #include <anglebase/numerics/safe_math.h>
 
 #include "common/debug.h"
 #include "common/platform.h"
 
 namespace angle
 {
 using base::CheckedNumeric;
 using base::IsValueInRangeForNumericType;
 }
 
 namespace gl
 {
 
-const unsigned int Float32One   = 0x3F800000;
+const unsigned int Float32One = 0x3F800000;
 const unsigned short Float16One = 0x3C00;
 
-template <typename T>
+template<typename T>
 inline bool isPow2(T x)
 {
     static_assert(std::is_integral<T>::value, "isPow2 must be called on an integer type.");
     return (x & (x - 1)) == 0 && (x != 0);
 }
 
 inline int log2(int x)
 {
     int r = 0;
-    while ((x >> r) > 1)
-        r++;
+    while ((x >> r) > 1) r++;
     return r;
 }
 
 inline unsigned int ceilPow2(unsigned int x)
 {
-    if (x != 0)
-        x--;
+    if (x != 0) x--;
     x |= x >> 1;
     x |= x >> 2;
     x |= x >> 4;
     x |= x >> 8;
     x |= x >> 16;
     x++;
 
     return x;
@@ -105,29 +103,29 @@ inline unsigned int clampCast(bool value
 }
 
 template <>
 inline int clampCast(bool value)
 {
     return static_cast<int>(value);
 }
 
-template <typename T, typename MIN, typename MAX>
+template<typename T, typename MIN, typename MAX>
 inline T clamp(T x, MIN min, MAX max)
 {
     // Since NaNs fail all comparison tests, a NaN value will default to min
     return x > min ? (x > max ? max : x) : min;
 }
 
 inline float clamp01(float x)
 {
     return clamp(x, 0.0f, 1.0f);
 }
 
-template <const int n>
+template<const int n>
 inline unsigned int unorm(float x)
 {
     const unsigned int max = 0xFFFFFFFF >> (32 - n);
 
     if (x > 1)
     {
         return max;
     }
@@ -139,17 +137,17 @@ inline unsigned int unorm(float x)
     {
         return (unsigned int)(max * x + 0.5f);
     }
 }
 
 inline bool supportsSSE2()
 {
 #if defined(ANGLE_USE_SSE)
-    static bool checked  = false;
+    static bool checked = false;
     static bool supports = false;
 
     if (checked)
     {
         return supports;
     }
 
 #if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM)
@@ -179,82 +177,79 @@ destType bitCast(const sourceType &sourc
     destType output;
     memcpy(&output, &source, copySize);
     return output;
 }
 
 inline unsigned short float32ToFloat16(float fp32)
 {
     unsigned int fp32i = bitCast<unsigned int>(fp32);
-    unsigned int sign  = (fp32i & 0x80000000) >> 16;
-    unsigned int abs   = fp32i & 0x7FFFFFFF;
+    unsigned int sign = (fp32i & 0x80000000) >> 16;
+    unsigned int abs = fp32i & 0x7FFFFFFF;
 
-    if (abs > 0x47FFEFFF)  // Infinity
+    if(abs > 0x47FFEFFF)   // Infinity
     {
         return static_cast<unsigned short>(sign | 0x7FFF);
     }
-    else if (abs < 0x38800000)  // Denormal
+    else if(abs < 0x38800000)   // Denormal
     {
         unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000;
-        int e                 = 113 - (abs >> 23);
+        int e = 113 - (abs >> 23);
 
-        if (e < 24)
+        if(e < 24)
         {
             abs = mantissa >> e;
         }
         else
         {
             abs = 0;
         }
 
         return static_cast<unsigned short>(sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
     }
     else
     {
-        return static_cast<unsigned short>(
-            sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+        return static_cast<unsigned short>(sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
     }
 }
 
 float float16ToFloat32(unsigned short h);
 
 unsigned int convertRGBFloatsTo999E5(float red, float green, float blue);
 void convert999E5toRGBFloats(unsigned int input, float *red, float *green, float *blue);
 
 inline unsigned short float32ToFloat11(float fp32)
 {
-    const unsigned int float32MantissaMask     = 0x7FFFFF;
-    const unsigned int float32ExponentMask     = 0x7F800000;
-    const unsigned int float32SignMask         = 0x80000000;
-    const unsigned int float32ValueMask        = ~float32SignMask;
+    const unsigned int float32MantissaMask = 0x7FFFFF;
+    const unsigned int float32ExponentMask = 0x7F800000;
+    const unsigned int float32SignMask = 0x80000000;
+    const unsigned int float32ValueMask = ~float32SignMask;
     const unsigned int float32ExponentFirstBit = 23;
-    const unsigned int float32ExponentBias     = 127;
+    const unsigned int float32ExponentBias = 127;
 
-    const unsigned short float11Max          = 0x7BF;
+    const unsigned short float11Max = 0x7BF;
     const unsigned short float11MantissaMask = 0x3F;
     const unsigned short float11ExponentMask = 0x7C0;
-    const unsigned short float11BitMask      = 0x7FF;
-    const unsigned int float11ExponentBias   = 14;
+    const unsigned short float11BitMask = 0x7FF;
+    const unsigned int float11ExponentBias = 14;
 
     const unsigned int float32Maxfloat11 = 0x477E0000;
     const unsigned int float32Minfloat11 = 0x38800000;
 
     const unsigned int float32Bits = bitCast<unsigned int>(fp32);
-    const bool float32Sign         = (float32Bits & float32SignMask) == float32SignMask;
+    const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask;
 
     unsigned int float32Val = float32Bits & float32ValueMask;
 
     if ((float32Val & float32ExponentMask) == float32ExponentMask)
     {
         // INF or NAN
         if ((float32Val & float32MantissaMask) != 0)
         {
-            return float11ExponentMask |
-                   (((float32Val >> 17) | (float32Val >> 11) | (float32Val >> 6) | (float32Val)) &
-                    float11MantissaMask);
+            return float11ExponentMask | (((float32Val >> 17) | (float32Val >> 11) | (float32Val >> 6) | (float32Val)) & float11MantissaMask);
         }
         else if (float32Sign)
         {
             // -INF is clamped to 0 since float11 is positive only
             return 0;
         }
         else
         {
@@ -272,62 +267,58 @@ inline unsigned short float32ToFloat11(f
         return float11Max;
     }
     else
     {
         if (float32Val < float32Minfloat11)
         {
             // The number is too small to be represented as a normalized float11
             // Convert it to a denormalized value.
-            const unsigned int shift = (float32ExponentBias - float11ExponentBias) -
-                                       (float32Val >> float32ExponentFirstBit);
-            float32Val =
-                ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;
+            const unsigned int shift = (float32ExponentBias - float11ExponentBias) - (float32Val >> float32ExponentFirstBit);
+            float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;
         }
         else
         {
             // Rebias the exponent to represent the value as a normalized float11
             float32Val += 0xC8000000;
         }
 
         return ((float32Val + 0xFFFF + ((float32Val >> 17) & 1)) >> 17) & float11BitMask;
     }
 }
 
 inline unsigned short float32ToFloat10(float fp32)
 {
-    const unsigned int float32MantissaMask     = 0x7FFFFF;
-    const unsigned int float32ExponentMask     = 0x7F800000;
-    const unsigned int float32SignMask         = 0x80000000;
-    const unsigned int float32ValueMask        = ~float32SignMask;
+    const unsigned int float32MantissaMask = 0x7FFFFF;
+    const unsigned int float32ExponentMask = 0x7F800000;
+    const unsigned int float32SignMask = 0x80000000;
+    const unsigned int float32ValueMask = ~float32SignMask;
     const unsigned int float32ExponentFirstBit = 23;
-    const unsigned int float32ExponentBias     = 127;
+    const unsigned int float32ExponentBias = 127;
 
-    const unsigned short float10Max          = 0x3DF;
+    const unsigned short float10Max = 0x3DF;
     const unsigned short float10MantissaMask = 0x1F;
     const unsigned short float10ExponentMask = 0x3E0;
-    const unsigned short float10BitMask      = 0x3FF;
-    const unsigned int float10ExponentBias   = 14;
+    const unsigned short float10BitMask = 0x3FF;
+    const unsigned int float10ExponentBias = 14;
 
     const unsigned int float32Maxfloat10 = 0x477C0000;
     const unsigned int float32Minfloat10 = 0x38800000;
 
     const unsigned int float32Bits = bitCast<unsigned int>(fp32);
-    const bool float32Sign         = (float32Bits & float32SignMask) == float32SignMask;
+    const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask;
 
     unsigned int float32Val = float32Bits & float32ValueMask;
 
     if ((float32Val & float32ExponentMask) == float32ExponentMask)
     {
         // INF or NAN
         if ((float32Val & float32MantissaMask) != 0)
         {
-            return float10ExponentMask |
-                   (((float32Val >> 18) | (float32Val >> 13) | (float32Val >> 3) | (float32Val)) &
-                    float10MantissaMask);
+            return float10ExponentMask | (((float32Val >> 18) | (float32Val >> 13) | (float32Val >> 3) | (float32Val)) & float10MantissaMask);
         }
         else if (float32Sign)
         {
             // -INF is clamped to 0 since float11 is positive only
             return 0;
         }
         else
         {
@@ -345,20 +336,18 @@ inline unsigned short float32ToFloat10(f
         return float10Max;
     }
     else
     {
         if (float32Val < float32Minfloat10)
         {
             // The number is too small to be represented as a normalized float11
             // Convert it to a denormalized value.
-            const unsigned int shift = (float32ExponentBias - float10ExponentBias) -
-                                       (float32Val >> float32ExponentFirstBit);
-            float32Val =
-                ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;
+            const unsigned int shift = (float32ExponentBias - float10ExponentBias) - (float32Val >> float32ExponentFirstBit);
+            float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;
         }
         else
         {
             // Rebias the exponent to represent the value as a normalized float11
             float32Val += 0xC8000000;
         }
 
         return ((float32Val + 0x1FFFF + ((float32Val >> 18) & 1)) >> 18) & float10BitMask;
@@ -385,21 +374,22 @@ inline float float11ToFloat32(unsigned s
         {
             // The value is denormalized
             exponent = 1;
 
             do
             {
                 exponent--;
                 mantissa <<= 1;
-            } while ((mantissa & 0x40) == 0);
+            }
+            while ((mantissa & 0x40) == 0);
 
             mantissa = mantissa & 0x3F;
         }
-        else  // The value is zero
+        else // The value is zero
         {
             exponent = static_cast<unsigned short>(-112);
         }
 
         return bitCast<float>(((exponent + 112) << 23) | (mantissa << 17));
     }
 }
 
@@ -423,55 +413,30 @@ inline float float10ToFloat32(unsigned s
         {
             // The value is denormalized
             exponent = 1;
 
             do
             {
                 exponent--;
                 mantissa <<= 1;
-            } while ((mantissa & 0x20) == 0);
+            }
+            while ((mantissa & 0x20) == 0);
 
             mantissa = mantissa & 0x1F;
         }
-        else  // The value is zero
+        else // The value is zero
         {
             exponent = static_cast<unsigned short>(-112);
         }
 
         return bitCast<float>(((exponent + 112) << 23) | (mantissa << 18));
     }
 }
 
-// Convers to and from float and 16.16 fixed point format.
-
-inline float FixedToFloat(uint32_t fixedInput)
-{
-    return static_cast<float>(fixedInput) / 65536.0f;
-}
-
-inline uint32_t FloatToFixed(float floatInput)
-{
-    static constexpr uint32_t kHighest = 32767 * 65536 + 65535;
-    static constexpr uint32_t kLowest  = static_cast<uint32_t>(-32768 * 65536 + 65535);
-
-    if (floatInput > 32767.65535)
-    {
-        return kHighest;
-    }
-    else if (floatInput < -32768.65535)
-    {
-        return kLowest;
-    }
-    else
-    {
-        return static_cast<uint32_t>(floatInput * 65536);
-    }
-}
-
 template <typename T>
 inline float normalizedToFloat(T input)
 {
     static_assert(std::numeric_limits<T>::is_integer, "T must be an integer.");
 
     const float inverseMax = 1.0f / std::numeric_limits<T>::max();
     return input * inverseMax;
 }
@@ -593,26 +558,22 @@ inline float average(float a, float b)
 
 inline unsigned short averageHalfFloat(unsigned short a, unsigned short b)
 {
     return float32ToFloat16((float16ToFloat32(a) + float16ToFloat32(b)) * 0.5f);
 }
 
 inline unsigned int averageFloat11(unsigned int a, unsigned int b)
 {
-    return float32ToFloat11((float11ToFloat32(static_cast<unsigned short>(a)) +
-                             float11ToFloat32(static_cast<unsigned short>(b))) *
-                            0.5f);
+    return float32ToFloat11((float11ToFloat32(static_cast<unsigned short>(a)) + float11ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
 }
 
 inline unsigned int averageFloat10(unsigned int a, unsigned int b)
 {
-    return float32ToFloat10((float10ToFloat32(static_cast<unsigned short>(a)) +
-                             float10ToFloat32(static_cast<unsigned short>(b))) *
-                            0.5f);
+    return float32ToFloat10((float10ToFloat32(static_cast<unsigned short>(a)) + float10ToFloat32(static_cast<unsigned short>(b))) * 0.5f);
 }
 
 template <typename T>
 class Range
 {
   public:
     Range() {}
     Range(T lo, T hi) : mLow(lo), mHigh(hi) {}
@@ -721,60 +682,60 @@ inline float Ldexp(float x, int exp)
 // Then, the results are packed into the returned 32-bit unsigned integer.
 // The first float value will be written to the least significant bits of the output;
 // the last float value will be written to the most significant bits.
 // The conversion of each value to fixed point is done as follows :
 // packSnorm2x16 : round(clamp(c, -1, +1) * 32767.0)
 inline uint32_t packSnorm2x16(float f1, float f2)
 {
     int16_t leastSignificantBits = static_cast<int16_t>(roundf(clamp(f1, -1.0f, 1.0f) * 32767.0f));
-    int16_t mostSignificantBits  = static_cast<int16_t>(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f));
+    int16_t mostSignificantBits = static_cast<int16_t>(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f));
     return static_cast<uint32_t>(mostSignificantBits) << 16 |
            (static_cast<uint32_t>(leastSignificantBits) & 0xFFFF);
 }
 
-// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then,
-// each component is converted to a normalized floating-point value to generate the returned two
-// float values. The first float value will be extracted from the least significant bits of the
-// input; the last float value will be extracted from the most-significant bits. The conversion for
-// unpacked fixed-point value to floating point is done as follows: unpackSnorm2x16 : clamp(f /
-// 32767.0, -1, +1)
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackSnorm2x16 : clamp(f / 32767.0, -1, +1)
 inline void unpackSnorm2x16(uint32_t u, float *f1, float *f2)
 {
     int16_t leastSignificantBits = static_cast<int16_t>(u & 0xFFFF);
-    int16_t mostSignificantBits  = static_cast<int16_t>(u >> 16);
+    int16_t mostSignificantBits = static_cast<int16_t>(u >> 16);
     *f1 = clamp(static_cast<float>(leastSignificantBits) / 32767.0f, -1.0f, 1.0f);
     *f2 = clamp(static_cast<float>(mostSignificantBits) / 32767.0f, -1.0f, 1.0f);
 }
 
 // First, both normalized floating-point values are converted into 16-bit integer values.
 // Then, the results are packed into the returned 32-bit unsigned integer.
 // The first float value will be written to the least significant bits of the output;
 // the last float value will be written to the most significant bits.
 // The conversion of each value to fixed point is done as follows:
 // packUnorm2x16 : round(clamp(c, 0, +1) * 65535.0)
 inline uint32_t packUnorm2x16(float f1, float f2)
 {
     uint16_t leastSignificantBits = static_cast<uint16_t>(roundf(clamp(f1, 0.0f, 1.0f) * 65535.0f));
-    uint16_t mostSignificantBits  = static_cast<uint16_t>(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f));
-    return static_cast<uint32_t>(mostSignificantBits) << 16 |
-           static_cast<uint32_t>(leastSignificantBits);
+    uint16_t mostSignificantBits = static_cast<uint16_t>(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f));
+    return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
 }
 
-// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then,
-// each component is converted to a normalized floating-point value to generate the returned two
-// float values. The first float value will be extracted from the least significant bits of the
-// input; the last float value will be extracted from the most-significant bits. The conversion for
-// unpacked fixed-point value to floating point is done as follows: unpackUnorm2x16 : f / 65535.0
+// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each
+// component is converted to a normalized floating-point value to generate the returned two float values.
+// The first float value will be extracted from the least significant bits of the input;
+// the last float value will be extracted from the most-significant bits.
+// The conversion for unpacked fixed-point value to floating point is done as follows:
+// unpackUnorm2x16 : f / 65535.0
 inline void unpackUnorm2x16(uint32_t u, float *f1, float *f2)
 {
     uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
-    uint16_t mostSignificantBits  = static_cast<uint16_t>(u >> 16);
-    *f1                           = static_cast<float>(leastSignificantBits) / 65535.0f;
-    *f2                           = static_cast<float>(mostSignificantBits) / 65535.0f;
+    uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
+    *f1 = static_cast<float>(leastSignificantBits) / 65535.0f;
+    *f2 = static_cast<float>(mostSignificantBits) / 65535.0f;
 }
 
 // Helper functions intended to be used only here.
 namespace priv
 {
 
 inline uint8_t ToPackedUnorm8(float f)
 {
@@ -855,30 +816,29 @@ inline void UnpackSnorm4x8(uint32_t u, f
 // Returns an unsigned integer obtained by converting the two floating-point values to the 16-bit
 // floating-point representation found in the OpenGL ES Specification, and then packing these
 // two 16-bit integers into a 32-bit unsigned integer.
 // f1: The 16 least-significant bits of the result;
 // f2: The 16 most-significant bits.
 inline uint32_t packHalf2x16(float f1, float f2)
 {
     uint16_t leastSignificantBits = static_cast<uint16_t>(float32ToFloat16(f1));
-    uint16_t mostSignificantBits  = static_cast<uint16_t>(float32ToFloat16(f2));
-    return static_cast<uint32_t>(mostSignificantBits) << 16 |
-           static_cast<uint32_t>(leastSignificantBits);
+    uint16_t mostSignificantBits = static_cast<uint16_t>(float32ToFloat16(f2));
+    return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits);
 }
 
-// Returns two floating-point values obtained by unpacking a 32-bit unsigned integer into a pair of
-// 16-bit values, interpreting those values as 16-bit floating-point numbers according to the OpenGL
-// ES Specification, and converting them to 32-bit floating-point values. The first float value is
-// obtained from the 16 least-significant bits of u; the second component is obtained from the 16
-// most-significant bits of u.
+// Returns two floating-point values obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values,
+// interpreting those values as 16-bit floating-point numbers according to the OpenGL ES Specification,
+// and converting them to 32-bit floating-point values.
+// The first float value is obtained from the 16 least-significant bits of u;
+// the second component is obtained from the 16 most-significant bits of u.
 inline void unpackHalf2x16(uint32_t u, float *f1, float *f2)
 {
     uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF);
-    uint16_t mostSignificantBits  = static_cast<uint16_t>(u >> 16);
+    uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16);
 
     *f1 = float16ToFloat32(leastSignificantBits);
     *f2 = float16ToFloat32(mostSignificantBits);
 }
 
 inline uint8_t sRGBToLinear(uint8_t srgbValue)
 {
     float value = srgbValue / 255.0f;
@@ -1039,35 +999,31 @@ int FindMSB(T bits)
     }
     else
     {
         return static_cast<int>(ScanReverse(bits));
     }
 }
 
 // Returns whether the argument is Not a Number.
-// IEEE 754 single precision NaN representation: Exponent(8 bits) - 255, Mantissa(23 bits) -
-// non-zero.
+// IEEE 754 single precision NaN representation: Exponent(8 bits) - 255, Mantissa(23 bits) - non-zero.
 inline bool isNaN(float f)
 {
     // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
     // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
-    return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) &&
-           (bitCast<uint32_t>(f) & 0x7fffffu);
+    return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && (bitCast<uint32_t>(f) & 0x7fffffu);
 }
 
 // Returns whether the argument is infinity.
-// IEEE 754 single precision infinity representation: Exponent(8 bits) - 255, Mantissa(23 bits) -
-// zero.
+// IEEE 754 single precision infinity representation: Exponent(8 bits) - 255, Mantissa(23 bits) - zero.
 inline bool isInf(float f)
 {
     // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u
     // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu
-    return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) &&
-           !(bitCast<uint32_t>(f) & 0x7fffffu);
+    return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast<uint32_t>(f) & 0x7fffffu);
 }
 
 namespace priv
 {
 template <unsigned int N, unsigned int R>
 struct iSquareRoot
 {
     static constexpr unsigned int solve()
@@ -1156,30 +1112,31 @@ angle::CheckedNumeric<T> CheckedRoundUp(
 inline unsigned int UnsignedCeilDivide(unsigned int value, unsigned int divisor)
 {
     unsigned int divided = value / divisor;
     return (divided + ((value % divisor == 0) ? 0 : 1));
 }
 
 #if defined(_MSC_VER)
 
-#define ANGLE_ROTL(x, y) _rotl(x, y)
-#define ANGLE_ROTR16(x, y) _rotr16(x, y)
+#define ANGLE_ROTL(x,y) _rotl(x,y)
+#define ANGLE_ROTR16(x,y) _rotr16(x,y)
 
 #else
 
 inline uint32_t RotL(uint32_t x, int8_t r)
 {
     return (x << r) | (x >> (32 - r));
 }
 
 inline uint16_t RotR16(uint16_t x, int8_t r)
 {
     return (x >> r) | (x << (16 - r));
 }
 
 #define ANGLE_ROTL(x, y) ::rx::RotL(x, y)
 #define ANGLE_ROTR16(x, y) ::rx::RotR16(x, y)
 
-#endif  // namespace rx
+#endif // namespace rx
+
 }
 
-#endif  // COMMON_MATHUTIL_H_
+#endif   // COMMON_MATHUTIL_H_
--- a/gfx/angle/checkout/src/common/matrix_utils.h
+++ b/gfx/angle/checkout/src/common/matrix_utils.h
@@ -89,38 +89,16 @@ class Matrix
     {
         ASSERT(columns() == m.rows());
         Matrix<T> res  = (*this) * m;
         size_t numElts = res.elements().size();
         mElements.resize(numElts);
         memcpy(mElements.data(), res.data(), numElts * sizeof(float));
     }
 
-    bool operator==(const Matrix<T> &m) const
-    {
-        ASSERT(columns() == m.columns());
-        ASSERT(rows() == m.rows());
-        return mElements == m.elements();
-    }
-
-    bool operator!=(const Matrix<T> &m) const { return !(mElements == m.elements()); }
-
-    bool nearlyEqual(T epsilon, const Matrix<T> &m) const
-    {
-        ASSERT(columns() == m.columns());
-        ASSERT(rows() == m.rows());
-        const auto &otherElts = m.elements();
-        for (size_t i = 0; i < otherElts.size(); i++)
-        {
-            if ((mElements[i] - otherElts[i] > epsilon) && (otherElts[i] - mElements[i] > epsilon))
-                return false;
-        }
-        return true;
-    }
-
     unsigned int size() const
     {
         ASSERT(rows() == columns());
         return rows();
     }
 
     unsigned int rows() const { return mRows; }
 
--- a/gfx/angle/checkout/src/common/utilities.cpp
+++ b/gfx/angle/checkout/src/common/utilities.cpp
@@ -432,16 +432,60 @@ bool IsAtomicCounterType(GLenum type)
 }
 
 bool IsOpaqueType(GLenum type)
 {
     // ESSL 3.10 section 4.1.7 defines opaque types as: samplers, images and atomic counters.
     return IsImageType(type) || IsSamplerType(type) || IsAtomicCounterType(type);
 }
 
+GLenum SamplerTypeToTextureType(GLenum samplerType)
+{
+    switch (samplerType)
+    {
+      case GL_SAMPLER_2D:
+      case GL_INT_SAMPLER_2D:
+      case GL_UNSIGNED_INT_SAMPLER_2D:
+      case GL_SAMPLER_2D_SHADOW:
+        return GL_TEXTURE_2D;
+
+      case GL_SAMPLER_EXTERNAL_OES:
+          return GL_TEXTURE_EXTERNAL_OES;
+
+      case GL_SAMPLER_CUBE:
+      case GL_INT_SAMPLER_CUBE:
+      case GL_UNSIGNED_INT_SAMPLER_CUBE:
+      case GL_SAMPLER_CUBE_SHADOW:
+        return GL_TEXTURE_CUBE_MAP;
+
+      case GL_SAMPLER_2D_ARRAY:
+      case GL_INT_SAMPLER_2D_ARRAY:
+      case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+      case GL_SAMPLER_2D_ARRAY_SHADOW:
+        return GL_TEXTURE_2D_ARRAY;
+
+      case GL_SAMPLER_3D:
+      case GL_INT_SAMPLER_3D:
+      case GL_UNSIGNED_INT_SAMPLER_3D:
+        return GL_TEXTURE_3D;
+
+      case GL_SAMPLER_2D_MULTISAMPLE:
+      case GL_INT_SAMPLER_2D_MULTISAMPLE:
+      case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+          return GL_TEXTURE_2D_MULTISAMPLE;
+
+      case GL_SAMPLER_2D_RECT_ANGLE:
+          return GL_TEXTURE_RECTANGLE_ANGLE;
+
+      default:
+        UNREACHABLE();
+        return 0;
+    }
+}
+
 bool IsMatrixType(GLenum type)
 {
     return VariableRowCount(type) > 1;
 }
 
 GLenum TransposeMatrixType(GLenum type)
 {
     if (!IsMatrixType(type))
@@ -496,16 +540,39 @@ int AllocateFirstFreeBits(unsigned int *
         }
 
         mask <<= 1;
     }
 
     return -1;
 }
 
+static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1, "Unexpected GL cube map enum value.");
+static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2, "Unexpected GL cube map enum value.");
+static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3, "Unexpected GL cube map enum value.");
+static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4, "Unexpected GL cube map enum value.");
+static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5, "Unexpected GL cube map enum value.");
+
+bool IsCubeMapTextureTarget(GLenum target)
+{
+    return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget);
+}
+
+size_t CubeMapTextureTargetToLayerIndex(GLenum target)
+{
+    ASSERT(IsCubeMapTextureTarget(target));
+    return target - static_cast<size_t>(FirstCubeMapTextureTarget);
+}
+
+GLenum LayerIndexToCubeMapTextureTarget(size_t index)
+{
+    ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget));
+    return FirstCubeMapTextureTarget + static_cast<GLenum>(index);
+}
+
 IndexRange ComputeIndexRange(GLenum indexType,
                              const GLvoid *indices,
                              size_t count,
                              bool primitiveRestartEnabled)
 {
     switch (indexType)
     {
         case GL_UNSIGNED_BYTE:
@@ -924,16 +991,62 @@ const char *GetGenericErrorMessage(EGLin
             return "Unknown error.";
     }
 }
 
 }  // namespace egl
 
 namespace egl_gl
 {
+GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget)
+{
+    ASSERT(egl::IsCubeMapTextureTarget(eglTarget));
+    return gl::LayerIndexToCubeMapTextureTarget(egl::CubeMapTextureTargetToLayerIndex(eglTarget));
+}
+
+GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget)
+{
+    switch (eglTarget)
+    {
+        case EGL_GL_TEXTURE_2D_KHR:
+            return GL_TEXTURE_2D;
+
+        case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
+        case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
+        case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
+        case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
+        case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
+        case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
+            return EGLCubeMapTargetToGLCubeMapTarget(eglTarget);
+
+        case EGL_GL_TEXTURE_3D_KHR:
+            return GL_TEXTURE_3D;
+
+        default:
+            UNREACHABLE();
+            return GL_NONE;
+    }
+}
+
+GLenum EGLTextureTargetToGLTextureTarget(EGLenum eglTarget)
+{
+    switch (eglTarget)
+    {
+        case EGL_TEXTURE_2D:
+            return GL_TEXTURE_2D;
+
+        case EGL_TEXTURE_RECTANGLE_ANGLE:
+            return GL_TEXTURE_RECTANGLE_ANGLE;
+
+        default:
+            UNREACHABLE();
+            return GL_NONE;
+    }
+}
+
 GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer)
 {
     return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer));
 }
 }  // namespace egl_gl
 
 namespace gl_egl
 {
--- a/gfx/angle/checkout/src/common/utilities.h
+++ b/gfx/angle/checkout/src/common/utilities.h
@@ -33,26 +33,33 @@ size_t VariableComponentSize(GLenum type
 size_t VariableInternalSize(GLenum type);
 size_t VariableExternalSize(GLenum type);
 int VariableRowCount(GLenum type);
 int VariableColumnCount(GLenum type);
 bool IsSamplerType(GLenum type);
 bool IsImageType(GLenum type);
 bool IsAtomicCounterType(GLenum type);
 bool IsOpaqueType(GLenum type);
+GLenum SamplerTypeToTextureType(GLenum samplerType);
 bool IsMatrixType(GLenum type);
 GLenum TransposeMatrixType(GLenum type);
 int VariableRegisterCount(GLenum type);
 int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix);
 int MatrixComponentCount(GLenum type, bool isRowMajorMatrix);
 int VariableSortOrder(GLenum type);
 GLenum VariableBoolVectorType(GLenum type);
 
 int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
 
+static const GLenum FirstCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+static const GLenum LastCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+bool IsCubeMapTextureTarget(GLenum target);
+size_t CubeMapTextureTargetToLayerIndex(GLenum target);
+GLenum LayerIndexToCubeMapTextureTarget(size_t index);
+
 // Parse the base resource name and array indices. Returns the base name of the resource.
 // If the provided name doesn't index an array, the outSubscripts vector will be empty.
 // If the provided name indexes an array, the outSubscripts vector will contain indices with
 // outermost array indices in the back. If an array index is invalid, GL_INVALID_INDEX is added to
 // outSubscripts.
 std::string ParseResourceName(const std::string &name, std::vector<unsigned int> *outSubscripts);
 
 // Find the child field which matches 'fullName' == var.name + "." + field.name.
@@ -149,16 +156,19 @@ EGLenum LayerIndexToCubeMapTextureTarget
 bool IsTextureTarget(EGLenum target);
 bool IsRenderbufferTarget(EGLenum target);
 
 const char *GetGenericErrorMessage(EGLint error);
 }  // namespace egl
 
 namespace egl_gl
 {
+GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget);
+GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget);
+GLenum EGLTextureTargetToGLTextureTarget(EGLenum eglTarget);
 GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer);
 }
 
 namespace gl_egl
 {
 EGLenum GLComponentTypeToEGLColorComponentType(GLenum glComponentType);
 }  // namespace gl_egl
 
--- a/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.cpp
+++ b/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.cpp
@@ -932,17 +932,16 @@ typedef pp::SourceLocation YYLTYPE;
 #define YY_USER_INIT                   \
     do {                               \
         yyfileno = 0;                  \
         yylineno = 1;                  \
         yyextra->leadingSpace = false; \
         yyextra->lineStart = true;     \
     } while(0);
 
-#define YY_NO_INPUT
 #define YY_USER_ACTION                                              \
     do                                                              \
     {                                                               \
         pp::Input* input = &yyextra->input;                         \
         pp::Input::Location* scanLoc = &yyextra->scanLoc;           \
         while ((scanLoc->sIndex < input->count()) &&                \
                (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
         {                                                           \
--- a/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.l
+++ b/gfx/angle/checkout/src/compiler/preprocessor/Tokenizer.l
@@ -59,17 +59,16 @@ typedef pp::SourceLocation YYLTYPE;
 #define YY_USER_INIT                   \
     do {                               \
         yyfileno = 0;                  \
         yylineno = 1;                  \
         yyextra->leadingSpace = false; \
         yyextra->lineStart = true;     \
     } while(0);
 
-#define YY_NO_INPUT
 #define YY_USER_ACTION                                              \
     do                                                              \
     {                                                               \
         pp::Input* input = &yyextra->input;                         \
         pp::Input::Location* scanLoc = &yyextra->scanLoc;           \
         while ((scanLoc->sIndex < input->count()) &&                \
                (scanLoc->cIndex >= input->length(scanLoc->sIndex))) \
         {                                                           \
--- a/gfx/angle/checkout/src/compiler/preprocessor/numeric_lex.h
+++ b/gfx/angle/checkout/src/compiler/preprocessor/numeric_lex.h
@@ -43,17 +43,30 @@ bool numeric_lex_int(const std::string &
 
     stream >> (*value);
     return !stream.fail();
 }
 
 template <typename FloatType>
 bool numeric_lex_float(const std::string &str, FloatType *value)
 {
-    // Some platforms have issues with the usage of std::locale and std::stringstream and cause
-    // crashes. Usage of strtod appears to be safe.
-    *value = static_cast<FloatType>(strtod(str.c_str(), nullptr));
-    return errno != ERANGE && std::isfinite(*value);
+// On 64-bit Intel Android, istringstream is broken.  Until this is fixed in
+// a newer NDK, don't use it.  Android doesn't have locale support, so this
+// doesn't have to force the C locale.
+// TODO(thakis): Remove this once this bug has been fixed in the NDK and
+// that NDK has been rolled into chromium.
+#if defined(ANGLE_PLATFORM_ANDROID) && __x86_64__
+    *value = strtod(str.c_str(), nullptr);
+    return errno != ERANGE;
+#else
+    std::istringstream stream(str);
+    // Force "C" locale so that decimal character is always '.', and
+    // not dependent on the current locale.
+    stream.imbue(std::locale::classic());
+
+    stream >> (*value);
+    return !stream.fail() && std::isfinite(*value);
+#endif
 }
 
 }  // namespace pp.
 
 #endif  // COMPILER_PREPROCESSOR_NUMERICLEX_H_
--- a/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -4,18 +4,18 @@
 // found in the LICENSE file.
 //
 
 // Analysis of the AST needed for HLSL generation
 
 #include "compiler/translator/ASTMetadataHLSL.h"
 
 #include "compiler/translator/CallDAG.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
-#include "compiler/translator/tree_util/IntermTraverse.h"
 
 namespace sh
 {
 
 namespace
 {
 
 // Class used to traverse the AST of a function definition, checking if the
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AddAndTrueToLoopCondition.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2016 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.
+//
+
+#include "compiler/translator/AddAndTrueToLoopCondition.h"
+
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// An AST traverser that rewrites for and while loops by replacing "condition" with
+// "condition && true" to work around condition bug on Intel Mac.
+class AddAndTrueToLoopConditionTraverser : public TIntermTraverser
+{
+  public:
+    AddAndTrueToLoopConditionTraverser() : TIntermTraverser(true, false, false) {}
+
+    bool visitLoop(Visit, TIntermLoop *loop) override
+    {
+        // do-while loop doesn't have this bug.
+        if (loop->getType() != ELoopFor && loop->getType() != ELoopWhile)
+        {
+            return true;
+        }
+
+        // For loop may not have a condition.
+        if (loop->getCondition() == nullptr)
+        {
+            return true;
+        }
+
+        // Constant true.
+        TIntermTyped *trueValue = CreateBoolNode(true);
+
+        // CONDITION && true.
+        TIntermBinary *andOp = new TIntermBinary(EOpLogicalAnd, loop->getCondition(), trueValue);
+        loop->setCondition(andOp);
+
+        return true;
+    }
+};
+
+}  // anonymous namespace
+
+void AddAndTrueToLoopCondition(TIntermNode *root)
+{
+    AddAndTrueToLoopConditionTraverser traverser;
+    root->traverse(&traverser);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AddAndTrueToLoopCondition.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// Rewrite condition in for and while loops to work around driver bug on Intel Mac.
+
+#ifndef COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
+#define COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
+
+class TIntermNode;
+namespace sh
+{
+
+void AddAndTrueToLoopCondition(TIntermNode *root);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_ADDANDTRUETOLOOPCONDITION_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AddDefaultReturnStatements.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2016 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.
+//
+// AddDefaultReturnStatements.cpp: Add default return statements to functions that do not end in a
+//                                 return.
+//
+
+#include "compiler/translator/AddDefaultReturnStatements.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool NeedsReturnStatement(TIntermFunctionDefinition *node, TType *returnType)
+{
+    *returnType = node->getFunctionPrototype()->getType();
+    if (returnType->getBasicType() == EbtVoid)
+    {
+        return false;
+    }
+
+    TIntermBlock *bodyNode    = node->getBody();
+    TIntermBranch *returnNode = bodyNode->getSequence()->back()->getAsBranchNode();
+    if (returnNode != nullptr && returnNode->getFlowOp() == EOpReturn)
+    {
+        return false;
+    }
+
+    return true;
+}
+
+}  // anonymous namespace
+
+void AddDefaultReturnStatements(TIntermBlock *root)
+{
+    TType returnType;
+    for (TIntermNode *node : *root->getSequence())
+    {
+        TIntermFunctionDefinition *definition = node->getAsFunctionDefinition();
+        if (definition != nullptr && NeedsReturnStatement(definition, &returnType))
+        {
+            TIntermBranch *branch = new TIntermBranch(EOpReturn, CreateZeroNode(returnType));
+
+            TIntermBlock *bodyNode = definition->getBody();
+            bodyNode->getSequence()->push_back(branch);
+        }
+    }
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/AddDefaultReturnStatements.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2016 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.
+//
+// AddDefaultReturnStatements.h: Add default return statements to functions that do not end in a
+//                               return.
+//
+
+#ifndef COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_
+#define COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_
+
+class TIntermBlock;
+
+namespace sh
+{
+
+void AddDefaultReturnStatements(TIntermBlock *root);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_ADDDEFAULTRETURNSTATEMENTS_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -0,0 +1,244 @@
+//
+// Copyright (c) 2002-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.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out
+// parameters in function definitions, prototypes, and call sites.
+
+#include "compiler/translator/ArrayReturnValueToOutParameter.h"
+
+#include <map>
+
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kReturnValueVariableName("angle_return");
+
+void CopyAggregateChildren(TIntermAggregateBase *from, TIntermAggregateBase *to)
+{
+    const TIntermSequence *fromSequence = from->getSequence();
+    for (size_t ii = 0; ii < fromSequence->size(); ++ii)
+    {
+        to->getSequence()->push_back(fromSequence->at(ii));
+    }
+}
+
+class ArrayReturnValueToOutParameterTraverser : private TIntermTraverser
+{
+  public:
+    static void apply(TIntermNode *root, TSymbolTable *symbolTable);
+
+  private:
+    ArrayReturnValueToOutParameterTraverser(TSymbolTable *symbolTable);
+
+    bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
+    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+    bool visitBranch(Visit visit, TIntermBranch *node) override;
+    bool visitBinary(Visit visit, TIntermBinary *node) override;
+
+    TIntermAggregate *createReplacementCall(TIntermAggregate *originalCall,
+                                            TIntermTyped *returnValueTarget);
+
+    // Set when traversal is inside a function with array return value.
+    TIntermFunctionDefinition *mFunctionWithArrayReturnValue;
+
+    struct ChangedFunction
+    {
+        const TVariable *returnValueVariable;
+        const TFunction *func;
+    };
+
+    // Map from function symbol ids to the changed function.
+    std::map<int, ChangedFunction> mChangedFunctions;
+};
+
+TIntermAggregate *ArrayReturnValueToOutParameterTraverser::createReplacementCall(
+    TIntermAggregate *originalCall,
+    TIntermTyped *returnValueTarget)
+{
+    TIntermSequence *replacementArguments = new TIntermSequence();
+    TIntermSequence *originalArguments    = originalCall->getSequence();
+    for (auto &arg : *originalArguments)
+    {
+        replacementArguments->push_back(arg);
+    }
+    replacementArguments->push_back(returnValueTarget);
+    ASSERT(originalCall->getFunction());
+    const TSymbolUniqueId &originalId = originalCall->getFunction()->uniqueId();
+    TIntermAggregate *replacementCall = TIntermAggregate::CreateFunctionCall(
+        *mChangedFunctions[originalId.get()].func, replacementArguments);
+    replacementCall->setLine(originalCall->getLine());
+    return replacementCall;
+}
+
+void ArrayReturnValueToOutParameterTraverser::apply(TIntermNode *root, TSymbolTable *symbolTable)
+{
+    ArrayReturnValueToOutParameterTraverser arrayReturnValueToOutParam(symbolTable);
+    root->traverse(&arrayReturnValueToOutParam);
+    arrayReturnValueToOutParam.updateTree();
+}
+
+ArrayReturnValueToOutParameterTraverser::ArrayReturnValueToOutParameterTraverser(
+    TSymbolTable *symbolTable)
+    : TIntermTraverser(true, false, true, symbolTable), mFunctionWithArrayReturnValue(nullptr)
+{
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitFunctionDefinition(
+    Visit visit,
+    TIntermFunctionDefinition *node)
+{
+    if (node->getFunctionPrototype()->isArray() && visit == PreVisit)
+    {
+        // Replacing the function header is done on visitFunctionPrototype().
+        mFunctionWithArrayReturnValue = node;
+    }
+    if (visit == PostVisit)
+    {
+        mFunctionWithArrayReturnValue = nullptr;
+    }
+    return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitFunctionPrototype(Visit visit,
+                                                                     TIntermFunctionPrototype *node)
+{
+    if (visit == PreVisit && node->isArray())
+    {
+        // Replace the whole prototype node with another node that has the out parameter
+        // added. Also set the function to return void.
+        const TSymbolUniqueId &functionId = node->getFunction()->uniqueId();
+        if (mChangedFunctions.find(functionId.get()) == mChangedFunctions.end())
+        {
+            TType *returnValueVariableType = new TType(node->getType());
+            returnValueVariableType->setQualifier(EvqOut);
+            ChangedFunction changedFunction;
+            changedFunction.returnValueVariable =
+                new TVariable(mSymbolTable, kReturnValueVariableName, returnValueVariableType,
+                              SymbolType::AngleInternal);
+            TFunction *func = new TFunction(mSymbolTable, node->getFunction()->name(),
+                                            node->getFunction()->symbolType(),
+                                            StaticType::GetBasic<EbtVoid>(), false);
+            for (size_t i = 0; i < node->getFunction()->getParamCount(); ++i)
+            {
+                func->addParameter(node->getFunction()->getParam(i));
+            }
+            func->addParameter(TConstParameter(
+                kReturnValueVariableName, static_cast<const TType *>(returnValueVariableType)));
+            changedFunction.func                = func;
+            mChangedFunctions[functionId.get()] = changedFunction;
+        }
+        TIntermFunctionPrototype *replacement =
+            new TIntermFunctionPrototype(mChangedFunctions[functionId.get()].func);
+        CopyAggregateChildren(node, replacement);
+        replacement->getSequence()->push_back(
+            new TIntermSymbol(mChangedFunctions[functionId.get()].returnValueVariable));
+        replacement->setLine(node->getLine());
+
+        queueReplacement(replacement, OriginalNode::IS_DROPPED);
+    }
+    return false;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+    ASSERT(!node->isArray() || node->getOp() != EOpCallInternalRawFunction);
+    if (visit == PreVisit && node->isArray() && node->getOp() == EOpCallFunctionInAST)
+    {
+        // Handle call sites where the returned array is not assigned.
+        // Examples where f() is a function returning an array:
+        // 1. f();
+        // 2. another_array == f();
+        // 3. another_function(f());
+        // 4. return f();
+        // Cases 2 to 4 are already converted to simpler cases by
+        // SeparateExpressionsReturningArrays, so we only need to worry about the case where a
+        // function call returning an array forms an expression by itself.
+        TIntermBlock *parentBlock = getParentNode()->getAsBlock();
+        if (parentBlock)
+        {
+            // replace
+            //   f();
+            // with
+            //   type s0[size]; f(s0);
+            TIntermSequence replacements;
+
+            // type s0[size];
+            TIntermDeclaration *returnValueDeclaration = nullptr;
+            TVariable *returnValue = DeclareTempVariable(mSymbolTable, new TType(node->getType()),
+                                                         EvqTemporary, &returnValueDeclaration);
+            replacements.push_back(returnValueDeclaration);
+
+            // f(s0);
+            TIntermSymbol *returnValueSymbol = CreateTempSymbolNode(returnValue);
+            replacements.push_back(createReplacementCall(node, returnValueSymbol));
+            mMultiReplacements.push_back(
+                NodeReplaceWithMultipleEntry(parentBlock, node, replacements));
+        }
+        return false;
+    }
+    return true;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+    if (mFunctionWithArrayReturnValue && node->getFlowOp() == EOpReturn)
+    {
+        // Instead of returning a value, assign to the out parameter and then return.
+        TIntermSequence replacements;
+
+        TIntermTyped *expression = node->getExpression();
+        ASSERT(expression != nullptr);
+        const TSymbolUniqueId &functionId =
+            mFunctionWithArrayReturnValue->getFunction()->uniqueId();
+        ASSERT(mChangedFunctions.find(functionId.get()) != mChangedFunctions.end());
+        TIntermSymbol *returnValueSymbol =
+            new TIntermSymbol(mChangedFunctions[functionId.get()].returnValueVariable);
+        TIntermBinary *replacementAssignment =
+            new TIntermBinary(EOpAssign, returnValueSymbol, expression);
+        replacementAssignment->setLine(expression->getLine());
+        replacements.push_back(replacementAssignment);
+
+        TIntermBranch *replacementBranch = new TIntermBranch(EOpReturn, nullptr);
+        replacementBranch->setLine(node->getLine());
+        replacements.push_back(replacementBranch);
+
+        mMultiReplacements.push_back(
+            NodeReplaceWithMultipleEntry(getParentNode()->getAsBlock(), node, replacements));
+    }
+    return false;
+}
+
+bool ArrayReturnValueToOutParameterTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+    if (node->getOp() == EOpAssign && node->getLeft()->isArray())
+    {
+        TIntermAggregate *rightAgg = node->getRight()->getAsAggregate();
+        ASSERT(rightAgg == nullptr || rightAgg->getOp() != EOpCallInternalRawFunction);
+        if (rightAgg != nullptr && rightAgg->getOp() == EOpCallFunctionInAST)
+        {
+            TIntermAggregate *replacementCall = createReplacementCall(rightAgg, node->getLeft());
+            queueReplacement(replacementCall, OriginalNode::IS_DROPPED);
+        }
+    }
+    return false;
+}
+
+}  // namespace
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable)
+{
+    ArrayReturnValueToOutParameterTraverser::apply(root, symbolTable);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ArrayReturnValueToOutParameter.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-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.
+//
+// The ArrayReturnValueToOutParameter function changes return values of an array type to out
+// parameters in function definitions, prototypes and call sites.
+
+#ifndef COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
+#define COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void ArrayReturnValueToOutParameter(TIntermNode *root, TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_ARRAYRETURNVALUETOOUTPARAMETER_H_
--- a/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
+++ b/gfx/angle/checkout/src/compiler/translator/BaseTypes.h
@@ -52,22 +52,28 @@ inline const char *getPrecisionString(TP
 //
 enum TBasicType
 {
     EbtVoid,
     EbtFloat,
     EbtInt,
     EbtUInt,
     EbtBool,
-
-    EbtAtomicCounter,
+    EbtGVec4,              // non type: represents vec4, ivec4, and uvec4
+    EbtGenType,            // non type: represents float, vec2, vec3, and vec4
+    EbtGenIType,           // non type: represents int, ivec2, ivec3, and ivec4
+    EbtGenUType,           // non type: represents uint, uvec2, uvec3, and uvec4
+    EbtGenBType,           // non type: represents bool, bvec2, bvec3, and bvec4
+    EbtVec,                // non type: represents vec2, vec3, and vec4
+    EbtIVec,               // non type: represents ivec2, ivec3, and ivec4
+    EbtUVec,               // non type: represents uvec2, uvec3, and uvec4
+    EbtBVec,               // non type: represents bvec2, bvec3, and bvec4
     EbtYuvCscStandardEXT,  // Only valid if EXT_YUV_target exists.
-
     EbtGuardSamplerBegin,  // non type: see implementation of IsSampler()
-    EbtSampler2D = EbtGuardSamplerBegin,
+    EbtSampler2D,
     EbtSampler3D,
     EbtSamplerCube,
     EbtSampler2DArray,
     EbtSamplerExternalOES,       // Only valid if OES_EGL_image_external exists.
     EbtSamplerExternal2DY2YEXT,  // Only valid if GL_EXT_YUV_target exists.
     EbtSampler2DRect,            // Only valid if GL_ARB_texture_rectangle exists.
     EbtSampler2DMS,
     EbtISampler2D,
@@ -78,67 +84,163 @@ enum TBasicType
     EbtUSampler2D,
     EbtUSampler3D,
     EbtUSamplerCube,
     EbtUSampler2DArray,
     EbtUSampler2DMS,
     EbtSampler2DShadow,
     EbtSamplerCubeShadow,
     EbtSampler2DArrayShadow,
-    EbtGuardSamplerEnd = EbtSampler2DArrayShadow,  // non type: see implementation of IsSampler()
+    EbtGuardSamplerEnd,  // non type: see implementation of IsSampler()
+    EbtGSampler2D,       // non type: represents sampler2D, isampler2D, and usampler2D
+    EbtGSampler3D,       // non type: represents sampler3D, isampler3D, and usampler3D
+    EbtGSamplerCube,     // non type: represents samplerCube, isamplerCube, and usamplerCube
+    EbtGSampler2DArray,  // non type: represents sampler2DArray, isampler2DArray, and
+                         // usampler2DArray
+    EbtGSampler2DMS,     // non type: represents sampler2DMS, isampler2DMS, and usampler2DMS
 
     // images
     EbtGuardImageBegin,
-    EbtImage2D = EbtGuardImageBegin,
+    EbtImage2D,
     EbtIImage2D,
     EbtUImage2D,
     EbtImage3D,
     EbtIImage3D,
     EbtUImage3D,
     EbtImage2DArray,
     EbtIImage2DArray,
     EbtUImage2DArray,
     EbtImageCube,
     EbtIImageCube,
     EbtUImageCube,
-    EbtGuardImageEnd = EbtUImageCube,
+    EbtGuardImageEnd,
 
-    EbtLastSimpleType = EbtGuardImageEnd,
+    EbtGuardGImageBegin,
+    EbtGImage2D,       // non type: represents image2D, uimage2D, iimage2D
+    EbtGImage3D,       // non type: represents image3D, uimage3D, iimage3D
+    EbtGImage2DArray,  // non type: represents image2DArray, uimage2DArray, iimage2DArray
+    EbtGImageCube,     // non type: represents imageCube, uimageCube, iimageCube
+    EbtGuardGImageEnd,
 
     EbtStruct,
     EbtInterfaceBlock,
+    EbtAddress,  // should be deprecated??
+
+    EbtAtomicCounter,
 
     // end of list
-    EbtLast = EbtInterfaceBlock
+    EbtLast
 };
 
-constexpr char GetBasicMangledName(TBasicType t)
+constexpr const char *GetBasicMangledName(TBasicType t)
 {
-    if (t > EbtLastSimpleType)
+    switch (t)
     {
-        return '{';
+        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:
+            // EbtVoid, EbtAddress and non types
+            return "";
     }
-    static_assert(EbtLastSimpleType < 52, "We only use alphabetic characters for mangled names");
-    if (t < 26)
-    {
-        return static_cast<char>('A' + t);
-    }
-    return static_cast<char>('a' - 26 + t);
 }
 
 const char *getBasicString(TBasicType t);
 
 inline bool IsSampler(TBasicType type)
 {
-    return type >= EbtGuardSamplerBegin && type <= EbtGuardSamplerEnd;
+    return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
 }
 
 inline bool IsImage(TBasicType type)
 {
-    return type >= EbtGuardImageBegin && type <= EbtGuardImageEnd;
+    return type > EbtGuardImageBegin && type < EbtGuardImageEnd;
+}
+
+inline bool IsGImage(TBasicType type)
+{
+    return type > EbtGuardGImageBegin && type < EbtGuardGImageEnd;
 }
 
 inline bool IsAtomicCounter(TBasicType type)
 {
     return type == EbtAtomicCounter;
 }
 
 inline bool IsOpaqueType(TBasicType type)
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
@@ -0,0 +1,107 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+//      may record a variable as aliasing another. Sometimes the alias information gets garbled
+//      so we work around this issue by breaking the aliasing chain in inner loops.
+
+#include "BreakVariableAliasingInInnerLoops.h"
+
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+
+// A HLSL compiler developer gave us more details on the root cause and the workaround needed:
+//     The root problem is that if the HLSL compiler is applying aliasing information even on
+//     incomplete simulations (in this case, a single pass). The bug is triggered by an assignment
+//     that comes from a series of assignments, possibly with swizzled or ternary operators with
+//     known conditionals, where the source is before the loop.
+//     So, a workaround is to add a +0 term to variables the first time they are assigned to in
+//     an inner loop (if they are declared in an outside scope, otherwise there is no need).
+//     This will break the aliasing chain.
+
+// For simplicity here we add a +0 to any assignment that is in at least two nested loops. Because
+// the bug only shows up with swizzles, and ternary assignment, whole array or whole structure
+// assignment don't need a workaround.
+
+namespace sh
+{
+
+namespace
+{
+
+class AliasingBreaker : public TIntermTraverser
+{
+  public:
+    AliasingBreaker() : TIntermTraverser(true, false, true) {}
+
+  protected:
+    bool visitBinary(Visit visit, TIntermBinary *binary)
+    {
+        if (visit != PreVisit)
+        {
+            return false;
+        }
+
+        if (mLoopLevel < 2 || !binary->isAssignment())
+        {
+            return true;
+        }
+
+        TIntermTyped *B = binary->getRight();
+        TType type      = B->getType();
+
+        if (!type.isScalar() && !type.isVector() && !type.isMatrix())
+        {
+            return true;
+        }
+
+        if (type.isArray() || IsSampler(type.getBasicType()))
+        {
+            return true;
+        }
+
+        // We have a scalar / vector / matrix assignment with loop depth 2.
+        // Transform it from
+        //    A = B
+        // to
+        //    A = (B + typeof<B>(0));
+
+        TIntermBinary *bPlusZero = new TIntermBinary(EOpAdd, B, CreateZeroNode(type));
+        bPlusZero->setLine(B->getLine());
+
+        binary->replaceChildNode(B, bPlusZero);
+
+        return true;
+    }
+
+    bool visitLoop(Visit visit, TIntermLoop *loop)
+    {
+        if (visit == PreVisit)
+        {
+            mLoopLevel++;
+        }
+        else
+        {
+            ASSERT(mLoopLevel > 0);
+            mLoopLevel--;
+        }
+
+        return true;
+    }
+
+  private:
+    int mLoopLevel = 0;
+};
+
+}  // anonymous namespace
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root)
+{
+    AliasingBreaker breaker;
+    root->traverse(&breaker);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/BreakVariableAliasingInInnerLoops.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// BreakVariableAliasingInInnerLoops.h: To optimize simple assignments, the HLSL compiler frontend
+//      may record a variable as aliasing another. Sometimes the alias information gets garbled
+//      so we work around this issue by breaking the aliasing chain in inner loops.
+
+#ifndef COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
+#define COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
+
+class TIntermNode;
+
+namespace sh
+{
+
+void BreakVariableAliasingInInnerLoops(TIntermNode *root);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_BREAKVARIABLEALIASINGININNERLOOPS_H_
--- a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -1,77 +1,174 @@
 //
 // Copyright (c) 2002-2011 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.
 //
 
 #include "compiler/translator/BuiltInFunctionEmulator.h"
 #include "angle_gl.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/StaticType.h"
-#include "compiler/translator/Symbol.h"
-#include "compiler/translator/tree_util/IntermTraverse.h"
 
 namespace sh
 {
 
 class BuiltInFunctionEmulator::BuiltInFunctionEmulationMarker : public TIntermTraverser
 {
   public:
     BuiltInFunctionEmulationMarker(BuiltInFunctionEmulator &emulator)
         : TIntermTraverser(true, false, false), mEmulator(emulator)
     {
     }
 
     bool visitUnary(Visit visit, TIntermUnary *node) override
     {
-        if (node->getFunction())
+        if (visit == PreVisit)
         {
-            bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
+            bool needToEmulate =
+                mEmulator.setFunctionCalled(node->getOp(), node->getOperand()->getType());
             if (needToEmulate)
                 node->setUseEmulatedFunction();
         }
         return true;
     }
 
     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     {
-        // Here we handle all the built-in functions mapped to ops, not just the ones that are
-        // currently identified as problematic.
-        if (node->isConstructor() || node->isFunctionCall())
+        if (visit == PreVisit)
         {
-            return true;
+            // Here we handle all the built-in functions mapped to ops, not just the ones that are
+            // currently identified as problematic.
+            if (node->isConstructor() || node->isFunctionCall())
+            {
+                return true;
+            }
+            const TIntermSequence &sequence = *(node->getSequence());
+            bool needToEmulate              = false;
+            // Right now we only handle built-in functions with two to four parameters.
+            if (sequence.size() == 2)
+            {
+                TIntermTyped *param1 = sequence[0]->getAsTyped();
+                TIntermTyped *param2 = sequence[1]->getAsTyped();
+                if (!param1 || !param2)
+                    return true;
+                needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(),
+                                                            param2->getType());
+            }
+            else if (sequence.size() == 3)
+            {
+                TIntermTyped *param1 = sequence[0]->getAsTyped();
+                TIntermTyped *param2 = sequence[1]->getAsTyped();
+                TIntermTyped *param3 = sequence[2]->getAsTyped();
+                if (!param1 || !param2 || !param3)
+                    return true;
+                needToEmulate = mEmulator.setFunctionCalled(node->getOp(), param1->getType(),
+                                                            param2->getType(), param3->getType());
+            }
+            else if (sequence.size() == 4)
+            {
+                TIntermTyped *param1 = sequence[0]->getAsTyped();
+                TIntermTyped *param2 = sequence[1]->getAsTyped();
+                TIntermTyped *param3 = sequence[2]->getAsTyped();
+                TIntermTyped *param4 = sequence[3]->getAsTyped();
+                if (!param1 || !param2 || !param3 || !param4)
+                    return true;
+                needToEmulate =
+                    mEmulator.setFunctionCalled(node->getOp(), param1->getType(), param2->getType(),
+                                                param3->getType(), param4->getType());
+            }
+            else
+            {
+                return true;
+            }
+
+            if (needToEmulate)
+                node->setUseEmulatedFunction();
         }
-        bool needToEmulate = mEmulator.setFunctionCalled(node->getFunction());
-        if (needToEmulate)
-            node->setUseEmulatedFunction();
         return true;
     }
 
   private:
     BuiltInFunctionEmulator &mEmulator;
 };
 
 BuiltInFunctionEmulator::BuiltInFunctionEmulator()
 {
 }
 
-void BuiltInFunctionEmulator::addEmulatedFunction(const TSymbolUniqueId &uniqueId,
-                                                  const char *emulatedFunctionDefinition)
+FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
+                                                        const TType *param,
+                                                        const char *emulatedFunctionDefinition)
+{
+    FunctionId id(op, param);
+    mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+    return id;
+}
+
+FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
+                                                        const TType *param1,
+                                                        const TType *param2,
+                                                        const char *emulatedFunctionDefinition)
 {
-    mEmulatedFunctions[uniqueId.get()] = std::string(emulatedFunctionDefinition);
+    FunctionId id(op, param1, param2);
+    mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+    return id;
+}
+
+FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
+    const FunctionId &dependency,
+    TOperator op,
+    const TType *param1,
+    const TType *param2,
+    const char *emulatedFunctionDefinition)
+{
+    FunctionId id(op, param1, param2);
+    mEmulatedFunctions[id]    = std::string(emulatedFunctionDefinition);
+    mFunctionDependencies[id] = dependency;
+    return id;
 }
 
-void BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
-    const TSymbolUniqueId &dependency,
-    const TSymbolUniqueId &uniqueId,
+FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
+                                                        const TType *param1,
+                                                        const TType *param2,
+                                                        const TType *param3,
+                                                        const char *emulatedFunctionDefinition)
+{
+    FunctionId id(op, param1, param2, param3);
+    mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+    return id;
+}
+
+FunctionId BuiltInFunctionEmulator::addEmulatedFunction(TOperator op,
+                                                        const TType *param1,
+                                                        const TType *param2,
+                                                        const TType *param3,
+                                                        const TType *param4,
+                                                        const char *emulatedFunctionDefinition)
+{
+    FunctionId id(op, param1, param2, param3, param4);
+    mEmulatedFunctions[id] = std::string(emulatedFunctionDefinition);
+    return id;
+}
+
+FunctionId BuiltInFunctionEmulator::addEmulatedFunctionWithDependency(
+    const FunctionId &dependency,
+    TOperator op,
+    const TType *param1,
+    const TType *param2,
+    const TType *param3,
+    const TType *param4,
     const char *emulatedFunctionDefinition)
 {
-    mEmulatedFunctions[uniqueId.get()]    = std::string(emulatedFunctionDefinition);
-    mFunctionDependencies[uniqueId.get()] = dependency.get();
+    FunctionId id(op, param1, param2, param3, param4);
+    mEmulatedFunctions[id]    = std::string(emulatedFunctionDefinition);
+    mFunctionDependencies[id] = dependency;
+    return id;
 }
 
 bool BuiltInFunctionEmulator::isOutputEmpty() const
 {
     return (mFunctions.size() == 0);
 }
 
 void BuiltInFunctionEmulator::outputEmulatedFunctions(TInfoSinkBase &out) const
@@ -80,61 +177,86 @@ void BuiltInFunctionEmulator::outputEmul
     {
         const char *body = findEmulatedFunction(function);
         ASSERT(body);
         out << body;
         out << "\n\n";
     }
 }
 
-const char *BuiltInFunctionEmulator::findEmulatedFunction(int uniqueId) const
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op, const TType &param)
+{
+    return setFunctionCalled(FunctionId(op, &param));
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
+                                                const TType &param1,
+                                                const TType &param2)
+{
+    return setFunctionCalled(FunctionId(op, &param1, &param2));
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
+                                                const TType &param1,
+                                                const TType &param2,
+                                                const TType &param3)
+{
+    return setFunctionCalled(FunctionId(op, &param1, &param2, &param3));
+}
+
+bool BuiltInFunctionEmulator::setFunctionCalled(TOperator op,
+                                                const TType &param1,
+                                                const TType &param2,
+                                                const TType &param3,
+                                                const TType &param4)
+{
+    return setFunctionCalled(FunctionId(op, &param1, &param2, &param3, &param4));
+}
+
+const char *BuiltInFunctionEmulator::findEmulatedFunction(const FunctionId &functionId) const
 {
     for (const auto &queryFunction : mQueryFunctions)
     {
-        const char *result = queryFunction(uniqueId);
+        const char *result = queryFunction(functionId);
         if (result)
         {
             return result;
         }
     }
 
-    const auto &result = mEmulatedFunctions.find(uniqueId);
+    const auto &result = mEmulatedFunctions.find(functionId);
     if (result != mEmulatedFunctions.end())
     {
         return result->second.c_str();
     }
 
     return nullptr;
 }
 
-bool BuiltInFunctionEmulator::setFunctionCalled(const TFunction *function)
+bool BuiltInFunctionEmulator::setFunctionCalled(const FunctionId &functionId)
 {
-    ASSERT(function != nullptr);
-    return setFunctionCalled(function->uniqueId().get());
-}
-
-bool BuiltInFunctionEmulator::setFunctionCalled(int uniqueId)
-{
-    if (!findEmulatedFunction(uniqueId))
+    if (!findEmulatedFunction(functionId))
     {
         return false;
     }
 
     for (size_t i = 0; i < mFunctions.size(); ++i)
     {
-        if (mFunctions[i] == uniqueId)
+        if (mFunctions[i] == functionId)
             return true;
     }
     // If the function depends on another, mark the dependency as called.
-    auto dependency = mFunctionDependencies.find(uniqueId);
+    auto dependency = mFunctionDependencies.find(functionId);
     if (dependency != mFunctionDependencies.end())
     {
         setFunctionCalled((*dependency).second);
     }
-    mFunctions.push_back(uniqueId);
+    // Copy the functionId if it needs to be stored, to make sure that the TType pointers inside
+    // remain valid and constant.
+    mFunctions.push_back(functionId.getCopy());
     return true;
 }
 
 void BuiltInFunctionEmulator::markBuiltInFunctionsForEmulation(TIntermNode *root)
 {
     ASSERT(root);
 
     if (mEmulatedFunctions.empty() && mQueryFunctions.empty())
@@ -157,9 +279,81 @@ void BuiltInFunctionEmulator::addFunctio
 
 // static
 void BuiltInFunctionEmulator::WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name)
 {
     ASSERT(name[strlen(name) - 1] != '(');
     out << name << "_emu";
 }
 
+FunctionId::FunctionId()
+    : mOp(EOpNull),
+      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(StaticType::GetBasic<EbtVoid>()),
+      mParam3(StaticType::GetBasic<EbtVoid>()),
+      mParam4(StaticType::GetBasic<EbtVoid>())
+{
+}
+
+FunctionId::FunctionId(TOperator op, const TType *param1, const TType *param2)
+    : mOp(op),
+      mParam1(param1),
+      mParam2(param2),
+      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(StaticType::GetBasic<EbtVoid>())
+{
+}
+
+FunctionId::FunctionId(TOperator op,
+                       const TType *param1,
+                       const TType *param2,
+                       const TType *param3,
+                       const TType *param4)
+    : mOp(op), mParam1(param1), mParam2(param2), mParam3(param3), mParam4(param4)
+{
+}
+
+bool FunctionId::operator==(const FunctionId &other) const
+{
+    return (mOp == other.mOp && *mParam1 == *other.mParam1 && *mParam2 == *other.mParam2 &&
+            *mParam3 == *other.mParam3 && *mParam4 == *other.mParam4);
+}
+
+bool FunctionId::operator<(const FunctionId &other) const
+{
+    if (mOp != other.mOp)
+        return mOp < other.mOp;
+    if (*mParam1 != *other.mParam1)
+        return *mParam1 < *other.mParam1;
+    if (*mParam2 != *other.mParam2)
+        return *mParam2 < *other.mParam2;
+    if (*mParam3 != *other.mParam3)
+        return *mParam3 < *other.mParam3;
+    if (*mParam4 != *other.mParam4)
+        return *mParam4 < *other.mParam4;
+    return false;  // all fields are equal
+}
+
+FunctionId FunctionId::getCopy() const
+{
+    return FunctionId(mOp, new TType(*mParam1), new TType(*mParam2), new TType(*mParam3),
+                      new TType(*mParam4));
+}
+
 }  // namespace sh
--- a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulator.h
@@ -3,25 +3,92 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 #ifndef COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
 #define COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
 
 #include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/ParamType.h"
 
 namespace sh
 {
 
-class TIntermNode;
-class TFunction;
-class TSymbolUniqueId;
+struct MiniFunctionId
+{
+    constexpr MiniFunctionId(TOperator op         = EOpNull,
+                             ParamType paramType1 = ParamType::Void,
+                             ParamType paramType2 = ParamType::Void,
+                             ParamType paramType3 = ParamType::Void,
+                             ParamType paramType4 = ParamType::Void)
+        : op(op),
+          paramType1(paramType1),
+          paramType2(paramType2),
+          paramType3(paramType3),
+          paramType4(paramType4)
+    {
+    }
+
+    TOperator op;
+    ParamType paramType1;
+    ParamType paramType2;
+    ParamType paramType3;
+    ParamType paramType4;
+};
+
+class FunctionId final
+{
+  public:
+    FunctionId();
+    FunctionId(TOperator op, const TType *param);
+    FunctionId(TOperator op, const TType *param1, const TType *param2);
+    FunctionId(TOperator op, const TType *param1, const TType *param2, const TType *param3);
+    FunctionId(TOperator op,
+               const TType *param1,
+               const TType *param2,
+               const TType *param3,
+               const TType *param4);
 
-using BuiltinQueryFunc = const char *(int);
+    FunctionId(const FunctionId &) = default;
+    FunctionId &operator=(const FunctionId &) = default;
+
+    bool operator==(const FunctionId &other) const;
+    bool operator<(const FunctionId &other) const;
+
+    FunctionId getCopy() const;
+
+  private:
+    friend bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId);
+    TOperator mOp;
+
+    // The memory that these TType objects use is freed by PoolAllocator. The
+    // BuiltInFunctionEmulator's lifetime can extend until after the memory pool is freed, but
+    // that's not an issue since this class never destructs these objects.
+    const TType *mParam1;
+    const TType *mParam2;
+    const TType *mParam3;
+    const TType *mParam4;
+};
+
+inline bool operator==(ParamType paramType, const TType *type)
+{
+    return SameParamType(paramType, type->getBasicType(), type->getNominalSize(),
+                         type->getSecondarySize());
+}
+
+inline bool operator==(const MiniFunctionId &miniId, const FunctionId &functionId)
+{
+    return miniId.op == functionId.mOp && miniId.paramType1 == functionId.mParam1 &&
+           miniId.paramType2 == functionId.mParam2 && miniId.paramType3 == functionId.mParam3 &&
+           miniId.paramType4 == functionId.mParam4;
+}
+
+using BuiltinQueryFunc = const char *(const FunctionId &);
 
 //
 // This class decides which built-in functions need to be replaced with the emulated ones. It can be
 // used to work around driver bugs or implement functions that are not natively implemented on a
 // specific platform.
 //
 class BuiltInFunctionEmulator
 {
@@ -36,45 +103,81 @@ class BuiltInFunctionEmulator
     static void WriteEmulatedFunctionName(TInfoSinkBase &out, const char *name);
 
     bool isOutputEmpty() const;
 
     // Output function emulation definition. This should be before any other shader source.
     void outputEmulatedFunctions(TInfoSinkBase &out) const;
 
     // Add functions that need to be emulated.
-    void addEmulatedFunction(const TSymbolUniqueId &uniqueId,
-                             const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunction(TOperator op,
+                                   const TType *param,
+                                   const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunction(TOperator op,
+                                   const TType *param1,
+                                   const TType *param2,
+                                   const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunction(TOperator op,
+                                   const TType *param1,
+                                   const TType *param2,
+                                   const TType *param3,
+                                   const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunction(TOperator op,
+                                   const TType *param1,
+                                   const TType *param2,
+                                   const TType *param3,
+                                   const TType *param4,
+                                   const char *emulatedFunctionDefinition);
 
-    void addEmulatedFunctionWithDependency(const TSymbolUniqueId &dependency,
-                                           const TSymbolUniqueId &uniqueId,
-                                           const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency,
+                                                 TOperator op,
+                                                 const TType *param1,
+                                                 const TType *param2,
+                                                 const char *emulatedFunctionDefinition);
+    FunctionId addEmulatedFunctionWithDependency(const FunctionId &dependency,
+                                                 TOperator op,
+                                                 const TType *param1,
+                                                 const TType *param2,
+                                                 const TType *param3,
+                                                 const TType *param4,
+                                                 const char *emulatedFunctionDefinition);
 
     void addFunctionMap(BuiltinQueryFunc queryFunc);
 
   private:
     class BuiltInFunctionEmulationMarker;
 
     // Records that a function is called by the shader and might need to be emulated. If the
     // function is not in mEmulatedFunctions, this becomes a no-op. Returns true if the function
     // call needs to be replaced with an emulated one.
-    bool setFunctionCalled(const TFunction *function);
-    bool setFunctionCalled(int uniqueId);
+    bool setFunctionCalled(TOperator op, const TType &param);
+    bool setFunctionCalled(TOperator op, const TType &param1, const TType &param2);
+    bool setFunctionCalled(TOperator op,
+                           const TType &param1,
+                           const TType &param2,
+                           const TType &param3);
+    bool setFunctionCalled(TOperator op,
+                           const TType &param1,
+                           const TType &param2,
+                           const TType &param3,
+                           const TType &param4);
 
-    const char *findEmulatedFunction(int uniqueId) const;
+    bool setFunctionCalled(const FunctionId &functionId);
 
-    // Map from function unique id to emulated function definition
-    std::map<int, std::string> mEmulatedFunctions;
+    const char *findEmulatedFunction(const FunctionId &functionId) const;
+
+    // Map from function id to emulated function definition
+    std::map<FunctionId, std::string> mEmulatedFunctions;
 
     // Map from dependent functions to their dependencies. This structure allows each function to
     // have at most one dependency.
-    std::map<int, int> mFunctionDependencies;
+    std::map<FunctionId, FunctionId> mFunctionDependencies;
 
     // Called function ids
-    std::vector<int> mFunctions;
+    std::vector<FunctionId> mFunctions;
 
     // Constexpr function tables.
     std::vector<BuiltinQueryFunc *> mQueryFunctions;
 };
 
 }  // namespace sh
 
 #endif  // COMPILER_TRANSLATOR_BUILTINFUNCTIONEMULATOR_H_
--- a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorGLSL.cpp
@@ -2,159 +2,178 @@
 // Copyright (c) 2002-2011 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.
 //
 
 #include "compiler/translator/BuiltInFunctionEmulatorGLSL.h"
 #include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/StaticType.h"
 #include "compiler/translator/VersionGLSL.h"
-#include "compiler/translator/tree_util/BuiltIn_autogen.h"
 
 namespace sh
 {
 
 void InitBuiltInAbsFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
                                                       sh::GLenum shaderType)
 {
     if (shaderType == GL_VERTEX_SHADER)
     {
-        emu->addEmulatedFunction(BuiltInId::abs_Int1, "int abs_emu(int x) { return x * sign(x); }");
+        const TType *int1 = StaticType::GetBasic<EbtInt>();
+        emu->addEmulatedFunction(EOpAbs, int1, "int abs_emu(int x) { return x * sign(x); }");
     }
 }
 
 void InitBuiltInIsnanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu,
                                                         int targetGLSLVersion)
 {
     // isnan() is supported since GLSL 1.3.
     if (targetGLSLVersion < GLSL_VERSION_130)
         return;
 
+    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(
-        BuiltInId::isnan_Float1,
+        EOpIsnan, float1,
         "bool isnan_emu(float x) { return (x > 0.0 || x < 0.0) ? false : x != 0.0; }");
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float2,
+        EOpIsnan, float2,
         "bvec2 isnan_emu(vec2 x)\n"
         "{\n"
         "    bvec2 isnan;\n"
         "    for (int i = 0; i < 2; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float3,
+        EOpIsnan, float3,
         "bvec3 isnan_emu(vec3 x)\n"
         "{\n"
         "    bvec3 isnan;\n"
         "    for (int i = 0; i < 3; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float4,
+        EOpIsnan, float4,
         "bvec4 isnan_emu(vec4 x)\n"
         "{\n"
         "    bvec4 isnan;\n"
         "    for (int i = 0; i < 4; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
 }
 
 void InitBuiltInAtanFunctionEmulatorForGLSLWorkarounds(BuiltInFunctionEmulator *emu)
 {
-    emu->addEmulatedFunction(BuiltInId::atan_Float1_Float1,
-                             "emu_precision float atan_emu(emu_precision float y, emu_precision "
-                             "float x)\n"
-                             "{\n"
-                             "    if (x > 0.0) return atan(y / x);\n"
-                             "    else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n"
-                             "    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<TSymbolUniqueId, 4> ids = {
-        BuiltInId::atan_Float1_Float1, BuiltInId::atan_Float2_Float2, BuiltInId::atan_Float3_Float3,
-        BuiltInId::atan_Float4_Float4,
+    const TType *float1 = StaticType::GetBasic<EbtFloat>();
+    auto floatFuncId    = emu->addEmulatedFunction(
+        EOpAtan, float1, float1,
+        "emu_precision float atan_emu(emu_precision float y, emu_precision "
+        "float x)\n"
+        "{\n"
+        "    if (x > 0.0) return atan(y / x);\n"
+        "    else if (x < 0.0 && y >= 0.0) return atan(y / x) + 3.14159265;\n"
+        "    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 = floatVecs[dim];
         std::stringstream ss;
         ss << "emu_precision vec" << dim << " atan_emu(emu_precision vec" << dim
            << " y, emu_precision vec" << dim << " x)\n"
            << "{\n"
               "    return vec"
            << dim << "(";
         for (int i = 0; i < dim; ++i)
         {
             ss << "atan_emu(y[" << i << "], x[" << i << "])";
             if (i < dim - 1)
             {
                 ss << ", ";
             }
         }
         ss << ");\n"
               "}\n";
-        emu->addEmulatedFunctionWithDependency(BuiltInId::atan_Float1_Float1, ids[dim - 1],
+        emu->addEmulatedFunctionWithDependency(floatFuncId, EOpAtan, floatVec, floatVec,
                                                ss.str().c_str());
     }
 }
 
 // Emulate built-in functions missing from GLSL 1.30 and higher
 void InitBuiltInFunctionEmulatorForGLSLMissingFunctions(BuiltInFunctionEmulator *emu,
                                                         sh::GLenum shaderType,
                                                         int targetGLSLVersion)
 {
     // Emulate packUnorm2x16 and unpackUnorm2x16 (GLSL 4.10)
     if (targetGLSLVersion < GLSL_VERSION_410)
     {
+        const TType *float2 = StaticType::GetBasic<EbtFloat, 2>();
+        const TType *uint1  = StaticType::GetBasic<EbtUInt>();
+
         // clang-format off
-        emu->addEmulatedFunction(BuiltInId::packUnorm2x16_Float2,
+        emu->addEmulatedFunction(EOpPackUnorm2x16, float2,
             "uint packUnorm2x16_emu(vec2 v)\n"
             "{\n"
             "    int x = int(round(clamp(v.x, 0.0, 1.0) * 65535.0));\n"
             "    int y = int(round(clamp(v.y, 0.0, 1.0) * 65535.0));\n"
             "    return uint((y << 16) | (x & 0xFFFF));\n"
             "}\n");
 
-        emu->addEmulatedFunction(BuiltInId::unpackUnorm2x16_UInt1,
+        emu->addEmulatedFunction(EOpUnpackUnorm2x16, uint1,
             "vec2 unpackUnorm2x16_emu(uint u)\n"
             "{\n"
             "    float x = float(u & 0xFFFFu) / 65535.0;\n"
             "    float y = float(u >> 16) / 65535.0;\n"
             "    return vec2(x, y);\n"
             "}\n");
         // clang-format on
     }
 
     // Emulate packSnorm2x16, packHalf2x16, unpackSnorm2x16, and unpackHalf2x16 (GLSL 4.20)
     // by using floatBitsToInt, floatBitsToUint, intBitsToFloat, and uintBitsToFloat (GLSL 3.30).
     if (targetGLSLVersion >= GLSL_VERSION_330 && targetGLSLVersion < GLSL_VERSION_420)
     {
+        const TType *float2 = StaticType::GetBasic<EbtFloat, 2>();
+        const TType *uint1  = StaticType::GetBasic<EbtUInt>();
+
         // clang-format off
-        emu->addEmulatedFunction(BuiltInId::packSnorm2x16_Float2,
+        emu->addEmulatedFunction(EOpPackSnorm2x16, float2,
             "uint packSnorm2x16_emu(vec2 v)\n"
             "{\n"
             "    #if defined(GL_ARB_shading_language_packing)\n"
             "        return packSnorm2x16(v);\n"
             "    #else\n"
             "        int x = int(round(clamp(v.x, -1.0, 1.0) * 32767.0));\n"
             "        int y = int(round(clamp(v.y, -1.0, 1.0) * 32767.0));\n"
             "        return uint((y << 16) | (x & 0xFFFF));\n"
             "    #endif\n"
             "}\n");
-        emu->addEmulatedFunction(BuiltInId::unpackSnorm2x16_UInt1,
+        emu->addEmulatedFunction(EOpUnpackSnorm2x16, uint1,
             "#if !defined(GL_ARB_shading_language_packing)\n"
             "    float fromSnorm(uint x)\n"
             "    {\n"
             "        int xi = (int(x) & 0x7FFF) - (int(x) & 0x8000);\n"
             "        return clamp(float(xi) / 32767.0, -1.0, 1.0);\n"
             "    }\n"
             "#endif\n"
             "\n"
@@ -165,17 +184,17 @@ void InitBuiltInFunctionEmulatorForGLSLM
             "    #else\n"
             "        uint y = (u >> 16);\n"
             "        uint x = u;\n"
             "        return vec2(fromSnorm(x), fromSnorm(y));\n"
             "    #endif\n"
             "}\n");
         // Functions uint f32tof16(float val) and float f16tof32(uint val) are
         // based on the OpenGL redbook Appendix Session "Floating-Point Formats Used in OpenGL".
-        emu->addEmulatedFunction(BuiltInId::packHalf2x16_Float2,
+        emu->addEmulatedFunction(EOpPackHalf2x16, float2,
             "#if !defined(GL_ARB_shading_language_packing)\n"
             "    uint f32tof16(float val)\n"
             "    {\n"
             "        uint f32 = floatBitsToUint(val);\n"
             "        uint f16 = 0u;\n"
             "        uint sign = (f32 >> 16) & 0x8000u;\n"
             "        int exponent = int((f32 >> 23) & 0xFFu) - 127;\n"
             "        uint mantissa = f32 & 0x007FFFFFu;\n"
@@ -212,17 +231,17 @@ void InitBuiltInFunctionEmulatorForGLSLM
             "    #if defined(GL_ARB_shading_language_packing)\n"
             "        return packHalf2x16(v);\n"
             "    #else\n"
             "        uint x = f32tof16(v.x);\n"
             "        uint y = f32tof16(v.y);\n"
             "        return (y << 16) | x;\n"
             "    #endif\n"
             "}\n");
-        emu->addEmulatedFunction(BuiltInId::unpackHalf2x16_UInt1,
+        emu->addEmulatedFunction(EOpUnpackHalf2x16, uint1,
             "#if !defined(GL_ARB_shading_language_packing)\n"
             "    float f16tof32(uint val)\n"
             "    {\n"
             "        uint sign = (val & 0x8000u) << 16;\n"
             "        int exponent = int((val & 0x7C00u) >> 10);\n"
             "        uint mantissa = val & 0x03FFu;\n"
             "        float f32 = 0.0;\n"
             "        if(exponent == 0)\n"
--- a/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/BuiltInFunctionEmulatorHLSL.cpp
@@ -1,131 +1,142 @@
 //
 // Copyright (c) 2014 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.
 //
 
-#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
 #include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulator.h"
+#include "compiler/translator/BuiltInFunctionEmulatorHLSL.h"
+#include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/VersionGLSL.h"
-#include "compiler/translator/tree_util/BuiltIn_autogen.h"
 
 namespace sh
 {
 
 // Defined in emulated_builtin_functions_hlsl_autogen.cpp.
-const char *FindHLSLFunction(int uniqueId);
+const char *FindHLSLFunction(const FunctionId &functionID);
 
 void InitBuiltInIsnanFunctionEmulatorForHLSLWorkarounds(BuiltInFunctionEmulator *emu,
                                                         int targetGLSLVersion)
 {
     if (targetGLSLVersion < GLSL_VERSION_130)
         return;
 
-    emu->addEmulatedFunction(BuiltInId::isnan_Float1,
+    TType *float1 = new TType(EbtFloat);
+    TType *float2 = new TType(EbtFloat, 2);
+    TType *float3 = new TType(EbtFloat, 3);
+    TType *float4 = new TType(EbtFloat, 4);
+
+    emu->addEmulatedFunction(EOpIsnan, float1,
                              "bool isnan_emu(float x)\n"
                              "{\n"
                              "    return (x > 0.0 || x < 0.0) ? false : x != 0.0;\n"
                              "}\n"
                              "\n");
 
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float2,
+        EOpIsnan, float2,
         "bool2 isnan_emu(float2 x)\n"
         "{\n"
         "    bool2 isnan;\n"
         "    for (int i = 0; i < 2; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
 
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float3,
+        EOpIsnan, float3,
         "bool3 isnan_emu(float3 x)\n"
         "{\n"
         "    bool3 isnan;\n"
         "    for (int i = 0; i < 3; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
 
     emu->addEmulatedFunction(
-        BuiltInId::isnan_Float4,
+        EOpIsnan, float4,
         "bool4 isnan_emu(float4 x)\n"
         "{\n"
         "    bool4 isnan;\n"
         "    for (int i = 0; i < 4; i++)\n"
         "    {\n"
         "        isnan[i] = (x[i] > 0.0 || x[i] < 0.0) ? false : x[i] != 0.0;\n"
         "    }\n"
         "    return isnan;\n"
         "}\n");
 }
 
 void InitBuiltInFunctionEmulatorForHLSL(BuiltInFunctionEmulator *emu)
 {
+    TType *int1   = new TType(EbtInt);
+    TType *int2   = new TType(EbtInt, 2);
+    TType *int3   = new TType(EbtInt, 3);
+    TType *int4   = new TType(EbtInt, 4);
+    TType *uint1  = new TType(EbtUInt);
+    TType *uint2  = new TType(EbtUInt, 2);
+    TType *uint3  = new TType(EbtUInt, 3);
+    TType *uint4  = new TType(EbtUInt, 4);
+
     emu->addFunctionMap(FindHLSLFunction);
 
     // (a + b2^16) * (c + d2^16) = ac + (ad + bc) * 2^16 + bd * 2^32
     // Also note that below, a * d + ((a * c) >> 16) is guaranteed not to overflow, because:
     // a <= 0xffff, d <= 0xffff, ((a * c) >> 16) <= 0xffff and 0xffff * 0xffff + 0xffff = 0xffff0000
-    emu->addEmulatedFunction(BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
-                             "void umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n"
-                             "{\n"
-                             "    lsb = x * y;\n"
-                             "    uint a = (x & 0xffffu);\n"
-                             "    uint b = (x >> 16);\n"
-                             "    uint c = (y & 0xffffu);\n"
-                             "    uint d = (y >> 16);\n"
-                             "    uint ad = a * d + ((a * c) >> 16);\n"
-                             "    uint bc = b * c;\n"
-                             "    uint carry = uint(ad > (0xffffffffu - bc));\n"
-                             "    msb = ((ad + bc) >> 16) + (carry << 16) + b * d;\n"
-                             "}\n");
+    FunctionId umulExtendedUint1 = emu->addEmulatedFunction(
+        EOpUmulExtended, uint1, uint1, uint1, uint1,
+        "void umulExtended_emu(uint x, uint y, out uint msb, out uint lsb)\n"
+        "{\n"
+        "    lsb = x * y;\n"
+        "    uint a = (x & 0xffffu);\n"
+        "    uint b = (x >> 16);\n"
+        "    uint c = (y & 0xffffu);\n"
+        "    uint d = (y >> 16);\n"
+        "    uint ad = a * d + ((a * c) >> 16);\n"
+        "    uint bc = b * c;\n"
+        "    uint carry = uint(ad > (0xffffffffu - bc));\n"
+        "    msb = ((ad + bc) >> 16) + (carry << 16) + b * d;\n"
+        "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
-        BuiltInId::umulExtended_UInt2_UInt2_UInt2_UInt2,
+        umulExtendedUint1, EOpUmulExtended, uint2, uint2, uint2, uint2,
         "void umulExtended_emu(uint2 x, uint2 y, out uint2 msb, out uint2 lsb)\n"
         "{\n"
         "    umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
-        BuiltInId::umulExtended_UInt3_UInt3_UInt3_UInt3,
+        umulExtendedUint1, EOpUmulExtended, uint3, uint3, uint3, uint3,
         "void umulExtended_emu(uint3 x, uint3 y, out uint3 msb, out uint3 lsb)\n"
         "{\n"
         "    umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "    umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
         "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
-        BuiltInId::umulExtended_UInt4_UInt4_UInt4_UInt4,
+        umulExtendedUint1, EOpUmulExtended, uint4, uint4, uint4, uint4,
         "void umulExtended_emu(uint4 x, uint4 y, out uint4 msb, out uint4 lsb)\n"
         "{\n"
         "    umulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    umulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "    umulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
         "    umulExtended_emu(x.w, y.w, msb.w, lsb.w);\n"
         "}\n");
 
     // The imul emulation does two's complement negation on the lsb and msb manually in case the
     // result needs to be negative.
     // TODO(oetuaho): Note that this code doesn't take one edge case into account, where x or y is
     // -2^31. abs(-2^31) is undefined.
-    emu->addEmulatedFunctionWithDependency(
-        BuiltInId::umulExtended_UInt1_UInt1_UInt1_UInt1,
-        BuiltInId::imulExtended_Int1_Int1_Int1_Int1,
+    FunctionId imulExtendedInt1 = emu->addEmulatedFunctionWithDependency(
+        umulExtendedUint1, EOpImulExtended, int1, int1, int1, int1,
         "void imulExtended_emu(int x, int y, out int msb, out int lsb)\n"
         "{\n"
         "    uint unsignedMsb;\n"
         "    uint unsignedLsb;\n"
         "    bool negative = (x < 0) != (y < 0);\n"
         "    umulExtended_emu(uint(abs(x)), uint(abs(y)), unsignedMsb, unsignedLsb);\n"
         "    lsb = asint(unsignedLsb);\n"
         "    msb = asint(unsignedMsb);\n"
@@ -140,32 +151,32 @@ void InitBuiltInFunctionEmulatorForHLSL(
         "        }\n"
         "        else\n"
         "        {\n"
         "            lsb += 1;\n"
         "        }\n"
         "    }\n"
         "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int2_Int2_Int2_Int2,
+        imulExtendedInt1, EOpImulExtended, int2, int2, int2, int2,
         "void imulExtended_emu(int2 x, int2 y, out int2 msb, out int2 lsb)\n"
         "{\n"
         "    imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int3_Int3_Int3_Int3,
+        imulExtendedInt1, EOpImulExtended, int3, int3, int3, int3,
         "void imulExtended_emu(int3 x, int3 y, out int3 msb, out int3 lsb)\n"
         "{\n"
         "    imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "    imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
         "}\n");
     emu->addEmulatedFunctionWithDependency(
-        BuiltInId::imulExtended_Int1_Int1_Int1_Int1, BuiltInId::imulExtended_Int4_Int4_Int4_Int4,
+        imulExtendedInt1, EOpImulExtended, int4, int4, int4, int4,
         "void imulExtended_emu(int4 x, int4 y, out int4 msb, out int4 lsb)\n"
         "{\n"
         "    imulExtended_emu(x.x, y.x, msb.x, lsb.x);\n"
         "    imulExtended_emu(x.y, y.y, msb.y, lsb.y);\n"
         "    imulExtended_emu(x.z, y.z, msb.z, lsb.z);\n"
         "    imulExtended_emu(x.w, y.w, msb.w, lsb.w);\n"
         "}\n");
 }
--- a/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/CallDAG.cpp
@@ -6,18 +6,18 @@
 
 // CallDAG.h: Implements a call graph DAG of functions to be re-used accross
 // analyses, allows to efficiently traverse the functions in topological
 // order.
 
 #include "compiler/translator/CallDAG.h"
 
 #include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
-#include "compiler/translator/tree_util/IntermTraverse.h"
 
 namespace sh
 {
 
 // The CallDAGCreator does all the processing required to create the CallDAG
 // structure so that the latter contains only the necessary variables.
 class CallDAG::CallDAGCreator : public TIntermTraverser
 {
@@ -111,23 +111,26 @@ class CallDAG::CallDAGCreator : public T
         mCurrentFunction->name           = node->getFunction()->name();
         mCurrentFunction->definitionNode = node;
 
         node->getBody()->traverse(this);
         mCurrentFunction = nullptr;
         return false;
     }
 
-    void visitFunctionPrototype(TIntermFunctionPrototype *node) override
+    bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override
     {
         ASSERT(mCurrentFunction == nullptr);
 
         // Function declaration, create an empty record.
         auto &record = mFunctions[node->getFunction()->uniqueId().get()];
         record.name  = node->getFunction()->name();
+
+        // No need to traverse the parameters.
+        return false;
     }
 
     // Track functions called from another function.
     bool visitAggregate(Visit visit, TIntermAggregate *node) override
     {
         if (node->getOp() == EOpCallFunctionInAST)
         {
             // Function call, add the callees
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ClampFragDepth.cpp
@@ -0,0 +1,54 @@
+//
+// 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.
+//
+// ClampFragDepth.cpp: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#include "compiler/translator/ClampFragDepth.h"
+
+#include "compiler/translator/FindSymbolNode.h"
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/RunAtTheEndOfShader.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable)
+{
+    // Only clamp gl_FragDepth if it's used in the shader.
+    if (!FindSymbolNode(root, ImmutableString("gl_FragDepth")))
+    {
+        return;
+    }
+
+    TIntermSymbol *fragDepthNode =
+        ReferenceBuiltInVariable(ImmutableString("gl_FragDepth"), *symbolTable, 300);
+
+    TIntermTyped *minFragDepthNode = CreateZeroNode(TType(EbtFloat, EbpHigh, EvqConst));
+
+    TConstantUnion *maxFragDepthConstant = new TConstantUnion();
+    maxFragDepthConstant->setFConst(1.0);
+    TIntermConstantUnion *maxFragDepthNode =
+        new TIntermConstantUnion(maxFragDepthConstant, TType(EbtFloat, EbpHigh, EvqConst));
+
+    // clamp(gl_FragDepth, 0.0, 1.0)
+    TIntermSequence *clampArguments = new TIntermSequence();
+    clampArguments->push_back(fragDepthNode->deepCopy());
+    clampArguments->push_back(minFragDepthNode);
+    clampArguments->push_back(maxFragDepthNode);
+    TIntermTyped *clampedFragDepth =
+        CreateBuiltInFunctionCallNode("clamp", clampArguments, *symbolTable, 100);
+
+    // gl_FragDepth = clamp(gl_FragDepth, 0.0, 1.0)
+    TIntermBinary *assignFragDepth = new TIntermBinary(EOpAssign, fragDepthNode, clampedFragDepth);
+
+    RunAtTheEndOfShader(root, assignFragDepth, symbolTable);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ClampFragDepth.h
@@ -0,0 +1,24 @@
+//
+// 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.
+//
+// ClampFragDepth.h: Limit the value that is written to gl_FragDepth to the range [0.0, 1.0].
+// The clamping is run at the very end of shader execution, and is only performed if the shader
+// statically accesses gl_FragDepth.
+//
+
+#ifndef COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
+#define COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ClampFragDepth(TIntermBlock *root, TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_CLAMPFRAGDEPTH_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ClampPointSize.cpp
@@ -0,0 +1,48 @@
+//
+// 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.
+//
+// ClampPointSize.cpp: Limit the value that is written to gl_PointSize.
+//
+
+#include "compiler/translator/ClampPointSize.h"
+
+#include "compiler/translator/FindSymbolNode.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/RunAtTheEndOfShader.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable)
+{
+    // Only clamp gl_PointSize if it's used in the shader.
+    if (!FindSymbolNode(root, ImmutableString("gl_PointSize")))
+    {
+        return;
+    }
+
+    TIntermSymbol *pointSizeNode =
+        ReferenceBuiltInVariable(ImmutableString("gl_PointSize"), *symbolTable, 100);
+
+    TConstantUnion *maxPointSizeConstant = new TConstantUnion();
+    maxPointSizeConstant->setFConst(maxPointSize);
+    TIntermConstantUnion *maxPointSizeNode =
+        new TIntermConstantUnion(maxPointSizeConstant, TType(EbtFloat, EbpHigh, EvqConst));
+
+    // min(gl_PointSize, maxPointSize)
+    TIntermSequence *minArguments = new TIntermSequence();
+    minArguments->push_back(pointSizeNode->deepCopy());
+    minArguments->push_back(maxPointSizeNode);
+    TIntermTyped *clampedPointSize =
+        CreateBuiltInFunctionCallNode("min", minArguments, *symbolTable, 100);
+
+    // gl_PointSize = min(gl_PointSize, maxPointSize)
+    TIntermBinary *assignPointSize = new TIntermBinary(EOpAssign, pointSizeNode, clampedPointSize);
+
+    RunAtTheEndOfShader(root, assignPointSize, symbolTable);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ClampPointSize.h
@@ -0,0 +1,22 @@
+//
+// 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.
+//
+// ClampPointSize.h: Limit the value that is written to gl_PointSize.
+//
+
+#ifndef COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_
+#define COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void ClampPointSize(TIntermBlock *root, float maxPointSize, TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_CLAMPPOINTSIZE_H_
--- a/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.cpp
@@ -5,18 +5,18 @@
 //
 // CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
 
 #include "compiler/translator/CollectVariables.h"
 
 #include "angle_gl.h"
 #include "common/utilities.h"
 #include "compiler/translator/HashNames.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
-#include "compiler/translator/tree_util/IntermTraverse.h"
 #include "compiler/translator/util.h"
 
 namespace sh
 {
 
 namespace
 {
 
@@ -63,46 +63,44 @@ VarT *FindVariable(const ImmutableString
     {
         if (name == (*infoList)[ii].name)
             return &((*infoList)[ii]);
     }
 
     return nullptr;
 }
 
-// Note that this shouldn't be called for interface blocks - active information is collected for
+// Note that this shouldn't be called for interface blocks - static use information is collected for
 // individual fields in case of interface blocks.
-void MarkActive(ShaderVariable *variable)
+void MarkStaticallyUsed(ShaderVariable *variable)
 {
-    if (!variable->active)
+    if (!variable->staticUse)
     {
         if (variable->isStruct())
         {
             // Conservatively assume all fields are statically used as well.
             for (auto &field : variable->fields)
             {
-                MarkActive(&field);
+                MarkStaticallyUsed(&field);
             }
         }
-        ASSERT(variable->staticUse);
-        variable->active    = true;
+        variable->staticUse = true;
     }
 }
 
 ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
                                              const TInterfaceBlock *interfaceBlock,
                                              std::vector<InterfaceBlock> *infoList)
 {
     ASSERT(interfaceBlock);
     InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
     ASSERT(namedBlock);
 
     // Set static use on the parent interface block here
     namedBlock->staticUse = true;
-    namedBlock->active    = true;
     return FindVariable(name, &namedBlock->fields);
 }
 
 // Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
 // and interface blocks.
 class CollectVariablesTraverser : public TIntermTraverser
 {
   public:
@@ -111,53 +109,50 @@ class CollectVariablesTraverser : public
                               std::vector<Uniform> *uniforms,
                               std::vector<Varying> *inputVaryings,
                               std::vector<Varying> *outputVaryings,
                               std::vector<InterfaceBlock> *uniformBlocks,
                               std::vector<InterfaceBlock> *shaderStorageBlocks,
                               std::vector<InterfaceBlock> *inBlocks,
                               ShHashFunction64 hashFunction,
                               TSymbolTable *symbolTable,
+                              int shaderVersion,
                               GLenum shaderType,
                               const TExtensionBehavior &extensionBehavior);
 
-    bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
     void visitSymbol(TIntermSymbol *symbol) override;
     bool visitDeclaration(Visit, TIntermDeclaration *node) override;
     bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
 
   private:
     std::string getMappedName(const TSymbol *symbol) const;
 
-    void setFieldOrVariableProperties(const TType &type,
-                                      bool staticUse,
-                                      ShaderVariable *variableOut) const;
+    void setFieldOrVariableProperties(const TType &type, ShaderVariable *variableOut) const;
     void setFieldProperties(const TType &type,
                             const ImmutableString &name,
-                            bool staticUse,
                             ShaderVariable *variableOut) const;
     void setCommonVariableProperties(const TType &type,
                                      const TVariable &variable,
                                      ShaderVariable *variableOut) const;
 
     Attribute recordAttribute(const TIntermSymbol &variable) const;
     OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
     Varying recordVarying(const TIntermSymbol &variable) const;
     void recordInterfaceBlock(const char *instanceName,
                               const TType &interfaceBlockType,
                               InterfaceBlock *interfaceBlock) const;
     Uniform recordUniform(const TIntermSymbol &variable) const;
 
-    void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
+    void setBuiltInInfoFromSymbolTable(const ImmutableString &name, ShaderVariable *info);
 
-    void recordBuiltInVaryingUsed(const TVariable &variable,
+    void recordBuiltInVaryingUsed(const ImmutableString &name,
                                   bool *addedFlag,
                                   std::vector<Varying> *varyings);
-    void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
-    void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
+    void recordBuiltInFragmentOutputUsed(const ImmutableString &name, bool *addedFlag);
+    void recordBuiltInAttributeUsed(const ImmutableString &name, bool *addedFlag);
     InterfaceBlock *recordGLInUsed(const TType &glInType);
     InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
 
     std::vector<Attribute> *mAttribs;
     std::vector<OutputVariable> *mOutputVariables;
     std::vector<Uniform> *mUniforms;
     std::vector<Varying> *mInputVaryings;
     std::vector<Varying> *mOutputVaryings;
@@ -196,31 +191,33 @@ class CollectVariablesTraverser : public
     bool mInvocationIDAdded;
 
     // Geometry Shader and Fragment Shader builtins
     bool mPrimitiveIDAdded;
     bool mLayerAdded;
 
     ShHashFunction64 mHashFunction;
 
+    int mShaderVersion;
     GLenum mShaderType;
     const TExtensionBehavior &mExtensionBehavior;
 };
 
 CollectVariablesTraverser::CollectVariablesTraverser(
     std::vector<sh::Attribute> *attribs,
     std::vector<sh::OutputVariable> *outputVariables,
     std::vector<sh::Uniform> *uniforms,
     std::vector<sh::Varying> *inputVaryings,
     std::vector<sh::Varying> *outputVaryings,
     std::vector<sh::InterfaceBlock> *uniformBlocks,
     std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
     std::vector<sh::InterfaceBlock> *inBlocks,
     ShHashFunction64 hashFunction,
     TSymbolTable *symbolTable,
+    int shaderVersion,
     GLenum shaderType,
     const TExtensionBehavior &extensionBehavior)
     : TIntermTraverser(true, false, false, symbolTable),
       mAttribs(attribs),
       mOutputVariables(outputVariables),
       mUniforms(uniforms),
       mInputVaryings(inputVaryings),
       mOutputVaryings(outputVaryings),
@@ -243,116 +240,112 @@ CollectVariablesTraverser::CollectVariab
       mSecondaryFragColorEXTAdded(false),
       mSecondaryFragDataEXTAdded(false),
       mPerVertexInAdded(false),
       mPrimitiveIDInAdded(false),
       mInvocationIDAdded(false),
       mPrimitiveIDAdded(false),
       mLayerAdded(false),
       mHashFunction(hashFunction),
+      mShaderVersion(shaderVersion),
       mShaderType(shaderType),
       mExtensionBehavior(extensionBehavior)
 {
 }
 
 std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
 {
     return HashName(symbol, mHashFunction, nullptr).data();
 }
 
-void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
-                                                         ShaderVariable *info)
+void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const ImmutableString &name,
+                                                              ShaderVariable *info)
 {
-    const TType &type = variable.getType();
+    const TVariable *symbolTableVar =
+        reinterpret_cast<const TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
+    ASSERT(symbolTableVar);
+    const TType &type = symbolTableVar->getType();
 
-    info->name       = variable.name().data();
-    info->mappedName = variable.name().data();
+    info->name       = name.data();
+    info->mappedName = name.data();
     info->type       = GLVariableType(type);
     info->precision = GLVariablePrecision(type);
     if (auto *arraySizes = type.getArraySizes())
     {
         info->arraySizes.assign(arraySizes->begin(), arraySizes->end());
     }
 }
 
-void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
+void CollectVariablesTraverser::recordBuiltInVaryingUsed(const ImmutableString &name,
                                                          bool *addedFlag,
                                                          std::vector<Varying> *varyings)
 {
     ASSERT(varyings);
     if (!(*addedFlag))
     {
         Varying info;
-        setBuiltInInfoFromSymbol(variable, &info);
+        setBuiltInInfoFromSymbolTable(name, &info);
         info.staticUse   = true;
-        info.active      = true;
-        info.isInvariant = mSymbolTable->isVaryingInvariant(variable.name());
+        info.isInvariant = mSymbolTable->isVaryingInvariant(name);
         varyings->push_back(info);
         (*addedFlag) = true;
     }
 }
 
-void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
+void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const ImmutableString &name,
                                                                 bool *addedFlag)
 {
     if (!(*addedFlag))
     {
         OutputVariable info;
-        setBuiltInInfoFromSymbol(variable, &info);
+        setBuiltInInfoFromSymbolTable(name, &info);
         info.staticUse = true;
-        info.active    = true;
         mOutputVariables->push_back(info);
         (*addedFlag) = true;
     }
 }
 
-void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
+void CollectVariablesTraverser::recordBuiltInAttributeUsed(const ImmutableString &name,
                                                            bool *addedFlag)
 {
     if (!(*addedFlag))
     {
         Attribute info;
-        setBuiltInInfoFromSymbol(variable, &info);
+        setBuiltInInfoFromSymbolTable(name, &info);
         info.staticUse = true;
-        info.active    = true;
         info.location  = -1;
         mAttribs->push_back(info);
         (*addedFlag) = true;
     }
 }
 
 InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
 {
     if (!mPerVertexInAdded)
     {
         ASSERT(glInType.getQualifier() == EvqPerVertexIn);
         InterfaceBlock info;
         recordInterfaceBlock("gl_in", glInType, &info);
+        info.staticUse = true;
 
         mPerVertexInAdded = true;
         mInBlocks->push_back(info);
         return &mInBlocks->back();
     }
     else
     {
         return FindVariable(ImmutableString("gl_PerVertex"), mInBlocks);
     }
 }
 
-bool CollectVariablesTraverser::visitInvariantDeclaration(Visit visit,
-                                                          TIntermInvariantDeclaration *node)
-{
-    // We should not mark variables as active just based on an invariant declaration, so we don't
-    // traverse the symbols declared invariant.
-    return false;
-}
-
-// We want to check whether a uniform/varying is active because we need to skip updating inactive
-// ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
-// and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
+// We want to check whether a uniform/varying is statically used
+// because we only count the used ones in packing computing.
+// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
+// toward varying counting if they are statically used in a fragment
+// shader.
 void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
 {
     ASSERT(symbol != nullptr);
 
     if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
         symbol->variable().symbolType() == SymbolType::Empty)
     {
         // Internal variables or nameless variables are not collected.
@@ -387,41 +380,37 @@ void CollectVariablesTraverser::visitSym
         {
             Uniform info;
             const char kName[] = "gl_DepthRange";
             info.name          = kName;
             info.mappedName    = kName;
             info.type          = GL_NONE;
             info.precision     = GL_NONE;
             info.staticUse     = true;
-            info.active        = true;
 
             ShaderVariable nearInfo(GL_FLOAT);
             const char kNearName[] = "near";
             nearInfo.name          = kNearName;
             nearInfo.mappedName    = kNearName;
             nearInfo.precision     = GL_HIGH_FLOAT;
             nearInfo.staticUse     = true;
-            nearInfo.active        = true;
 
             ShaderVariable farInfo(GL_FLOAT);
             const char kFarName[] = "far";
             farInfo.name          = kFarName;
             farInfo.mappedName    = kFarName;
             farInfo.precision     = GL_HIGH_FLOAT;
             farInfo.staticUse     = true;
-            farInfo.active        = true;
 
             ShaderVariable diffInfo(GL_FLOAT);
             const char kDiffName[] = "diff";
             diffInfo.name          = kDiffName;
             diffInfo.mappedName    = kDiffName;
             diffInfo.precision     = GL_HIGH_FLOAT;
             diffInfo.staticUse     = true;
-            diffInfo.active        = true;
 
             info.fields.push_back(nearInfo);
             info.fields.push_back(farInfo);
             info.fields.push_back(diffInfo);
 
             mUniforms->push_back(info);
             mDepthRangeAdded = true;
         }
@@ -456,126 +445,148 @@ void CollectVariablesTraverser::visitSym
             case EvqBuffer:
             {
                 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
                 var =
                     FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
             }
             break;
             case EvqFragCoord:
-                recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_FragCoord"), &mFragCoordAdded,
+                                         mInputVaryings);
                 return;
             case EvqFrontFacing:
-                recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_FrontFacing"), &mFrontFacingAdded,
+                                         mInputVaryings);
                 return;
             case EvqPointCoord:
-                recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_PointCoord"), &mPointCoordAdded,
+                                         mInputVaryings);
                 return;
             case EvqInstanceID:
                 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
                 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
-                // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
-                // shaders.
-                recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
+                // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
+                // which makes it necessary to populate the type information explicitly instead of
+                // extracting it from the symbol table.
+                if (!mInstanceIDAdded)
+                {
+                    Attribute info;
+                    const char kName[] = "gl_InstanceID";
+                    info.name          = kName;
+                    info.mappedName    = kName;
+                    info.type          = GL_INT;
+                    info.precision     = GL_HIGH_INT;  // Defined by spec.
+                    info.staticUse     = true;
+                    info.location      = -1;
+                    mAttribs->push_back(info);
+                    mInstanceIDAdded = true;
+                }
                 return;
             case EvqVertexID:
-                recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
+                recordBuiltInAttributeUsed(ImmutableString("gl_VertexID"), &mVertexIDAdded);
                 return;
             case EvqPosition:
-                recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_Position"), &mPositionAdded,
+                                         mOutputVaryings);
                 return;
             case EvqPointSize:
-                recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_PointSize"), &mPointSizeAdded,
+                                         mOutputVaryings);
                 return;
             case EvqLastFragData:
-                recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_LastFragData"), &mLastFragDataAdded,
+                                         mInputVaryings);
                 return;
             case EvqFragColor:
-                recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
+                recordBuiltInFragmentOutputUsed(ImmutableString("gl_FragColor"), &mFragColorAdded);
                 return;
             case EvqFragData:
                 if (!mFragDataAdded)
                 {
                     OutputVariable info;
-                    setBuiltInInfoFromSymbol(symbol->variable(), &info);
+                    setBuiltInInfoFromSymbolTable(ImmutableString("gl_FragData"), &info);
                     if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
                     {
                         ASSERT(info.arraySizes.size() == 1u);
                         info.arraySizes.back() = 1u;
                     }
                     info.staticUse = true;
-                    info.active    = true;
                     mOutputVariables->push_back(info);
                     mFragDataAdded = true;
                 }
                 return;
             case EvqFragDepthEXT:
-                recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthEXTAdded);
+                recordBuiltInFragmentOutputUsed(ImmutableString("gl_FragDepthEXT"),
+                                                &mFragDepthEXTAdded);
                 return;
             case EvqFragDepth:
-                recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
+                recordBuiltInFragmentOutputUsed(ImmutableString("gl_FragDepth"), &mFragDepthAdded);
                 return;
             case EvqSecondaryFragColorEXT:
-                recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
+                recordBuiltInFragmentOutputUsed(ImmutableString("gl_SecondaryFragColorEXT"),
+                                                &mSecondaryFragColorEXTAdded);
                 return;
             case EvqSecondaryFragDataEXT:
-                recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
+                recordBuiltInFragmentOutputUsed(ImmutableString("gl_SecondaryFragDataEXT"),
+                                                &mSecondaryFragDataEXTAdded);
                 return;
             case EvqInvocationID:
-                recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_InvocationID"), &mInvocationIDAdded,
+                                         mInputVaryings);
                 break;
             case EvqPrimitiveIDIn:
-                recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
+                recordBuiltInVaryingUsed(ImmutableString("gl_PrimitiveIDIn"), &mPrimitiveIDInAdded,
+                                         mInputVaryings);
                 break;
             case EvqPrimitiveID:
                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
                 {
-                    recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
+                    recordBuiltInVaryingUsed(ImmutableString("gl_PrimitiveID"), &mPrimitiveIDAdded,
                                              mOutputVaryings);
                 }
                 else
                 {
                     ASSERT(mShaderType == GL_FRAGMENT_SHADER);
-                    recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
+                    recordBuiltInVaryingUsed(ImmutableString("gl_PrimitiveID"), &mPrimitiveIDAdded,
                                              mInputVaryings);
                 }
                 break;
             case EvqLayer:
                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
                 {
-                    recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
+                    recordBuiltInVaryingUsed(ImmutableString("gl_Layer"), &mLayerAdded,
+                                             mOutputVaryings);
                 }
                 else if (mShaderType == GL_FRAGMENT_SHADER)
                 {
-                    recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
+                    recordBuiltInVaryingUsed(ImmutableString("gl_Layer"), &mLayerAdded,
+                                             mInputVaryings);
                 }
                 else
                 {
                     ASSERT(mShaderType == GL_VERTEX_SHADER &&
                            IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview));
                 }
                 break;
             default:
                 break;
         }
     }
     if (var)
     {
-        MarkActive(var);
+        MarkStaticallyUsed(var);
     }
 }
 
 void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
-                                                             bool staticUse,
                                                              ShaderVariable *variableOut) const
 {
     ASSERT(variableOut);
 
-    variableOut->staticUse = staticUse;
-
     const TStructure *structure = type.getStruct();
     if (!structure)
     {
         variableOut->type      = GLVariableType(type);
         variableOut->precision = GLVariablePrecision(type);
     }
     else
     {
@@ -588,45 +599,43 @@ void CollectVariablesTraverser::setField
 
         const TFieldList &fields = structure->fields();
 
         for (const TField *field : fields)
         {
             // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
             // ShaderVariable objects.
             ShaderVariable fieldVariable;
-            setFieldProperties(*field->type(), field->name(), staticUse, &fieldVariable);
+            setFieldProperties(*field->type(), field->name(), &fieldVariable);
             variableOut->fields.push_back(fieldVariable);
         }
     }
     if (auto *arraySizes = type.getArraySizes())
     {
         variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
     }
 }
 
 void CollectVariablesTraverser::setFieldProperties(const TType &type,
                                                    const ImmutableString &name,
-                                                   bool staticUse,
                                                    ShaderVariable *variableOut) const
 {
     ASSERT(variableOut);
-    setFieldOrVariableProperties(type, staticUse, variableOut);
+    setFieldOrVariableProperties(type, variableOut);
     variableOut->name.assign(name.data(), name.length());
     variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
 }
 
 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
                                                             const TVariable &variable,
                                                             ShaderVariable *variableOut) const
 {
     ASSERT(variableOut);
 
-    variableOut->staticUse = mSymbolTable->isStaticallyUsed(variable);
-    setFieldOrVariableProperties(type, variableOut->staticUse, variableOut);
+    setFieldOrVariableProperties(type, variableOut);
     ASSERT(variable.symbolType() != SymbolType::Empty);
     variableOut->name.assign(variable.name().data(), variable.name().length());
     variableOut->mappedName = getMappedName(&variable);
 }
 
 Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
 {
     const TType &type = variable.getType();
@@ -692,73 +701,41 @@ void CollectVariablesTraverser::recordIn
     const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
     ASSERT(blockType);
 
     interfaceBlock->name       = blockType->name().data();
     interfaceBlock->mappedName = getMappedName(blockType);
     if (instanceName != nullptr)
     {
         interfaceBlock->instanceName = instanceName;
-        const TSymbol *blockSymbol   = nullptr;
-        if (strncmp(instanceName, "gl_in", 5u) == 0)
-        {
-            blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
-        }
-        else
-        {
-            blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
-        }
-        ASSERT(blockSymbol && blockSymbol->isVariable());
-        interfaceBlock->staticUse =
-            mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
     }
     ASSERT(!interfaceBlockType.isArrayOfArrays());  // Disallowed by GLSL ES 3.10 section 4.3.9
     interfaceBlock->arraySize = interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
 
     interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
     if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
         interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
     {
         // TODO(oetuaho): Remove setting isRowMajorLayout.
         interfaceBlock->isRowMajorLayout = false;
         interfaceBlock->binding          = blockType->blockBinding();
         interfaceBlock->layout           = GetBlockLayoutType(blockType->blockStorage());
     }
 
     // Gather field information
-    bool anyFieldStaticallyUsed = false;
     for (const TField *field : blockType->fields())
     {
         const TType &fieldType = *field->type();
 
-        bool staticUse = false;
-        if (instanceName == nullptr)
-        {
-            // Static use of individual fields has been recorded, since they are present in the
-            // symbol table as variables.
-            const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
-            ASSERT(fieldSymbol && fieldSymbol->isVariable());
-            staticUse =
-                mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
-            if (staticUse)
-            {
-                anyFieldStaticallyUsed = true;
-            }
-        }
-
         InterfaceBlockField fieldVariable;
-        setFieldProperties(fieldType, field->name(), staticUse, &fieldVariable);
+        setFieldProperties(fieldType, field->name(), &fieldVariable);
         fieldVariable.isRowMajorLayout =
             (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
         interfaceBlock->fields.push_back(fieldVariable);
     }
-    if (anyFieldStaticallyUsed)
-    {
-        interfaceBlock->staticUse = true;
-    }
 }
 
 Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
 {
     Uniform uniform;
     setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
     uniform.binding  = variable.getType().getLayoutQualifier().binding;
     uniform.location = variable.getType().getLayoutQualifier().location;
@@ -866,17 +843,17 @@ InterfaceBlock *CollectVariablesTraverse
     }
     return namedBlock;
 }
 
 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
 {
     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
     {
-        // NOTE: we do not determine static use / activeness for individual blocks of an array.
+        // NOTE: we do not determine static use for individual blocks of an array
         TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
         ASSERT(blockNode);
 
         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
         ASSERT(constantUnion);
 
         InterfaceBlock *namedBlock = nullptr;
 
@@ -900,25 +877,20 @@ bool CollectVariablesTraverser::visitBin
         }
 
         const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
         if (!namedBlock)
         {
             namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
         }
         ASSERT(namedBlock);
-        ASSERT(namedBlock->staticUse);
-        namedBlock->active      = true;
+        namedBlock->staticUse   = true;
         unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
         ASSERT(fieldIndex < namedBlock->fields.size());
-        // TODO(oetuaho): Would be nicer to record static use of fields of named interface blocks
-        // more accurately at parse time - now we only mark the fields statically used if they are
-        // active. http://anglebug.com/2440
         namedBlock->fields[fieldIndex].staticUse = true;
-        namedBlock->fields[fieldIndex].active    = true;
 
         if (traverseIndexExpression)
         {
             ASSERT(interfaceIndexingNode);
             interfaceIndexingNode->getRight()->traverse(this);
         }
         return false;
     }
@@ -934,18 +906,20 @@ void CollectVariables(TIntermBlock *root
                       std::vector<Uniform> *uniforms,
                       std::vector<Varying> *inputVaryings,
                       std::vector<Varying> *outputVaryings,
                       std::vector<InterfaceBlock> *uniformBlocks,
                       std::vector<InterfaceBlock> *shaderStorageBlocks,
                       std::vector<InterfaceBlock> *inBlocks,
                       ShHashFunction64 hashFunction,
                       TSymbolTable *symbolTable,
+                      int shaderVersion,
                       GLenum shaderType,
                       const TExtensionBehavior &extensionBehavior)
 {
     CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
                                       outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
-                                      hashFunction, symbolTable, shaderType, extensionBehavior);
+                                      hashFunction, symbolTable, shaderVersion, shaderType,
+                                      extensionBehavior);
     root->traverse(&collect);
 }
 
 }  // namespace sh
--- a/gfx/angle/checkout/src/compiler/translator/CollectVariables.h
+++ b/gfx/angle/checkout/src/compiler/translator/CollectVariables.h
@@ -24,13 +24,14 @@ void CollectVariables(TIntermBlock *root
                       std::vector<Uniform> *uniforms,
                       std::vector<Varying> *inputVaryings,
                       std::vector<Varying> *outputVaryings,
                       std::vector<InterfaceBlock> *uniformBlocks,
                       std::vector<InterfaceBlock> *shaderStorageBlocks,
                       std::vector<InterfaceBlock> *inBlocks,
                       ShHashFunction64 hashFunction,
                       TSymbolTable *symbolTable,
+                      int shaderVersion,
                       GLenum shaderType,
                       const TExtensionBehavior &extensionBehavior);
 }
 
 #endif  // COMPILER_TRANSLATOR_COLLECTVARIABLES_H_
--- a/gfx/angle/checkout/src/compiler/translator/Compiler.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/Compiler.cpp
@@ -5,53 +5,53 @@
 //
 
 #include "compiler/translator/Compiler.h"
 
 #include <sstream>
 
 #include "angle_gl.h"
 #include "common/utilities.h"
+#include "compiler/translator/AddAndTrueToLoopCondition.h"
 #include "compiler/translator/CallDAG.h"
+#include "compiler/translator/ClampFragDepth.h"
+#include "compiler/translator/ClampPointSize.h"
 #include "compiler/translator/CollectVariables.h"
+#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h"
+#include "compiler/translator/DeferGlobalInitializers.h"
+#include "compiler/translator/EmulateGLFragColorBroadcast.h"
+#include "compiler/translator/EmulatePrecision.h"
+#include "compiler/translator/FoldExpressions.h"
 #include "compiler/translator/Initialize.h"
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/IntermNodePatternMatcher.h"
 #include "compiler/translator/IsASTDepthBelowLimit.h"
 #include "compiler/translator/OutputTree.h"
 #include "compiler/translator/ParseContext.h"
+#include "compiler/translator/PruneNoOps.h"
+#include "compiler/translator/RegenerateStructNames.h"
+#include "compiler/translator/RemoveArrayLengthMethod.h"
+#include "compiler/translator/RemoveEmptySwitchStatements.h"
+#include "compiler/translator/RemoveInvariantDeclaration.h"
+#include "compiler/translator/RemoveNoOpCasesFromEndOfSwitchStatements.h"
+#include "compiler/translator/RemovePow.h"
+#include "compiler/translator/RemoveUnreferencedVariables.h"
+#include "compiler/translator/RewriteDoWhile.h"
+#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
+#include "compiler/translator/SeparateDeclarations.h"
+#include "compiler/translator/SimplifyLoopConditions.h"
+#include "compiler/translator/SplitSequenceOperator.h"
+#include "compiler/translator/UnfoldShortCircuitAST.h"
+#include "compiler/translator/UseInterfaceBlockFields.h"
 #include "compiler/translator/ValidateLimitations.h"
 #include "compiler/translator/ValidateMaxParameters.h"
 #include "compiler/translator/ValidateOutputs.h"
 #include "compiler/translator/ValidateVaryingLocations.h"
 #include "compiler/translator/VariablePacker.h"
-#include "compiler/translator/tree_ops/AddAndTrueToLoopCondition.h"
-#include "compiler/translator/tree_ops/ClampFragDepth.h"
-#include "compiler/translator/tree_ops/ClampPointSize.h"
-#include "compiler/translator/tree_ops/DeclareAndInitBuiltinsForInstancedMultiview.h"
-#include "compiler/translator/tree_ops/DeferGlobalInitializers.h"
-#include "compiler/translator/tree_ops/EmulateGLFragColorBroadcast.h"
-#include "compiler/translator/tree_ops/EmulatePrecision.h"
-#include "compiler/translator/tree_ops/FoldExpressions.h"
-#include "compiler/translator/tree_ops/InitializeVariables.h"
-#include "compiler/translator/tree_ops/PruneEmptyCases.h"
-#include "compiler/translator/tree_ops/PruneNoOps.h"
-#include "compiler/translator/tree_ops/RegenerateStructNames.h"
-#include "compiler/translator/tree_ops/RemoveArrayLengthMethod.h"
-#include "compiler/translator/tree_ops/RemoveInvariantDeclaration.h"
-#include "compiler/translator/tree_ops/RemovePow.h"
-#include "compiler/translator/tree_ops/RemoveUnreferencedVariables.h"
-#include "compiler/translator/tree_ops/RewriteDoWhile.h"
-#include "compiler/translator/tree_ops/ScalarizeVecAndMatConstructorArgs.h"
-#include "compiler/translator/tree_ops/SeparateDeclarations.h"
-#include "compiler/translator/tree_ops/SimplifyLoopConditions.h"
-#include "compiler/translator/tree_ops/SplitSequenceOperator.h"
-#include "compiler/translator/tree_ops/UnfoldShortCircuitAST.h"
-#include "compiler/translator/tree_ops/UseInterfaceBlockFields.h"
-#include "compiler/translator/tree_ops/VectorizeVectorScalarArithmetic.h"
-#include "compiler/translator/tree_util/BuiltIn_autogen.h"
-#include "compiler/translator/tree_util/IntermNodePatternMatcher.h"
+#include "compiler/translator/VectorizeVectorScalarArithmetic.h"
 #include "compiler/translator/util.h"
 #include "third_party/compiler/ArrayBoundsClamper.h"
 
 namespace sh
 {
 
 namespace
 {
@@ -188,22 +188,22 @@ class TScopedPoolAllocator
     TPoolAllocator *mAllocator;
 };
 
 class TScopedSymbolTableLevel
 {
   public:
     TScopedSymbolTableLevel(TSymbolTable *table) : mTable(table)
     {
-        ASSERT(mTable->isEmpty());
+        ASSERT(mTable->atBuiltInLevel());
         mTable->push();
     }
     ~TScopedSymbolTableLevel()
     {
-        while (!mTable->isEmpty())
+        while (!mTable->atBuiltInLevel())
             mTable->pop();
     }
 
   private:
     TSymbolTable *mTable;
 };
 
 int MapSpecToShaderVersion(ShShaderSpec spec)
@@ -220,61 +220,16 @@ int MapSpecToShaderVersion(ShShaderSpec 
         case SH_WEBGL3_SPEC:
             return 310;
         default:
             UNREACHABLE();
             return 0;
     }
 }
 
-bool ValidateFragColorAndFragData(GLenum shaderType,
-                                  int shaderVersion,
-                                  const TSymbolTable &symbolTable,
-                                  TDiagnostics *diagnostics)
-{
-    if (shaderVersion > 100 || shaderType != GL_FRAGMENT_SHADER)
-    {
-        return true;
-    }
-
-    bool usesFragColor = false;
-    bool usesFragData  = false;
-    // This validation is a bit stricter than the spec - it's only an error to write to
-    // both FragData and FragColor. But because it's better not to have reads from undefined
-    // variables, we always return an error if they are both referenced, rather than only if they
-    // are written.
-    if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_FragColor()) ||
-        symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()))
-    {
-        usesFragColor = true;
-    }
-    // Extension variables may not always be initialized (saves some time at symbol table init).
-    bool secondaryFragDataUsed =
-        symbolTable.gl_SecondaryFragDataEXT() != nullptr &&
-        symbolTable.isStaticallyUsed(*symbolTable.gl_SecondaryFragDataEXT());
-    if (symbolTable.isStaticallyUsed(*symbolTable.gl_FragData()) || secondaryFragDataUsed)
-    {
-        usesFragData = true;
-    }
-    if (usesFragColor && usesFragData)
-    {
-        const char *errorMessage = "cannot use both gl_FragData and gl_FragColor";
-        if (symbolTable.isStaticallyUsed(*BuiltInVariable::gl_SecondaryFragColorEXT()) ||
-            secondaryFragDataUsed)
-        {
-            errorMessage =
-                "cannot use both output variable sets (gl_FragData, gl_SecondaryFragDataEXT)"
-                " and (gl_FragColor, gl_SecondaryFragColorEXT)";
-        }
-        diagnostics->globalError(errorMessage);
-        return false;
-    }
-    return true;
-}
-
 }  // namespace
 
 TShHandleBase::TShHandleBase()
 {
     allocator.push();
     SetGlobalPoolAllocator(&allocator);
 }
 
@@ -491,36 +446,41 @@ bool TCompiler::checkAndSimplifyAST(TInt
     }
 
     if (shouldRunLoopAndIndexingValidation(compileOptions) &&
         !ValidateLimitations(root, shaderType, &symbolTable, &mDiagnostics))
     {
         return false;
     }
 
-    if (!ValidateFragColorAndFragData(shaderType, shaderVersion, symbolTable, &mDiagnostics))
-    {
-        return false;
-    }
-
     // Fold expressions that could not be folded before validation that was done as a part of
     // parsing.
     FoldExpressions(root, &mDiagnostics);
     // Folding should only be able to generate warnings.
     ASSERT(mDiagnostics.numErrors() == 0);
 
     // We prune no-ops to work around driver bugs and to keep AST processing and output simple.
     // The following kinds of no-ops are pruned:
     //   1. Empty declarations "int;".
     //   2. Literal statements: "1.0;". The ESSL output doesn't define a default precision
     //      for float, so float literal statements would end up with no precision which is
     //      invalid ESSL.
     // After this empty declarations are not allowed in the AST.
     PruneNoOps(root, &symbolTable);
 
+    // In case the last case inside a switch statement is a certain type of no-op, GLSL
+    // compilers in drivers may not accept it. In this case we clean up the dead code from the
+    // end of switch statements. This is also required because PruneNoOps may have left switch
+    // statements that only contained an empty declaration inside the final case in an invalid
+    // state. Relies on that PruneNoOps has already been run.
+    RemoveNoOpCasesFromEndOfSwitchStatements(root, &symbolTable);
+
+    // Remove empty switch statements - this makes output simpler.
+    RemoveEmptySwitchStatements(root);
+
     // Create the function DAG and check there is no recursion
     if (!initCallDag(root))
     {
         return false;
     }
 
     if ((compileOptions & SH_LIMIT_CALL_STACK_DEPTH) && !checkCallDepth())
     {
@@ -583,17 +543,17 @@ bool TCompiler::checkAndSimplifyAST(TInt
 
     if (compileOptions & SH_UNFOLD_SHORT_CIRCUIT)
     {
         UnfoldShortCircuitAST(root);
     }
 
     if (compileOptions & SH_REMOVE_POW_WITH_CONSTANT_EXPONENT)
     {
-        RemovePow(root, &symbolTable);
+        RemovePow(root);
     }
 
     if (compileOptions & SH_REGENERATE_STRUCT_NAMES)
     {
         RegenerateStructNames gen(&symbolTable);
         root->traverse(&gen);
     }
 
@@ -623,24 +583,16 @@ bool TCompiler::checkAndSimplifyAST(TInt
 
     SplitSequenceOperator(root, IntermNodePatternMatcher::kArrayLengthMethod | simplifyScalarized,
                           &getSymbolTable());
 
     RemoveArrayLengthMethod(root);
 
     RemoveUnreferencedVariables(root, &symbolTable);
 
-    // In case the last case inside a switch statement is a certain type of no-op, GLSL compilers in
-    // drivers may not accept it. In this case we clean up the dead code from the end of switch
-    // statements. This is also required because PruneNoOps or RemoveUnreferencedVariables may have
-    // left switch statements that only contained an empty declaration inside the final case in an
-    // invalid state. Relies on that PruneNoOps and RemoveUnreferencedVariables have already been
-    // run.
-    PruneEmptyCases(root);
-
     // Built-in function emulation needs to happen after validateLimitations pass.
     // TODO(jmadill): Remove global pool allocator.
     GetGlobalPoolAllocator()->lock();
     initBuiltInFunctionEmulator(&builtInFunctionEmulator, compileOptions);
     GetGlobalPoolAllocator()->unlock();
     builtInFunctionEmulator.markBuiltInFunctionsForEmulation(root);
 
     if (compileOptions & SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS)
@@ -648,17 +600,17 @@ bool TCompiler::checkAndSimplifyAST(TInt
         ScalarizeVecAndMatConstructorArgs(root, shaderType, fragmentPrecisionHigh, &symbolTable);
     }
 
     if (shouldCollectVariables(compileOptions))
     {
         ASSERT(!variablesCollected);
         CollectVariables(root, &attributes, &outputVariables, &uniforms, &inputVaryings,
                          &outputVaryings, &uniformBlocks, &shaderStorageBlocks, &inBlocks,
-                         hashFunction, &symbolTable, shaderType, extensionBehavior);
+                         hashFunction, &symbolTable, shaderVersion, shaderType, extensionBehavior);
         collectInterfaceBlocks();
         variablesCollected = true;
         if (compileOptions & SH_USE_UNUSED_STANDARD_SHARED_BLOCKS)
         {
             useAllMembersInUnusedStandardAndSharedBlocks(root);
         }
         if (compileOptions & SH_ENFORCE_PACKING_RESTRICTIONS)
         {
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -0,0 +1,210 @@
+//
+// 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.
+//
+// Applies the necessary AST transformations to support multiview rendering through instancing.
+// Check the header file For more information.
+//
+
+#include "compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h"
+
+#include "compiler/translator/FindMain.h"
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/ReplaceVariable.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kGlLayerString("gl_Layer");
+constexpr const ImmutableString kGlViewportIndexString("gl_ViewportIndex");
+constexpr const ImmutableString kGlViewIdOVRString("gl_ViewID_OVR");
+constexpr const ImmutableString kGlInstanceIdString("gl_InstanceID");
+constexpr const ImmutableString kViewIDVariableName("ViewID_OVR");
+constexpr const ImmutableString kInstanceIDVariableName("InstanceID");
+constexpr const ImmutableString kMultiviewBaseViewLayerIndexVariableName(
+    "multiviewBaseViewLayerIndex");
+
+TIntermSymbol *CreateGLInstanceIDSymbol(const TSymbolTable &symbolTable)
+{
+    return ReferenceBuiltInVariable(kGlInstanceIdString, symbolTable, 300);
+}
+
+// Adds the InstanceID and ViewID_OVR initializers to the end of the initializers' sequence.
+void InitializeViewIDAndInstanceID(const TVariable *viewID,
+                                   const TVariable *instanceID,
+                                   unsigned numberOfViews,
+                                   const TSymbolTable &symbolTable,
+                                   TIntermSequence *initializers)
+{
+    // Create an unsigned numberOfViews node.
+    TConstantUnion *numberOfViewsUnsignedConstant = new TConstantUnion();
+    numberOfViewsUnsignedConstant->setUConst(numberOfViews);
+    TIntermConstantUnion *numberOfViewsUint =
+        new TIntermConstantUnion(numberOfViewsUnsignedConstant, TType(EbtUInt, EbpHigh, EvqConst));
+
+    // Create a uint(gl_InstanceID) node.
+    TIntermSequence *glInstanceIDSymbolCastArguments = new TIntermSequence();
+    glInstanceIDSymbolCastArguments->push_back(CreateGLInstanceIDSymbol(symbolTable));
+    TIntermAggregate *glInstanceIDAsUint = TIntermAggregate::CreateConstructor(
+        TType(EbtUInt, EbpHigh, EvqTemporary), glInstanceIDSymbolCastArguments);
+
+    // Create a uint(gl_InstanceID) / numberOfViews node.
+    TIntermBinary *normalizedInstanceID =
+        new TIntermBinary(EOpDiv, glInstanceIDAsUint, numberOfViewsUint);
+
+    // Create an int(uint(gl_InstanceID) / numberOfViews) node.
+    TIntermSequence *normalizedInstanceIDCastArguments = new TIntermSequence();
+    normalizedInstanceIDCastArguments->push_back(normalizedInstanceID);
+    TIntermAggregate *normalizedInstanceIDAsInt = TIntermAggregate::CreateConstructor(
+        TType(EbtInt, EbpHigh, EvqTemporary), normalizedInstanceIDCastArguments);
+
+    // Create an InstanceID = int(uint(gl_InstanceID) / numberOfViews) node.
+    TIntermBinary *instanceIDInitializer =
+        new TIntermBinary(EOpAssign, new TIntermSymbol(instanceID), normalizedInstanceIDAsInt);
+    initializers->push_back(instanceIDInitializer);
+
+    // Create a uint(gl_InstanceID) % numberOfViews node.
+    TIntermBinary *normalizedViewID =
+        new TIntermBinary(EOpIMod, glInstanceIDAsUint->deepCopy(), numberOfViewsUint->deepCopy());
+
+    // Create a ViewID_OVR = uint(gl_InstanceID) % numberOfViews node.
+    TIntermBinary *viewIDInitializer =
+        new TIntermBinary(EOpAssign, new TIntermSymbol(viewID), normalizedViewID);
+    initializers->push_back(viewIDInitializer);
+}
+
+void DeclareGlobalVariable(TIntermBlock *root, const TVariable *variable)
+{
+    TIntermDeclaration *declaration = new TIntermDeclaration();
+    declaration->appendDeclarator(new TIntermSymbol(variable));
+
+    TIntermSequence *globalSequence = root->getSequence();
+    globalSequence->insert(globalSequence->begin(), declaration);
+}
+
+// Adds a branch to write int(ViewID_OVR) to either gl_ViewportIndex or gl_Layer. The branch is
+// added to the end of the initializers' sequence.
+void SelectViewIndexInVertexShader(const TVariable *viewID,
+                                   const TVariable *multiviewBaseViewLayerIndex,
+                                   TIntermSequence *initializers,
+                                   const TSymbolTable &symbolTable)
+{
+    // Create an int(ViewID_OVR) node.
+    TIntermSequence *viewIDSymbolCastArguments = new TIntermSequence();
+    viewIDSymbolCastArguments->push_back(new TIntermSymbol(viewID));
+    TIntermAggregate *viewIDAsInt = TIntermAggregate::CreateConstructor(
+        TType(EbtInt, EbpHigh, EvqTemporary), viewIDSymbolCastArguments);
+
+    // Create a gl_ViewportIndex node.
+    TIntermSymbol *viewportIndexSymbol =
+        ReferenceBuiltInVariable(kGlViewportIndexString, symbolTable, 0);
+
+    // Create a { gl_ViewportIndex = int(ViewID_OVR) } node.
+    TIntermBlock *viewportIndexInitializerInBlock = new TIntermBlock();
+    viewportIndexInitializerInBlock->appendStatement(
+        new TIntermBinary(EOpAssign, viewportIndexSymbol, viewIDAsInt));
+
+    // Create a gl_Layer node.
+    TIntermSymbol *layerSymbol = ReferenceBuiltInVariable(kGlLayerString, symbolTable, 0);
+
+    // Create an int(ViewID_OVR) + multiviewBaseViewLayerIndex node
+    TIntermBinary *sumOfViewIDAndBaseViewIndex = new TIntermBinary(
+        EOpAdd, viewIDAsInt->deepCopy(), new TIntermSymbol(multiviewBaseViewLayerIndex));
+
+    // Create a { gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex } node.
+    TIntermBlock *layerInitializerInBlock = new TIntermBlock();
+    layerInitializerInBlock->appendStatement(
+        new TIntermBinary(EOpAssign, layerSymbol, sumOfViewIDAndBaseViewIndex));
+
+    // Create a node to compare whether the base view index uniform is less than zero.
+    TIntermBinary *multiviewBaseViewLayerIndexZeroComparison =
+        new TIntermBinary(EOpLessThan, new TIntermSymbol(multiviewBaseViewLayerIndex),
+                          CreateZeroNode(TType(EbtInt, EbpHigh, EvqConst)));
+
+    // Create an if-else statement to select the code path.
+    TIntermIfElse *multiviewBranch =
+        new TIntermIfElse(multiviewBaseViewLayerIndexZeroComparison,
+                          viewportIndexInitializerInBlock, layerInitializerInBlock);
+
+    initializers->push_back(multiviewBranch);
+}
+
+}  // namespace
+
+void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
+                                                 unsigned numberOfViews,
+                                                 GLenum shaderType,
+                                                 ShCompileOptions compileOptions,
+                                                 ShShaderOutput shaderOutput,
+                                                 TSymbolTable *symbolTable)
+{
+    ASSERT(shaderType == GL_VERTEX_SHADER || shaderType == GL_FRAGMENT_SHADER);
+
+    TQualifier viewIDQualifier  = (shaderType == GL_VERTEX_SHADER) ? EvqFlatOut : EvqFlatIn;
+    const TVariable *viewID =
+        new TVariable(symbolTable, kViewIDVariableName,
+                      new TType(EbtUInt, EbpHigh, viewIDQualifier), SymbolType::AngleInternal);
+
+    DeclareGlobalVariable(root, viewID);
+    ReplaceVariable(
+        root,
+        static_cast<const TVariable *>(symbolTable->findBuiltIn(kGlViewIdOVRString, 300, true)),
+        viewID);
+    if (shaderType == GL_VERTEX_SHADER)
+    {
+        // Replacing gl_InstanceID with InstanceID should happen before adding the initializers of
+        // InstanceID and ViewID.
+        const TType *instanceIDVariableType   = StaticType::Get<EbtInt, EbpHigh, EvqGlobal, 1, 1>();
+        const TVariable *instanceID =
+            new TVariable(symbolTable, kInstanceIDVariableName, instanceIDVariableType,
+                          SymbolType::AngleInternal);
+        DeclareGlobalVariable(root, instanceID);
+        ReplaceVariable(root,
+                        static_cast<const TVariable *>(
+                            symbolTable->findBuiltIn(kGlInstanceIdString, 300, true)),
+                        instanceID);
+
+        TIntermSequence *initializers = new TIntermSequence();
+        InitializeViewIDAndInstanceID(viewID, instanceID, numberOfViews, *symbolTable,
+                                      initializers);
+
+        // The AST transformation which adds the expression to select the viewport index should
+        // be done only for the GLSL and ESSL output.
+        const bool selectView = (compileOptions & SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER) != 0u;
+        // Assert that if the view is selected in the vertex shader, then the output is
+        // either GLSL or ESSL.
+        ASSERT(!selectView || IsOutputGLSL(shaderOutput) || IsOutputESSL(shaderOutput));
+        if (selectView)
+        {
+            // Add a uniform to switch between side-by-side and layered rendering.
+            const TType *baseLayerIndexVariableType =
+                StaticType::Get<EbtInt, EbpHigh, EvqUniform, 1, 1>();
+            const TVariable *multiviewBaseViewLayerIndex =
+                new TVariable(symbolTable, kMultiviewBaseViewLayerIndexVariableName,
+                              baseLayerIndexVariableType, SymbolType::AngleInternal);
+            DeclareGlobalVariable(root, multiviewBaseViewLayerIndex);
+
+            // Setting a value to gl_ViewportIndex or gl_Layer should happen after ViewID_OVR's
+            // initialization.
+            SelectViewIndexInVertexShader(viewID, multiviewBaseViewLayerIndex, initializers,
+                                          *symbolTable);
+        }
+
+        // Insert initializers at the beginning of main().
+        TIntermBlock *initializersBlock = new TIntermBlock();
+        initializersBlock->getSequence()->swap(*initializers);
+        TIntermBlock *mainBody = FindMainBody(root);
+        mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initializersBlock);
+    }
+}
+
+}  // namespace sh
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.h
@@ -0,0 +1,48 @@
+//
+// 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.
+//
+// Regardless of the shader type, the following AST transformations are applied:
+// - Add declaration of View_ID_OVR.
+// - Replace every occurrence of gl_ViewID_OVR with ViewID_OVR, mark ViewID_OVR as internal and
+// declare it as a flat varying.
+//
+// If the shader type is a vertex shader, the following AST transformations are applied:
+// - Replace every occurrence of gl_InstanceID with InstanceID, mark InstanceID as internal and set
+// its qualifier to EvqTemporary.
+// - Add initializers of ViewID_OVR and InstanceID to the beginning of the body of main. The pass
+// should be executed before any variables get collected so that usage of gl_InstanceID is recorded.
+// - If the output is ESSL or GLSL and the SH_SELECT_VIEW_IN_NV_GLSL_VERTEX_SHADER option is
+// enabled, the expression
+// "if (multiviewBaseViewLayerIndex < 0) {
+//      gl_ViewportIndex = int(ViewID_OVR);
+//  } else {
+//      gl_Layer = int(ViewID_OVR) + multiviewBaseViewLayerIndex;
+//  }"
+// is added after ViewID and InstanceID are initialized. Also, MultiviewRenderPath is added as a
+// uniform.
+//
+
+#ifndef COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
+#define COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "angle_gl.h"
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void DeclareAndInitBuiltinsForInstancedMultiview(TIntermBlock *root,
+                                                 unsigned numberOfViews,
+                                                 GLenum shaderType,
+                                                 ShCompileOptions compileOptions,
+                                                 ShShaderOutput shaderOutput,
+                                                 TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_DECLAREANDINITBUILTINSFORINSTANCEDMULTIVIEW_H_
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DeferGlobalInitializers.cpp
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2016 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.
+//
+// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
+// function that is called in the beginning of main(). This enables initialization of globals with
+// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
+// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
+// done after DeferGlobalInitializers is run. Note that it's important that the function definition
+// is at the end of the shader, as some globals may be declared after main().
+//
+// It can also initialize all uninitialized globals.
+//
+
+#include "compiler/translator/DeferGlobalInitializers.h"
+
+#include <vector>
+
+#include "compiler/translator/FindMain.h"
+#include "compiler/translator/InitializeVariables.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/ReplaceVariable.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kInitGlobalsString("initGlobals");
+
+void GetDeferredInitializers(TIntermDeclaration *declaration,
+                             bool initializeUninitializedGlobals,
+                             bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
+                             TIntermSequence *deferredInitializersOut,
+                             std::vector<const TVariable *> *variablesToReplaceOut,
+                             TSymbolTable *symbolTable)
+{
+    // SeparateDeclarations should have already been run.
+    ASSERT(declaration->getSequence()->size() == 1);
+
+    TIntermNode *declarator = declaration->getSequence()->back();
+    TIntermBinary *init     = declarator->getAsBinaryNode();
+    if (init)
+    {
+        TIntermSymbol *symbolNode = init->getLeft()->getAsSymbolNode();
+        ASSERT(symbolNode);
+        TIntermTyped *expression = init->getRight();
+
+        if (expression->getQualifier() != EvqConst || !expression->hasConstantValue())
+        {
+            // For variables which are not constant, defer their real initialization until
+            // after we initialize uniforms.
+            // Deferral is done also in any cases where the variable can not be converted to a
+            // constant union, since otherwise there's a chance that HLSL output will generate extra
+            // statements from the initializer expression.
+
+            // Change const global to a regular global if its initialization is deferred.
+            // This can happen if ANGLE has not been able to fold the constant expression used
+            // as an initializer.
+            ASSERT(symbolNode->getQualifier() == EvqConst ||
+                   symbolNode->getQualifier() == EvqGlobal);
+            if (symbolNode->getQualifier() == EvqConst)
+            {
+                variablesToReplaceOut->push_back(&symbolNode->variable());
+            }
+
+            TIntermBinary *deferredInit =
+                new TIntermBinary(EOpAssign, symbolNode->deepCopy(), init->getRight());
+            deferredInitializersOut->push_back(deferredInit);
+
+            // Remove the initializer from the global scope and just declare the global instead.
+            declaration->replaceChildNode(init, symbolNode);
+        }
+    }
+    else if (initializeUninitializedGlobals)
+    {
+        TIntermSymbol *symbolNode = declarator->getAsSymbolNode();
+        ASSERT(symbolNode);
+
+        // Ignore ANGLE internal variables and nameless declarations.
+        if (symbolNode->variable().symbolType() == SymbolType::AngleInternal ||
+            symbolNode->variable().symbolType() == SymbolType::Empty)
+            return;
+
+        if (symbolNode->getQualifier() == EvqGlobal)
+        {
+            TIntermSequence *initCode = CreateInitCode(symbolNode, canUseLoopsToInitialize,
+                                                       highPrecisionSupported, symbolTable);
+            deferredInitializersOut->insert(deferredInitializersOut->end(), initCode->begin(),
+                                            initCode->end());
+        }
+    }
+}
+
+void InsertInitCallToMain(TIntermBlock *root,
+                          TIntermSequence *deferredInitializers,
+                          TSymbolTable *symbolTable)
+{
+    TIntermBlock *initGlobalsBlock = new TIntermBlock();
+    initGlobalsBlock->getSequence()->swap(*deferredInitializers);
+
+    TFunction *initGlobalsFunction =
+        new TFunction(symbolTable, kInitGlobalsString, SymbolType::AngleInternal,
+                      StaticType::GetBasic<EbtVoid>(), false);
+
+    TIntermFunctionPrototype *initGlobalsFunctionPrototype =
+        CreateInternalFunctionPrototypeNode(*initGlobalsFunction);
+    root->getSequence()->insert(root->getSequence()->begin(), initGlobalsFunctionPrototype);
+    TIntermFunctionDefinition *initGlobalsFunctionDefinition =
+        CreateInternalFunctionDefinitionNode(*initGlobalsFunction, initGlobalsBlock);
+    root->appendStatement(initGlobalsFunctionDefinition);
+
+    TIntermAggregate *initGlobalsCall =
+        TIntermAggregate::CreateFunctionCall(*initGlobalsFunction, new TIntermSequence());
+
+    TIntermBlock *mainBody = FindMainBody(root);
+    mainBody->getSequence()->insert(mainBody->getSequence()->begin(), initGlobalsCall);
+}
+
+}  // namespace
+
+void DeferGlobalInitializers(TIntermBlock *root,
+                             bool initializeUninitializedGlobals,
+                             bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
+                             TSymbolTable *symbolTable)
+{
+    TIntermSequence *deferredInitializers = new TIntermSequence();
+    std::vector<const TVariable *> variablesToReplace;
+
+    // Loop over all global statements and process the declarations. This is simpler than using a
+    // traverser.
+    for (TIntermNode *statement : *root->getSequence())
+    {
+        TIntermDeclaration *declaration = statement->getAsDeclarationNode();
+        if (declaration)
+        {
+            GetDeferredInitializers(declaration, initializeUninitializedGlobals,
+                                    canUseLoopsToInitialize, highPrecisionSupported,
+                                    deferredInitializers, &variablesToReplace, symbolTable);
+        }
+    }
+
+    // Add the function with initialization and the call to that.
+    if (!deferredInitializers->empty())
+    {
+        InsertInitCallToMain(root, deferredInitializers, symbolTable);
+    }
+
+    // Replace constant variables with non-constant global variables.
+    for (const TVariable *var : variablesToReplace)
+    {
+        TType *replacementType = new TType(var->getType());
+        replacementType->setQualifier(EvqGlobal);
+        TVariable *replacement =
+            new TVariable(symbolTable, var->name(), replacementType, var->symbolType());
+        ReplaceVariable(root, var, replacement);
+    }
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/DeferGlobalInitializers.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2016 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.
+//
+// DeferGlobalInitializers is an AST traverser that moves global initializers into a separate
+// function that is called in the beginning of main(). This enables initialization of globals with
+// uniforms or non-constant globals, as allowed by the WebGL spec. Some initializers referencing
+// non-constants may need to be unfolded into if statements in HLSL - this kind of steps should be
+// done after DeferGlobalInitializers is run. Note that it's important that the function definition
+// is at the end of the shader, as some globals may be declared after main().
+//
+// It can also initialize all uninitialized globals.
+//
+
+#ifndef COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
+#define COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TSymbolTable;
+
+void DeferGlobalInitializers(TIntermBlock *root,
+                             bool initializeUninitializedGlobals,
+                             bool canUseLoopsToInitialize,
+                             bool highPrecisionSupported,
+                             TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_DEFERGLOBALINITIALIZERS_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -0,0 +1,132 @@
+//
+// Copyright (c) 2002-2016 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.
+//
+// gl_FragColor needs to broadcast to all color buffers in ES2 if
+// GL_EXT_draw_buffers is explicitly enabled in a fragment shader.
+//
+// We emulate this by replacing all gl_FragColor with gl_FragData[0], and in the end
+// of main() function, assigning gl_FragData[1], ..., gl_FragData[maxDrawBuffers-1]
+// with gl_FragData[0].
+//
+
+#include "compiler/translator/EmulateGLFragColorBroadcast.h"
+
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/RunAtTheEndOfShader.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kGlFragDataString("gl_FragData");
+
+class GLFragColorBroadcastTraverser : public TIntermTraverser
+{
+  public:
+    GLFragColorBroadcastTraverser(int maxDrawBuffers, TSymbolTable *symbolTable, int shaderVersion)
+        : TIntermTraverser(true, false, false, symbolTable),
+          mGLFragColorUsed(false),
+          mMaxDrawBuffers(maxDrawBuffers),
+          mShaderVersion(shaderVersion)
+    {
+    }
+
+    void broadcastGLFragColor(TIntermBlock *root);
+
+    bool isGLFragColorUsed() const { return mGLFragColorUsed; }
+
+  protected:
+    void visitSymbol(TIntermSymbol *node) override;
+
+    TIntermBinary *constructGLFragDataNode(int index) const;
+    TIntermBinary *constructGLFragDataAssignNode(int index) const;
+
+  private:
+    bool mGLFragColorUsed;
+    int mMaxDrawBuffers;
+    const int mShaderVersion;
+};
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataNode(int index) const
+{
+    TIntermSymbol *symbol =
+        ReferenceBuiltInVariable(kGlFragDataString, *mSymbolTable, mShaderVersion);
+    TIntermTyped *indexNode = CreateIndexNode(index);
+
+    TIntermBinary *binary = new TIntermBinary(EOpIndexDirect, symbol, indexNode);
+    return binary;
+}
+
+TIntermBinary *GLFragColorBroadcastTraverser::constructGLFragDataAssignNode(int index) const
+{
+    TIntermTyped *fragDataIndex = constructGLFragDataNode(index);
+    TIntermTyped *fragDataZero  = constructGLFragDataNode(0);
+
+    return new TIntermBinary(EOpAssign, fragDataIndex, fragDataZero);
+}
+
+void GLFragColorBroadcastTraverser::visitSymbol(TIntermSymbol *node)
+{
+    if (node->variable().symbolType() == SymbolType::BuiltIn && node->getName() == "gl_FragColor")
+    {
+        queueReplacement(constructGLFragDataNode(0), OriginalNode::IS_DROPPED);
+        mGLFragColorUsed = true;
+    }
+}
+
+void GLFragColorBroadcastTraverser::broadcastGLFragColor(TIntermBlock *root)
+{
+    ASSERT(mMaxDrawBuffers > 1);
+    if (!mGLFragColorUsed)
+    {
+        return;
+    }
+
+    TIntermBlock *broadcastBlock = new TIntermBlock();
+    // Now insert statements
+    //   gl_FragData[1] = gl_FragData[0];
+    //   ...
+    //   gl_FragData[maxDrawBuffers - 1] = gl_FragData[0];
+    for (int colorIndex = 1; colorIndex < mMaxDrawBuffers; ++colorIndex)
+    {
+        broadcastBlock->appendStatement(constructGLFragDataAssignNode(colorIndex));
+    }
+    RunAtTheEndOfShader(root, broadcastBlock, mSymbolTable);
+}
+
+}  // namespace anonymous
+
+void EmulateGLFragColorBroadcast(TIntermBlock *root,
+                                 int maxDrawBuffers,
+                                 std::vector<sh::OutputVariable> *outputVariables,
+                                 TSymbolTable *symbolTable,
+                                 int shaderVersion)
+{
+    ASSERT(maxDrawBuffers > 1);
+    GLFragColorBroadcastTraverser traverser(maxDrawBuffers, symbolTable, shaderVersion);
+    root->traverse(&traverser);
+    if (traverser.isGLFragColorUsed())
+    {
+        traverser.updateTree();
+        traverser.broadcastGLFragColor(root);
+        for (auto &var : *outputVariables)
+        {
+            if (var.name == "gl_FragColor")
+            {
+                // TODO(zmo): Find a way to keep the original variable information.
+                var.name       = "gl_FragData";
+                var.mappedName = "gl_FragData";
+                var.arraySizes.push_back(maxDrawBuffers);
+                ASSERT(var.arraySizes.size() == 1u);
+            }
+        }
+    }
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/EmulateGLFragColorBroadcast.h
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2002-2016 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.
+//
+// Emulate gl_FragColor broadcast behaviors in ES2 where
+// GL_EXT_draw_buffers is explicitly enabled in a fragment shader.
+//
+
+#ifndef COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_
+#define COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_
+
+#include <vector>
+
+namespace sh
+{
+struct OutputVariable;
+class TIntermBlock;
+class TSymbolTable;
+
+// Replace all gl_FragColor with gl_FragData[0], and in the end of main() function,
+// assign gl_FragData[1] ... gl_FragData[maxDrawBuffers - 1] with gl_FragData[0].
+// If gl_FragColor is in outputVariables, it is replaced by gl_FragData.
+void EmulateGLFragColorBroadcast(TIntermBlock *root,
+                                 int maxDrawBuffers,
+                                 std::vector<OutputVariable> *outputVariables,
+                                 TSymbolTable *symbolTable,
+                                 int shaderVersion);
+}
+
+#endif  // COMPILER_TRANSLATOR_EMULATEGLFRAGCOLORBROADCAST_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/EmulatePrecision.cpp
@@ -0,0 +1,779 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+#include "compiler/translator/EmulatePrecision.h"
+
+#include "compiler/translator/FunctionLookup.h"
+
+#include <memory>
+
+namespace sh
+{
+
+namespace
+{
+
+constexpr const ImmutableString kParamXName("x");
+constexpr const ImmutableString kParamYName("y");
+constexpr const ImmutableString kAngleFrmString("angle_frm");
+constexpr const ImmutableString kAngleFrlString("angle_frl");
+
+class RoundingHelperWriter : angle::NonCopyable
+{
+  public:
+    static RoundingHelperWriter *createHelperWriter(const ShShaderOutput outputLanguage);
+
+    void writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion);
+    void writeCompoundAssignmentHelper(TInfoSinkBase &sink,
+                                       const char *lType,
+                                       const char *rType,
+                                       const char *opStr,
+                                       const char *opNameStr);
+
+    virtual ~RoundingHelperWriter() {}
+
+  protected:
+    RoundingHelperWriter(const ShShaderOutput outputLanguage) : mOutputLanguage(outputLanguage) {}
+    RoundingHelperWriter() = delete;
+
+    const ShShaderOutput mOutputLanguage;
+
+  private:
+    virtual std::string getTypeString(const char *glslType)     = 0;
+    virtual void writeFloatRoundingHelpers(TInfoSinkBase &sink) = 0;
+    virtual void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) = 0;
+    virtual void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+                                           const unsigned int columns,
+                                           const unsigned int rows,
+                                           const char *functionName) = 0;
+};
+
+class RoundingHelperWriterGLSL : public RoundingHelperWriter
+{
+  public:
+    RoundingHelperWriterGLSL(const ShShaderOutput outputLanguage)
+        : RoundingHelperWriter(outputLanguage)
+    {
+    }
+
+  private:
+    std::string getTypeString(const char *glslType) override;
+    void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
+    void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
+    void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+                                   const unsigned int columns,
+                                   const unsigned int rows,
+                                   const char *functionName) override;
+};
+
+class RoundingHelperWriterESSL : public RoundingHelperWriterGLSL
+{
+  public:
+    RoundingHelperWriterESSL(const ShShaderOutput outputLanguage)
+        : RoundingHelperWriterGLSL(outputLanguage)
+    {
+    }
+
+  private:
+    std::string getTypeString(const char *glslType) override;
+};
+
+class RoundingHelperWriterHLSL : public RoundingHelperWriter
+{
+  public:
+    RoundingHelperWriterHLSL(const ShShaderOutput outputLanguage)
+        : RoundingHelperWriter(outputLanguage)
+    {
+    }
+
+  private:
+    std::string getTypeString(const char *glslType) override;
+    void writeFloatRoundingHelpers(TInfoSinkBase &sink) override;
+    void writeVectorRoundingHelpers(TInfoSinkBase &sink, const unsigned int size) override;
+    void writeMatrixRoundingHelper(TInfoSinkBase &sink,
+                                   const unsigned int columns,
+                                   const unsigned int rows,
+                                   const char *functionName) override;
+};
+
+RoundingHelperWriter *RoundingHelperWriter::createHelperWriter(const ShShaderOutput outputLanguage)
+{
+    ASSERT(EmulatePrecision::SupportedInLanguage(outputLanguage));
+    switch (outputLanguage)
+    {
+        case SH_HLSL_4_1_OUTPUT:
+            return new RoundingHelperWriterHLSL(outputLanguage);
+        case SH_ESSL_OUTPUT:
+            return new RoundingHelperWriterESSL(outputLanguage);
+        default:
+            return new RoundingHelperWriterGLSL(outputLanguage);
+    }
+}
+
+void RoundingHelperWriter::writeCommonRoundingHelpers(TInfoSinkBase &sink, const int shaderVersion)
+{
+    // Write the angle_frm functions that round floating point numbers to
+    // half precision, and angle_frl functions that round them to minimum lowp
+    // precision.
+
+    writeFloatRoundingHelpers(sink);
+    writeVectorRoundingHelpers(sink, 2);
+    writeVectorRoundingHelpers(sink, 3);
+    writeVectorRoundingHelpers(sink, 4);
+    if (shaderVersion > 100)
+    {
+        for (unsigned int columns = 2; columns <= 4; ++columns)
+        {
+            for (unsigned int rows = 2; rows <= 4; ++rows)
+            {
+                writeMatrixRoundingHelper(sink, columns, rows, "angle_frm");
+                writeMatrixRoundingHelper(sink, columns, rows, "angle_frl");
+            }
+        }
+    }
+    else
+    {
+        for (unsigned int size = 2; size <= 4; ++size)
+        {
+            writeMatrixRoundingHelper(sink, size, size, "angle_frm");
+            writeMatrixRoundingHelper(sink, size, size, "angle_frl");
+        }
+    }
+}
+
+void RoundingHelperWriter::writeCompoundAssignmentHelper(TInfoSinkBase &sink,
+                                                         const char *lType,
+                                                         const char *rType,
+                                                         const char *opStr,
+                                                         const char *opNameStr)
+{
+    std::string lTypeStr = getTypeString(lType);
+    std::string rTypeStr = getTypeString(rType);
+
+    // Note that y should be passed through angle_frm at the function call site,
+    // but x can't be passed through angle_frm there since it is an inout parameter.
+    // So only pass x and the result through angle_frm here.
+    // clang-format off
+    sink <<
+        lTypeStr << " angle_compound_" << opNameStr << "_frm(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
+        "    x = angle_frm(angle_frm(x) " << opStr << " y);\n"
+        "    return x;\n"
+        "}\n";
+    sink <<
+        lTypeStr << " angle_compound_" << opNameStr << "_frl(inout " << lTypeStr << " x, in " << rTypeStr << " y) {\n"
+        "    x = angle_frl(angle_frl(x) " << opStr << " y);\n"
+        "    return x;\n"
+        "}\n";
+    // clang-format on
+}
+
+std::string RoundingHelperWriterGLSL::getTypeString(const char *glslType)
+{
+    return glslType;
+}
+
+std::string RoundingHelperWriterESSL::getTypeString(const char *glslType)
+{
+    std::stringstream typeStrStr;
+    typeStrStr << "highp " << glslType;
+    return typeStrStr.str();
+}
+
+void RoundingHelperWriterGLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
+{
+    // Unoptimized version of angle_frm for single floats:
+    //
+    // int webgl_maxNormalExponent(in int exponentBits)
+    // {
+    //     int possibleExponents = int(exp2(float(exponentBits)));
+    //     int exponentBias = possibleExponents / 2 - 1;
+    //     int allExponentBitsOne = possibleExponents - 1;
+    //     return (allExponentBitsOne - 1) - exponentBias;
+    // }
+    //
+    // float angle_frm(in float x)
+    // {
+    //     int mantissaBits = 10;
+    //     int exponentBits = 5;
+    //     float possibleMantissas = exp2(float(mantissaBits));
+    //     float mantissaMax = 2.0 - 1.0 / possibleMantissas;
+    //     int maxNE = webgl_maxNormalExponent(exponentBits);
+    //     float max = exp2(float(maxNE)) * mantissaMax;
+    //     if (x > max)
+    //     {
+    //         return max;
+    //     }
+    //     if (x < -max)
+    //     {
+    //         return -max;
+    //     }
+    //     float exponent = floor(log2(abs(x)));
+    //     if (abs(x) == 0.0 || exponent < -float(maxNE))
+    //     {
+    //         return 0.0 * sign(x)
+    //     }
+    //     x = x * exp2(-(exponent - float(mantissaBits)));
+    //     x = sign(x) * floor(abs(x));
+    //     return x * exp2(exponent - float(mantissaBits));
+    // }
+
+    // All numbers with a magnitude less than 2^-15 are subnormal, and are
+    // flushed to zero.
+
+    // Note the constant numbers below:
+    // a) 65504 is the maximum possible mantissa (1.1111111111 in binary) times
+    //    2^15, the maximum normal exponent.
+    // b) 10.0 is the number of mantissa bits.
+    // c) -25.0 is the minimum normal half-float exponent -15.0 minus the number
+    //    of mantissa bits.
+    // d) + 1e-30 is to make sure the argument of log2() won't be zero. It can
+    //    only affect the result of log2 on x where abs(x) < 1e-22. Since these
+    //    numbers will be flushed to zero either way (2^-15 is the smallest
+    //    normal positive number), this does not introduce any error.
+
+    std::string floatType = getTypeString("float");
+
+    // clang-format off
+    sink <<
+        floatType << " angle_frm(in " << floatType << " x) {\n"
+        "    x = clamp(x, -65504.0, 65504.0);\n"
+        "    " << floatType << " exponent = floor(log2(abs(x) + 1e-30)) - 10.0;\n"
+        "    bool isNonZero = (exponent >= -25.0);\n"
+        "    x = x * exp2(-exponent);\n"
+        "    x = sign(x) * floor(abs(x));\n"
+        "    return x * exp2(exponent) * float(isNonZero);\n"
+        "}\n";
+
+    sink <<
+        floatType << " angle_frl(in " << floatType << " x) {\n"
+        "    x = clamp(x, -2.0, 2.0);\n"
+        "    x = x * 256.0;\n"
+        "    x = sign(x) * floor(abs(x));\n"
+        "    return x * 0.00390625;\n"
+        "}\n";
+    // clang-format on
+}
+
+void RoundingHelperWriterGLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
+                                                          const unsigned int size)
+{
+    std::stringstream vecTypeStrStr;
+    vecTypeStrStr << "vec" << size;
+    std::string vecType = getTypeString(vecTypeStrStr.str().c_str());
+
+    // clang-format off
+    sink <<
+        vecType << " angle_frm(in " << vecType << " v) {\n"
+        "    v = clamp(v, -65504.0, 65504.0);\n"
+        "    " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
+        "    bvec" << size << " isNonZero = greaterThanEqual(exponent, vec" << size << "(-25.0));\n"
+        "    v = v * exp2(-exponent);\n"
+        "    v = sign(v) * floor(abs(v));\n"
+        "    return v * exp2(exponent) * vec" << size << "(isNonZero);\n"
+        "}\n";
+
+    sink <<
+        vecType << " angle_frl(in " << vecType << " v) {\n"
+        "    v = clamp(v, -2.0, 2.0);\n"
+        "    v = v * 256.0;\n"
+        "    v = sign(v) * floor(abs(v));\n"
+        "    return v * 0.00390625;\n"
+        "}\n";
+    // clang-format on
+}
+
+void RoundingHelperWriterGLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
+                                                         const unsigned int columns,
+                                                         const unsigned int rows,
+                                                         const char *functionName)
+{
+    std::stringstream matTypeStrStr;
+    matTypeStrStr << "mat" << columns;
+    if (rows != columns)
+    {
+        matTypeStrStr << "x" << rows;
+    }
+    std::string matType = getTypeString(matTypeStrStr.str().c_str());
+
+    sink << matType << " " << functionName << "(in " << matType << " m) {\n"
+         << "    " << matType << " rounded;\n";
+
+    for (unsigned int i = 0; i < columns; ++i)
+    {
+        sink << "    rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
+    }
+
+    sink << "    return rounded;\n"
+            "}\n";
+}
+
+static const char *GetHLSLTypeStr(const char *floatTypeStr)
+{
+    if (strcmp(floatTypeStr, "float") == 0)
+    {
+        return "float";
+    }
+    if (strcmp(floatTypeStr, "vec2") == 0)
+    {
+        return "float2";
+    }
+    if (strcmp(floatTypeStr, "vec3") == 0)
+    {
+        return "float3";
+    }
+    if (strcmp(floatTypeStr, "vec4") == 0)
+    {
+        return "float4";
+    }
+    if (strcmp(floatTypeStr, "mat2") == 0)
+    {
+        return "float2x2";
+    }
+    if (strcmp(floatTypeStr, "mat3") == 0)
+    {
+        return "float3x3";
+    }
+    if (strcmp(floatTypeStr, "mat4") == 0)
+    {
+        return "float4x4";
+    }
+    if (strcmp(floatTypeStr, "mat2x3") == 0)
+    {
+        return "float2x3";
+    }
+    if (strcmp(floatTypeStr, "mat2x4") == 0)
+    {
+        return "float2x4";
+    }
+    if (strcmp(floatTypeStr, "mat3x2") == 0)
+    {
+        return "float3x2";
+    }
+    if (strcmp(floatTypeStr, "mat3x4") == 0)
+    {
+        return "float3x4";
+    }
+    if (strcmp(floatTypeStr, "mat4x2") == 0)
+    {
+        return "float4x2";
+    }
+    if (strcmp(floatTypeStr, "mat4x3") == 0)
+    {
+        return "float4x3";
+    }
+    UNREACHABLE();
+    return nullptr;
+}
+
+std::string RoundingHelperWriterHLSL::getTypeString(const char *glslType)
+{
+    return GetHLSLTypeStr(glslType);
+}
+
+void RoundingHelperWriterHLSL::writeFloatRoundingHelpers(TInfoSinkBase &sink)
+{
+    // In HLSL scalars are the same as 1-vectors.
+    writeVectorRoundingHelpers(sink, 1);
+}
+
+void RoundingHelperWriterHLSL::writeVectorRoundingHelpers(TInfoSinkBase &sink,
+                                                          const unsigned int size)
+{
+    std::stringstream vecTypeStrStr;
+    vecTypeStrStr << "float" << size;
+    std::string vecType = vecTypeStrStr.str();
+
+    // clang-format off
+    sink <<
+        vecType << " angle_frm(" << vecType << " v) {\n"
+        "    v = clamp(v, -65504.0, 65504.0);\n"
+        "    " << vecType << " exponent = floor(log2(abs(v) + 1e-30)) - 10.0;\n"
+        "    bool" << size << " isNonZero = exponent < -25.0;\n"
+        "    v = v * exp2(-exponent);\n"
+        "    v = sign(v) * floor(abs(v));\n"
+        "    return v * exp2(exponent) * (float" << size << ")(isNonZero);\n"
+        "}\n";
+
+    sink <<
+        vecType << " angle_frl(" << vecType << " v) {\n"
+        "    v = clamp(v, -2.0, 2.0);\n"
+        "    v = v * 256.0;\n"
+        "    v = sign(v) * floor(abs(v));\n"
+        "    return v * 0.00390625;\n"
+        "}\n";
+    // clang-format on
+}
+
+void RoundingHelperWriterHLSL::writeMatrixRoundingHelper(TInfoSinkBase &sink,
+                                                         const unsigned int columns,
+                                                         const unsigned int rows,
+                                                         const char *functionName)
+{
+    std::stringstream matTypeStrStr;
+    matTypeStrStr << "float" << columns << "x" << rows;
+    std::string matType = matTypeStrStr.str();
+
+    sink << matType << " " << functionName << "(" << matType << " m) {\n"
+         << "    " << matType << " rounded;\n";
+
+    for (unsigned int i = 0; i < columns; ++i)
+    {
+        sink << "    rounded[" << i << "] = " << functionName << "(m[" << i << "]);\n";
+    }
+
+    sink << "    return rounded;\n"
+            "}\n";
+}
+
+bool canRoundFloat(const TType &type)
+{
+    return type.getBasicType() == EbtFloat && !type.isArray() &&
+           (type.getPrecision() == EbpLow || type.getPrecision() == EbpMedium);
+}
+
+bool ParentUsesResult(TIntermNode *parent, TIntermTyped *node)
+{
+    if (!parent)
+    {
+        return false;
+    }
+
+    TIntermBlock *blockParent = parent->getAsBlock();
+    // If the parent is a block, the result is not assigned anywhere,
+    // so rounding it is not needed. In particular, this can avoid a lot of
+    // unnecessary rounding of unused return values of assignment.
+    if (blockParent)
+    {
+        return false;
+    }
+    TIntermBinary *binaryParent = parent->getAsBinaryNode();
+    if (binaryParent && binaryParent->getOp() == EOpComma && (binaryParent->getRight() != node))
+    {
+        return false;
+    }
+    return true;
+}
+
+bool ParentConstructorTakesCareOfRounding(TIntermNode *parent, TIntermTyped *node)
+{
+    if (!parent)
+    {
+        return false;
+    }
+    TIntermAggregate *parentConstructor = parent->getAsAggregate();
+    if (!parentConstructor || parentConstructor->getOp() != EOpConstruct)
+    {
+        return false;
+    }
+    if (parentConstructor->getPrecision() != node->getPrecision())
+    {
+        return false;
+    }
+    return canRoundFloat(parentConstructor->getType());
+}
+
+}  // namespace anonymous
+
+EmulatePrecision::EmulatePrecision(TSymbolTable *symbolTable)
+    : TLValueTrackingTraverser(true, true, true, symbolTable), mDeclaringVariables(false)
+{
+}
+
+void EmulatePrecision::visitSymbol(TIntermSymbol *node)
+{
+    TIntermNode *parent = getParentNode();
+    if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) &&
+        !ParentConstructorTakesCareOfRounding(parent, node) && !mDeclaringVariables &&
+        !isLValueRequiredHere())
+    {
+        TIntermNode *replacement = createRoundingFunctionCallNode(node);
+        queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+    }
+}
+
+bool EmulatePrecision::visitBinary(Visit visit, TIntermBinary *node)
+{
+    bool visitChildren = true;
+
+    TOperator op = node->getOp();
+
+    // RHS of initialize is not being declared.
+    if (op == EOpInitialize && visit == InVisit)
+        mDeclaringVariables = false;
+
+    if ((op == EOpIndexDirectStruct) && visit == InVisit)
+        visitChildren = false;
+
+    if (visit != PreVisit)
+        return visitChildren;
+
+    const TType &type = node->getType();
+    bool roundFloat   = canRoundFloat(type);
+
+    if (roundFloat)
+    {
+        switch (op)
+        {
+            // Math operators that can result in a float may need to apply rounding to the return
+            // value. Note that in the case of assignment, the rounding is applied to its return
+            // value here, not the value being assigned.
+            case EOpAssign:
+            case EOpAdd:
+            case EOpSub:
+            case EOpMul:
+            case EOpDiv:
+            case EOpVectorTimesScalar:
+            case EOpVectorTimesMatrix:
+            case EOpMatrixTimesVector:
+            case EOpMatrixTimesScalar:
+            case EOpMatrixTimesMatrix:
+            {
+                TIntermNode *parent = getParentNode();
+                if (!ParentUsesResult(parent, node) ||
+                    ParentConstructorTakesCareOfRounding(parent, node))
+                {
+                    break;
+                }
+                TIntermNode *replacement = createRoundingFunctionCallNode(node);
+                queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+                break;
+            }
+
+            // Compound assignment cases need to replace the operator with a function call.
+            case EOpAddAssign:
+            {
+                mEmulateCompoundAdd.insert(
+                    TypePair(type.getBuiltInTypeNameString(),
+                             node->getRight()->getType().getBuiltInTypeNameString()));
+                TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+                    node->getLeft(), node->getRight(), "add");
+                queueReplacement(replacement, OriginalNode::IS_DROPPED);
+                break;
+            }
+            case EOpSubAssign:
+            {
+                mEmulateCompoundSub.insert(
+                    TypePair(type.getBuiltInTypeNameString(),
+                             node->getRight()->getType().getBuiltInTypeNameString()));
+                TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+                    node->getLeft(), node->getRight(), "sub");
+                queueReplacement(replacement, OriginalNode::IS_DROPPED);
+                break;
+            }
+            case EOpMulAssign:
+            case EOpVectorTimesMatrixAssign:
+            case EOpVectorTimesScalarAssign:
+            case EOpMatrixTimesScalarAssign:
+            case EOpMatrixTimesMatrixAssign:
+            {
+                mEmulateCompoundMul.insert(
+                    TypePair(type.getBuiltInTypeNameString(),
+                             node->getRight()->getType().getBuiltInTypeNameString()));
+                TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+                    node->getLeft(), node->getRight(), "mul");
+                queueReplacement(replacement, OriginalNode::IS_DROPPED);
+                break;
+            }
+            case EOpDivAssign:
+            {
+                mEmulateCompoundDiv.insert(
+                    TypePair(type.getBuiltInTypeNameString(),
+                             node->getRight()->getType().getBuiltInTypeNameString()));
+                TIntermNode *replacement = createCompoundAssignmentFunctionCallNode(
+                    node->getLeft(), node->getRight(), "div");
+                queueReplacement(replacement, OriginalNode::IS_DROPPED);
+                break;
+            }
+            default:
+                // The rest of the binary operations should not need precision emulation.
+                break;
+        }
+    }
+    return visitChildren;
+}
+
+bool EmulatePrecision::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+    // Variable or interface block declaration.
+    if (visit == PreVisit)
+    {
+        mDeclaringVariables = true;
+    }
+    else if (visit == InVisit)
+    {
+        mDeclaringVariables = true;
+    }
+    else
+    {
+        mDeclaringVariables = false;
+    }
+    return true;
+}
+
+bool EmulatePrecision::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+    return false;
+}
+
+bool EmulatePrecision::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+    return false;
+}
+
+bool EmulatePrecision::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+    if (visit != PreVisit)
+        return true;
+
+    // User-defined function return values are not rounded. The calculations that produced
+    // the value inside the function definition should have been rounded.
+    TOperator op = node->getOp();
+    if (op == EOpCallInternalRawFunction || op == EOpCallFunctionInAST ||
+        (op == EOpConstruct && node->getBasicType() == EbtStruct))
+    {
+        return true;
+    }
+
+    TIntermNode *parent = getParentNode();
+    if (canRoundFloat(node->getType()) && ParentUsesResult(parent, node) &&
+        !ParentConstructorTakesCareOfRounding(parent, node))
+    {
+        TIntermNode *replacement = createRoundingFunctionCallNode(node);
+        queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+    }
+    return true;
+}
+
+bool EmulatePrecision::visitUnary(Visit visit, TIntermUnary *node)
+{
+    switch (node->getOp())
+    {
+        case EOpNegative:
+        case EOpLogicalNot:
+        case EOpPostIncrement:
+        case EOpPostDecrement:
+        case EOpPreIncrement:
+        case EOpPreDecrement:
+        case EOpLogicalNotComponentWise:
+            break;
+        default:
+            if (canRoundFloat(node->getType()) && visit == PreVisit)
+            {
+                TIntermNode *replacement = createRoundingFunctionCallNode(node);
+                queueReplacement(replacement, OriginalNode::BECOMES_CHILD);
+            }
+            break;
+    }
+
+    return true;
+}
+
+void EmulatePrecision::writeEmulationHelpers(TInfoSinkBase &sink,
+                                             const int shaderVersion,
+                                             const ShShaderOutput outputLanguage)
+{
+    std::unique_ptr<RoundingHelperWriter> roundingHelperWriter(
+        RoundingHelperWriter::createHelperWriter(outputLanguage));
+
+    roundingHelperWriter->writeCommonRoundingHelpers(sink, shaderVersion);
+
+    EmulationSet::const_iterator it;
+    for (it = mEmulateCompoundAdd.begin(); it != mEmulateCompoundAdd.end(); it++)
+        roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "+", "add");
+    for (it = mEmulateCompoundSub.begin(); it != mEmulateCompoundSub.end(); it++)
+        roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "-", "sub");
+    for (it = mEmulateCompoundDiv.begin(); it != mEmulateCompoundDiv.end(); it++)
+        roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "/", "div");
+    for (it = mEmulateCompoundMul.begin(); it != mEmulateCompoundMul.end(); it++)
+        roundingHelperWriter->writeCompoundAssignmentHelper(sink, it->lType, it->rType, "*", "mul");
+}
+
+// static
+bool EmulatePrecision::SupportedInLanguage(const ShShaderOutput outputLanguage)
+{
+    switch (outputLanguage)
+    {
+        case SH_HLSL_4_1_OUTPUT:
+        case SH_ESSL_OUTPUT:
+            return true;
+        default:
+            // Other languages not yet supported
+            return (outputLanguage == SH_GLSL_COMPATIBILITY_OUTPUT ||
+                    sh::IsGLSL130OrNewer(outputLanguage));
+    }
+}
+
+const TFunction *EmulatePrecision::getInternalFunction(const ImmutableString &functionName,
+                                                       const TType &returnType,
+                                                       TIntermSequence *arguments,
+                                                       const TVector<TConstParameter> &parameters,
+                                                       bool knownToNotHaveSideEffects)
+{
+    ImmutableString mangledName = TFunctionLookup::GetMangledName(functionName.data(), *arguments);
+    if (mInternalFunctions.find(mangledName) == mInternalFunctions.end())
+    {
+        TFunction *func = new TFunction(mSymbolTable, functionName, SymbolType::AngleInternal,
+                                        new TType(returnType), knownToNotHaveSideEffects);
+        ASSERT(parameters.size() == arguments->size());
+        for (size_t i = 0; i < parameters.size(); ++i)
+        {
+            func->addParameter(parameters[i]);
+        }
+        mInternalFunctions[mangledName] = func;
+    }
+    return mInternalFunctions[mangledName];
+}
+
+TIntermAggregate *EmulatePrecision::createRoundingFunctionCallNode(TIntermTyped *roundedChild)
+{
+    const ImmutableString *roundFunctionName = &kAngleFrmString;
+    if (roundedChild->getPrecision() == EbpLow)
+        roundFunctionName = &kAngleFrlString;
+    TIntermSequence *arguments = new TIntermSequence();
+    arguments->push_back(roundedChild);
+
+    TVector<TConstParameter> parameters;
+    TType *paramType = new TType(roundedChild->getType());
+    paramType->setPrecision(EbpHigh);
+    paramType->setQualifier(EvqIn);
+    parameters.push_back(TConstParameter(kParamXName, static_cast<const TType *>(paramType)));
+
+    return TIntermAggregate::CreateRawFunctionCall(
+        *getInternalFunction(*roundFunctionName, roundedChild->getType(), arguments, parameters,
+                             true),
+        arguments);
+}
+
+TIntermAggregate *EmulatePrecision::createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
+                                                                             TIntermTyped *right,
+                                                                             const char *opNameStr)
+{
+    std::stringstream strstr;
+    if (left->getPrecision() == EbpMedium)
+        strstr << "angle_compound_" << opNameStr << "_frm";
+    else
+        strstr << "angle_compound_" << opNameStr << "_frl";
+    ImmutableString functionName = ImmutableString(strstr.str());
+    TIntermSequence *arguments = new TIntermSequence();
+    arguments->push_back(left);
+    arguments->push_back(right);
+
+    TVector<TConstParameter> parameters;
+    TType *leftParamType = new TType(left->getType());
+    leftParamType->setPrecision(EbpHigh);
+    leftParamType->setQualifier(EvqOut);
+    parameters.push_back(TConstParameter(kParamXName, static_cast<const TType *>(leftParamType)));
+    TType *rightParamType = new TType(right->getType());
+    rightParamType->setPrecision(EbpHigh);
+    rightParamType->setQualifier(EvqIn);
+    parameters.push_back(TConstParameter(kParamYName, static_cast<const TType *>(rightParamType)));
+
+    return TIntermAggregate::CreateRawFunctionCall(
+        *getInternalFunction(functionName, left->getType(), arguments, parameters, false),
+        arguments);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/EmulatePrecision.h
@@ -0,0 +1,86 @@
+//
+// Copyright (c) 2002-2014 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
+#define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "common/angleutils.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermTraverse.h"
+
+// This class gathers all compound assignments from the AST and can then write
+// the functions required for their precision emulation. This way there is no
+// need to write a huge number of variations of the emulated compound assignment
+// to every translated shader with emulation enabled.
+
+namespace sh
+{
+
+class EmulatePrecision : public TLValueTrackingTraverser
+{
+  public:
+    EmulatePrecision(TSymbolTable *symbolTable);
+
+    void visitSymbol(TIntermSymbol *node) override;
+    bool visitBinary(Visit visit, TIntermBinary *node) override;
+    bool visitUnary(Visit visit, TIntermUnary *node) override;
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+    bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+    bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
+
+    void writeEmulationHelpers(TInfoSinkBase &sink,
+                               const int shaderVersion,
+                               const ShShaderOutput outputLanguage);
+
+    static bool SupportedInLanguage(const ShShaderOutput outputLanguage);
+
+  private:
+    struct TypePair
+    {
+        TypePair(const char *l, const char *r) : lType(l), rType(r) {}
+
+        const char *lType;
+        const char *rType;
+    };
+
+    struct TypePairComparator
+    {
+        bool operator()(const TypePair &l, const TypePair &r) const
+        {
+            if (l.lType == r.lType)
+                return l.rType < r.rType;
+            return l.lType < r.lType;
+        }
+    };
+
+    const TFunction *getInternalFunction(const ImmutableString &functionName,
+                                         const TType &returnType,
+                                         TIntermSequence *arguments,
+                                         const TVector<TConstParameter> &parameters,
+                                         bool knownToNotHaveSideEffects);
+    TIntermAggregate *createRoundingFunctionCallNode(TIntermTyped *roundedChild);
+    TIntermAggregate *createCompoundAssignmentFunctionCallNode(TIntermTyped *left,
+                                                               TIntermTyped *right,
+                                                               const char *opNameStr);
+
+    typedef std::set<TypePair, TypePairComparator> EmulationSet;
+    EmulationSet mEmulateCompoundAdd;
+    EmulationSet mEmulateCompoundSub;
+    EmulationSet mEmulateCompoundMul;
+    EmulationSet mEmulateCompoundDiv;
+
+    // Map from mangled name to function.
+    TMap<ImmutableString, const TFunction *> mInternalFunctions;
+
+    bool mDeclaringVariables;
+};
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExpandIntegerPowExpressions.cpp
@@ -0,0 +1,147 @@
+//
+// Copyright (c) 2016 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.
+//
+// Implementation of the integer pow expressions HLSL bug workaround.
+// See header for more info.
+
+#include "compiler/translator/ExpandIntegerPowExpressions.h"
+
+#include <cmath>
+#include <cstdlib>
+
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class Traverser : public TIntermTraverser
+{
+  public:
+    static void Apply(TIntermNode *root, TSymbolTable *symbolTable);
+
+  private:
+    Traverser(TSymbolTable *symbolTable);
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override;
+    void nextIteration();
+
+    bool mFound = false;
+};
+
+// static
+void Traverser::Apply(TIntermNode *root, TSymbolTable *symbolTable)
+{
+    Traverser traverser(symbolTable);
+    do
+    {
+        traverser.nextIteration();
+        root->traverse(&traverser);
+        if (traverser.mFound)
+        {
+            traverser.updateTree();
+        }
+    } while (traverser.mFound);
+}
+
+Traverser::Traverser(TSymbolTable *symbolTable) : TIntermTraverser(true, false, false, symbolTable)
+{
+}
+
+void Traverser::nextIteration()
+{
+    mFound = false;
+}
+
+bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+    if (mFound)
+    {
+        return false;
+    }
+
+    // Test 0: skip non-pow operators.
+    if (node->getOp() != EOpPow)
+    {
+        return true;
+    }
+
+    const TIntermSequence *sequence = node->getSequence();
+    ASSERT(sequence->size() == 2u);
+    const TIntermConstantUnion *constantExponent = sequence->at(1)->getAsConstantUnion();
+
+    // Test 1: check for a single constant.
+    if (!constantExponent || constantExponent->getNominalSize() != 1)
+    {
+        return true;
+    }
+
+    ASSERT(constantExponent->getBasicType() == EbtFloat);
+    float exponentValue = constantExponent->getConstantValue()->getFConst();
+
+    // Test 2: exponentValue is in the problematic range.
+    if (exponentValue < -5.0f || exponentValue > 9.0f)
+    {
+        return true;
+    }
+
+    // Test 3: exponentValue is integer or pretty close to an integer.
+    if (std::abs(exponentValue - std::round(exponentValue)) > 0.0001f)
+    {
+        return true;
+    }
+
+    // Test 4: skip -1, 0, and 1
+    int exponent = static_cast<int>(std::round(exponentValue));
+    int n        = std::abs(exponent);
+    if (n < 2)
+    {
+        return true;
+    }
+
+    // Potential problem case detected, apply workaround.
+
+    TIntermTyped *lhs = sequence->at(0)->getAsTyped();
+    ASSERT(lhs);
+
+    TIntermDeclaration *lhsVariableDeclaration = nullptr;
+    TVariable *lhsVariable =
+        DeclareTempVariable(mSymbolTable, lhs, EvqTemporary, &lhsVariableDeclaration);
+    insertStatementInParentBlock(lhsVariableDeclaration);
+
+    // Create a chain of n-1 multiples.
+    TIntermTyped *current = CreateTempSymbolNode(lhsVariable);
+    for (int i = 1; i < n; ++i)
+    {
+        TIntermBinary *mul = new TIntermBinary(EOpMul, current, CreateTempSymbolNode(lhsVariable));
+        mul->setLine(node->getLine());
+        current = mul;
+    }
+
+    // For negative pow, compute the reciprocal of the positive pow.
+    if (exponent < 0)
+    {
+        TConstantUnion *oneVal = new TConstantUnion();
+        oneVal->setFConst(1.0f);
+        TIntermConstantUnion *oneNode = new TIntermConstantUnion(oneVal, node->getType());
+        TIntermBinary *div            = new TIntermBinary(EOpDiv, oneNode, current);
+        current                       = div;
+    }
+
+    queueReplacement(current, OriginalNode::IS_DROPPED);
+    mFound = true;
+    return false;
+}
+
+}  // anonymous namespace
+
+void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable)
+{
+    Traverser::Apply(root, symbolTable);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ExpandIntegerPowExpressions.h
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2016 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.
+//
+// This mutating tree traversal works around a bug in the HLSL compiler optimizer with "pow" that
+// manifests under the following conditions:
+//
+// - If pow() has a literal exponent value
+// - ... and this value is integer or within 10e-6 of an integer
+// - ... and it is in {-4, -3, -2, 2, 3, 4, 5, 6, 7, 8}
+//
+// The workaround is to replace the pow with a series of multiplies.
+// See http://anglebug.com/851
+
+#ifndef COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TSymbolTable;
+
+void ExpandIntegerPowExpressions(TIntermNode *root, TSymbolTable *symbolTable);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_EXPANDINTEGERPOWEXPRESSIONS_H_
--- a/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h
+++ b/gfx/angle/checkout/src/compiler/translator/ExtensionGLSL.h
@@ -7,17 +7,17 @@
 // shaders.
 
 #ifndef COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
 #define COMPILER_TRANSLATOR_EXTENSIONGLSL_H_
 
 #include <set>
 #include <string>
 
-#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
 
 // Traverses the intermediate tree to determine which GLSL extensions are required
 // to support the shader.
 class TExtensionGLSL : public TIntermTraverser
 {
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FindMain.cpp
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+
+// FindMain.cpp: Find the main() function definition in a given AST.
+
+#include "compiler/translator/FindMain.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+TIntermFunctionDefinition *FindMain(TIntermBlock *root)
+{
+    for (TIntermNode *node : *root->getSequence())
+    {
+        TIntermFunctionDefinition *nodeFunction = node->getAsFunctionDefinition();
+        if (nodeFunction != nullptr && nodeFunction->getFunction()->isMain())
+        {
+            return nodeFunction;
+        }
+    }
+    return nullptr;
+}
+
+TIntermBlock *FindMainBody(TIntermBlock *root)
+{
+    TIntermFunctionDefinition *main = FindMain(root);
+    ASSERT(main != nullptr);
+    TIntermBlock *mainBody = main->getBody();
+    ASSERT(mainBody != nullptr);
+    return mainBody;
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FindMain.h
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+
+// FindMain.h: Adds functions to get the main function definition and its body.
+
+#ifndef COMPILER_TRANSLATOR_FINDMAIN_H_
+#define COMPILER_TRANSLATOR_FINDMAIN_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TIntermFunctionDefinition;
+
+TIntermFunctionDefinition *FindMain(TIntermBlock *root);
+TIntermBlock *FindMainBody(TIntermBlock *root);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_FINDMAIN_H_
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FindSymbolNode.cpp
@@ -0,0 +1,54 @@
+//
+// 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.
+//
+// FindSymbol.cpp:
+//     Utility for finding a symbol node inside an AST tree.
+
+#include "compiler/translator/FindSymbolNode.h"
+
+#include "compiler/translator/ImmutableString.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/Symbol.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class SymbolFinder : public TIntermTraverser
+{
+  public:
+    SymbolFinder(const ImmutableString &symbolName)
+        : TIntermTraverser(true, false, false), mSymbolName(symbolName), mNodeFound(nullptr)
+    {
+    }
+
+    void visitSymbol(TIntermSymbol *node)
+    {
+        if (node->variable().symbolType() != SymbolType::Empty && node->getName() == mSymbolName)
+        {
+            mNodeFound = node;
+        }
+    }
+
+    bool isFound() const { return mNodeFound != nullptr; }
+    const TIntermSymbol *getNode() const { return mNodeFound; }
+
+  private:
+    ImmutableString mSymbolName;
+    TIntermSymbol *mNodeFound;
+};
+
+}  // anonymous namespace
+
+const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName)
+{
+    SymbolFinder finder(symbolName);
+    root->traverse(&finder);
+    return finder.getNode();
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FindSymbolNode.h
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+// FindSymbolNode.h:
+//     Utility for finding a symbol node inside an AST tree.
+
+#ifndef COMPILER_TRANSLATOR_FIND_SYMBOL_H_
+#define COMPILER_TRANSLATOR_FIND_SYMBOL_H_
+
+namespace sh
+{
+
+class ImmutableString;
+class TIntermNode;
+class TIntermSymbol;
+
+const TIntermSymbol *FindSymbolNode(TIntermNode *root, const ImmutableString &symbolName);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_FIND_SYMBOL_H_
\ No newline at end of file
--- a/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/FlagStd140Structs.cpp
@@ -3,18 +3,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 // FlagStd140Structs.cpp: Find structs in std140 blocks, where the padding added in the translator
 // conflicts with the "natural" unpadded type.
 
 #include "compiler/translator/FlagStd140Structs.h"
 
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
-#include "compiler/translator/tree_util/IntermTraverse.h"
 
 namespace sh
 {
 
 namespace
 {
 
 class FlagStd140StructsTraverser : public TIntermTraverser
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FoldExpressions.cpp
@@ -0,0 +1,116 @@
+//
+// Copyright (c) 2018 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.
+//
+// FoldExpressions.cpp: Fold expressions. This may fold expressions so that the qualifier of the
+// folded node differs from the qualifier of the original expression, so it needs to be done after
+// parsing and validation of qualifiers is complete. Expressions that are folded:
+//  1. Ternary ops with a constant condition.
+//  2. Sequence aka comma ops where the left side has no side effects.
+//  3. Any expressions containing any of the above.
+
+#include "compiler/translator/FoldExpressions.h"
+
+#include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+class FoldExpressionsTraverser : public TIntermTraverser
+{
+  public:
+    FoldExpressionsTraverser(TDiagnostics *diagnostics)
+        : TIntermTraverser(true, false, false), mDiagnostics(diagnostics), mDidReplace(false)
+    {
+    }
+
+    bool didReplace() { return mDidReplace; }
+
+    void nextIteration() { mDidReplace = false; }
+
+  protected:
+    bool visitTernary(Visit visit, TIntermTernary *node) override
+    {
+        TIntermTyped *folded = node->fold(mDiagnostics);
+        if (folded != node)
+        {
+            queueReplacement(folded, OriginalNode::IS_DROPPED);
+            mDidReplace = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool visitAggregate(Visit visit, TIntermAggregate *node) override
+    {
+        TIntermTyped *folded = node->fold(mDiagnostics);
+        if (folded != node)
+        {
+            queueReplacement(folded, OriginalNode::IS_DROPPED);
+            mDidReplace = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool visitBinary(Visit visit, TIntermBinary *node) override
+    {
+        TIntermTyped *folded = node->fold(mDiagnostics);
+        if (folded != node)
+        {
+            queueReplacement(folded, OriginalNode::IS_DROPPED);
+            mDidReplace = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool visitUnary(Visit visit, TIntermUnary *node) override
+    {
+        TIntermTyped *folded = node->fold(mDiagnostics);
+        if (folded != node)
+        {
+            queueReplacement(folded, OriginalNode::IS_DROPPED);
+            mDidReplace = true;
+            return false;
+        }
+        return true;
+    }
+
+    bool visitSwizzle(Visit visit, TIntermSwizzle *node) override
+    {
+        TIntermTyped *folded = node->fold(mDiagnostics);
+        if (folded != node)
+        {
+            queueReplacement(folded, OriginalNode::IS_DROPPED);
+            mDidReplace = true;
+            return false;
+        }
+        return true;
+    }
+
+  private:
+    TDiagnostics *mDiagnostics;
+    bool mDidReplace;
+};
+
+}  // anonymous namespace
+
+void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics)
+{
+    FoldExpressionsTraverser traverser(diagnostics);
+    do
+    {
+        traverser.nextIteration();
+        root->traverse(&traverser);
+        traverser.updateTree();
+    } while (traverser.didReplace());
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/FoldExpressions.h
@@ -0,0 +1,24 @@
+//
+// Copyright (c) 2018 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.
+//
+// FoldExpressions.h: Fold expressions. This may fold expressions so that the qualifier of the
+// folded node differs from the qualifier of the original expression, so it needs to be done after
+// parsing and validation of qualifiers is complete. Expressions that are folded: 1. Ternary ops
+// with a constant condition.
+
+#ifndef COMPILER_TRANSLATOR_FOLDEXPRESSIONS_H_
+#define COMPILER_TRANSLATOR_FOLDEXPRESSIONS_H_
+
+namespace sh
+{
+
+class TIntermBlock;
+class TDiagnostics;
+
+void FoldExpressions(TIntermBlock *root, TDiagnostics *diagnostics);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_FOLDEXPRESSIONS_H_
--- a/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.cpp
@@ -30,40 +30,22 @@ const size_t ImmutableString::FowlerNoll
 template <>
 const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime =
     static_cast<size_t>(1099511628211ull);
 
 template <>
 const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis =
     static_cast<size_t>(0xcbf29ce484222325ull);
 
-uint32_t ImmutableString::mangledNameHash() const
+uint32_t ImmutableString::hash32() const
 {
-    const char *dataPtr              = data();
-    uint32_t hash                    = static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvOffsetBasis);
-    const uint32_t kMaxSixBitValue   = (1u << 6) - 1u;
-    uint32_t parenLocation           = kMaxSixBitValue;
-    uint32_t hasArrayOrBlockParamBit = 0u;
-    uint32_t index                   = 0;
-    while (dataPtr[index] != '\0')
+    const char *data_ptr = data();
+    uint32_t hash        = static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvOffsetBasis);
+    while ((*data_ptr) != '\0')
     {
-        hash = hash ^ dataPtr[index];
+        hash = hash ^ (*data_ptr);
         hash = hash * static_cast<uint32_t>(FowlerNollVoHash<4>::kFnvPrime);
-        if (dataPtr[index] == '(')
-        {
-            // We should only reach here once, since this function should not be called with invalid
-            // mangled names.
-            ASSERT(parenLocation == kMaxSixBitValue);
-            parenLocation = index;
-        }
-        else if (dataPtr[index] == '{' || dataPtr[index] == '[')
-        {
-            hasArrayOrBlockParamBit = 1u;
-        }
-        ++index;
+        ++data_ptr;
     }
-    // Should not be called with strings longer than 63 characters.
-    ASSERT(index <= kMaxSixBitValue);
-    return ((hash >> 13) ^ (hash & 0x1fff)) | (index << 19) | (parenLocation << 25) |
-           (hasArrayOrBlockParamBit << 31);
+    return hash;
 }
 
 }  // namespace sh
--- a/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableString.h
@@ -123,20 +123,17 @@ class ImmutableString
                 hash = hash ^ (*data);
                 hash = hash * kFnvPrime;
                 ++data;
             }
             return hash;
         }
     };
 
-    // This hash encodes the opening parentheses location (if any), name length and whether the name
-    // contains { or [ characters in addition to a 19-bit hash. This way the hash is more useful for
-    // lookups. The string passed in should be at most 63 characters.
-    uint32_t mangledNameHash() const;
+    uint32_t hash32() const;
 
   private:
     const char *mData;
     size_t mLength;
 };
 
 }  // namespace sh
 
--- a/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h
+++ b/gfx/angle/checkout/src/compiler/translator/ImmutableStringBuilder.h
@@ -42,17 +42,17 @@ class ImmutableStringBuilder
         while (((number >> (index * 4)) & 0xfu) == 0 && index > 0)
         {
             --index;
         }
         // Write the rest of the hex digits.
         while (index >= 0)
         {
             char digit     = static_cast<char>((number >> (index * 4)) & 0xfu);
-            char digitChar = (digit < 10) ? (digit + '0') : (digit + ('a' - 10));
+            char digitChar = digit < 10 ? digit + '0' : digit + 'a';
             mData[mPos++]  = digitChar;
             --index;
         }
         return;
     }
 
   private:
     inline static char *AllocateEmptyPoolCharArray(size_t strLength)
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InitializeVariables.cpp
@@ -0,0 +1,311 @@
+//
+// Copyright (c) 2002-2013 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.
+//
+
+#include "compiler/translator/InitializeVariables.h"
+
+#include "angle_gl.h"
+#include "common/debug.h"
+#include "compiler/translator/FindMain.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/StaticType.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/util.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+                              bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported,
+                              TIntermSequence *initSequenceOut,
+                              TSymbolTable *symbolTable);
+
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+                               bool canUseLoopsToInitialize,
+                               bool highPrecisionSupported,
+                               TIntermSequence *initSequenceOut,
+                               TSymbolTable *symbolTable);
+
+TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
+{
+    TIntermTyped *zero = CreateZeroNode(initializedNode->getType());
+    return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
+}
+
+void AddZeroInitSequence(const TIntermTyped *initializedNode,
+                         bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported,
+                         TIntermSequence *initSequenceOut,
+                         TSymbolTable *symbolTable)
+{
+    if (initializedNode->isArray())
+    {
+        AddArrayZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+                                 initSequenceOut, symbolTable);
+    }
+    else if (initializedNode->getType().isStructureContainingArrays() ||
+             initializedNode->getType().isNamelessStruct())
+    {
+        AddStructZeroInitSequence(initializedNode, canUseLoopsToInitialize, highPrecisionSupported,
+                                  initSequenceOut, symbolTable);
+    }
+    else
+    {
+        initSequenceOut->push_back(CreateZeroInitAssignment(initializedNode));
+    }
+}
+
+void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
+                               bool canUseLoopsToInitialize,
+                               bool highPrecisionSupported,
+                               TIntermSequence *initSequenceOut,
+                               TSymbolTable *symbolTable)
+{
+    ASSERT(initializedNode->getBasicType() == EbtStruct);
+    const TStructure *structType = initializedNode->getType().getStruct();
+    for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
+    {
+        TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
+                                                   initializedNode->deepCopy(), CreateIndexNode(i));
+        // Structs can't be defined inside structs, so the type of a struct field can't be a
+        // nameless struct.
+        ASSERT(!element->getType().isNamelessStruct());
+        AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+                            initSequenceOut, symbolTable);
+    }
+}
+
+void AddArrayZeroInitStatementList(const TIntermTyped *initializedNode,
+                                   bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
+                                   TIntermSequence *initSequenceOut,
+                                   TSymbolTable *symbolTable)
+{
+    for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
+    {
+        TIntermBinary *element =
+            new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
+        AddZeroInitSequence(element, canUseLoopsToInitialize, highPrecisionSupported,
+                            initSequenceOut, symbolTable);
+    }
+}
+
+void AddArrayZeroInitForLoop(const TIntermTyped *initializedNode,
+                             bool highPrecisionSupported,
+                             TIntermSequence *initSequenceOut,
+                             TSymbolTable *symbolTable)
+{
+    ASSERT(initializedNode->isArray());
+    const TType *mediumpIndexType = StaticType::Get<EbtInt, EbpMedium, EvqTemporary, 1, 1>();
+    const TType *highpIndexType   = StaticType::Get<EbtInt, EbpHigh, EvqTemporary, 1, 1>();
+    TVariable *indexVariable =
+        CreateTempVariable(symbolTable, highPrecisionSupported ? highpIndexType : mediumpIndexType);
+
+    TIntermSymbol *indexSymbolNode = CreateTempSymbolNode(indexVariable);
+    TIntermDeclaration *indexInit =
+        CreateTempInitDeclarationNode(indexVariable, CreateZeroNode(indexVariable->getType()));
+    TIntermConstantUnion *arraySizeNode = CreateIndexNode(initializedNode->getOutermostArraySize());
+    TIntermBinary *indexSmallerThanSize =
+        new TIntermBinary(EOpLessThan, indexSymbolNode->deepCopy(), arraySizeNode);
+    TIntermUnary *indexIncrement = new TIntermUnary(EOpPreIncrement, indexSymbolNode->deepCopy());
+
+    TIntermBlock *forLoopBody       = new TIntermBlock();
+    TIntermSequence *forLoopBodySeq = forLoopBody->getSequence();
+
+    TIntermBinary *element = new TIntermBinary(EOpIndexIndirect, initializedNode->deepCopy(),
+                                               indexSymbolNode->deepCopy());
+    AddZeroInitSequence(element, true, highPrecisionSupported, forLoopBodySeq, symbolTable);
+
+    TIntermLoop *forLoop =
+        new TIntermLoop(ELoopFor, indexInit, indexSmallerThanSize, indexIncrement, forLoopBody);
+    initSequenceOut->push_back(forLoop);
+}
+
+void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
+                              bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported,
+                              TIntermSequence *initSequenceOut,
+                              TSymbolTable *symbolTable)
+{
+    // The array elements are assigned one by one to keep the AST compatible with ESSL 1.00 which
+    // doesn't have array assignment. We'll do this either with a for loop or just a list of
+    // statements assigning to each array index. Note that it is important to have the array init in
+    // the right order to workaround http://crbug.com/709317
+    bool isSmallArray = initializedNode->getOutermostArraySize() <= 1u ||
+                        (initializedNode->getBasicType() != EbtStruct &&
+                         !initializedNode->getType().isArrayOfArrays() &&
+                         initializedNode->getOutermostArraySize() <= 3u);
+    if (initializedNode->getQualifier() == EvqFragData ||
+        initializedNode->getQualifier() == EvqFragmentOut || isSmallArray ||
+        !canUseLoopsToInitialize)
+    {
+        // Fragment outputs should not be indexed by non-constant indices.
+        // Also it doesn't make sense to use loops to initialize very small arrays.
+        AddArrayZeroInitStatementList(initializedNode, canUseLoopsToInitialize,
+                                      highPrecisionSupported, initSequenceOut, symbolTable);
+    }
+    else
+    {
+        AddArrayZeroInitForLoop(initializedNode, highPrecisionSupported, initSequenceOut,
+                                symbolTable);
+    }
+}
+
+void InsertInitCode(TIntermSequence *mainBody,
+                    const InitVariableList &variables,
+                    TSymbolTable *symbolTable,
+                    int shaderVersion,
+                    const TExtensionBehavior &extensionBehavior,
+                    bool canUseLoopsToInitialize,
+                    bool highPrecisionSupported)
+{
+    for (const auto &var : variables)
+    {
+        // Note that tempVariableName will reference a short-lived char array here - that's fine
+        // since we're only using it to find symbols.
+        ImmutableString tempVariableName(var.name.c_str(), var.name.length());
+
+        TIntermTyped *initializedSymbol = nullptr;
+        if (var.isBuiltIn())
+        {
+            initializedSymbol =
+                ReferenceBuiltInVariable(tempVariableName, *symbolTable, shaderVersion);
+            if (initializedSymbol->getQualifier() == EvqFragData &&
+                !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
+            {
+                // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
+                // written to.
+                // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
+                // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
+                // to have the array size of MaxDrawBuffers, and the initialization happens before
+                // the shader sets the extensions it is using.
+                initializedSymbol =
+                    new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
+            }
+        }
+        else
+        {
+            initializedSymbol = ReferenceGlobalVariable(tempVariableName, *symbolTable);
+        }
+        ASSERT(initializedSymbol != nullptr);
+
+        TIntermSequence *initCode = CreateInitCode(initializedSymbol, canUseLoopsToInitialize,
+                                                   highPrecisionSupported, symbolTable);
+        mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
+    }
+}
+
+class InitializeLocalsTraverser : public TIntermTraverser
+{
+  public:
+    InitializeLocalsTraverser(int shaderVersion,
+                              TSymbolTable *symbolTable,
+                              bool canUseLoopsToInitialize,
+                              bool highPrecisionSupported)
+        : TIntermTraverser(true, false, false, symbolTable),
+          mShaderVersion(shaderVersion),
+          mCanUseLoopsToInitialize(canUseLoopsToInitialize),
+          mHighPrecisionSupported(highPrecisionSupported)
+    {
+    }
+
+  protected:
+    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
+    {
+        for (TIntermNode *declarator : *node->getSequence())
+        {
+            if (!mInGlobalScope && !declarator->getAsBinaryNode())
+            {
+                TIntermSymbol *symbol = declarator->getAsSymbolNode();
+                ASSERT(symbol);
+                if (symbol->variable().symbolType() == SymbolType::Empty)
+                {
+                    continue;
+                }
+
+                // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
+                // support array constructors or assigning arrays.
+                bool arrayConstructorUnavailable =
+                    (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
+                    mShaderVersion == 100;
+                // Nameless struct constructors can't be referred to, so they also need to be
+                // initialized one element at a time.
+                // TODO(oetuaho): Check if it makes sense to initialize using a loop, even if we
+                // could use an initializer. It could at least reduce code size for very large
+                // arrays, but could hurt runtime performance.
+                if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct())
+                {
+                    // SimplifyLoopConditions should have been run so the parent node of this node
+                    // should not be a loop.
+                    ASSERT(getParentNode()->getAsLoopNode() == nullptr);
+                    // SeparateDeclarations should have already been run, so we don't need to worry
+                    // about further declarators in this declaration depending on the effects of
+                    // this declarator.
+                    ASSERT(node->getSequence()->size() == 1);
+                    insertStatementsInParentBlock(
+                        TIntermSequence(), *CreateInitCode(symbol, mCanUseLoopsToInitialize,
+                                                           mHighPrecisionSupported, mSymbolTable));
+                }
+                else
+                {
+                    TIntermBinary *init =
+                        new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
+                    queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
+                }
+            }
+        }
+        return false;
+    }
+
+  private:
+    int mShaderVersion;
+    bool mCanUseLoopsToInitialize;
+    bool mHighPrecisionSupported;
+};
+
+}  // namespace anonymous
+
+TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
+                                bool canUseLoopsToInitialize,
+                                bool highPrecisionSupported,
+                                TSymbolTable *symbolTable)
+{
+    TIntermSequence *initCode = new TIntermSequence();
+    AddZeroInitSequence(initializedSymbol, canUseLoopsToInitialize, highPrecisionSupported,
+                        initCode, symbolTable);
+    return initCode;
+}
+
+void InitializeUninitializedLocals(TIntermBlock *root,
+                                   int shaderVersion,
+                                   bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
+                                   TSymbolTable *symbolTable)
+{
+    InitializeLocalsTraverser traverser(shaderVersion, symbolTable, canUseLoopsToInitialize,
+                                        highPrecisionSupported);
+    root->traverse(&traverser);
+    traverser.updateTree();
+}
+
+void InitializeVariables(TIntermBlock *root,
+                         const InitVariableList &vars,
+                         TSymbolTable *symbolTable,
+                         int shaderVersion,
+                         const TExtensionBehavior &extensionBehavior,
+                         bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported)
+{
+    TIntermBlock *body = FindMainBody(root);
+    InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior,
+                   canUseLoopsToInitialize, highPrecisionSupported);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/InitializeVariables.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2013 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.
+//
+
+#ifndef COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
+#define COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "compiler/translator/ExtensionBehavior.h"
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+class TSymbolTable;
+
+typedef std::vector<sh::ShaderVariable> InitVariableList;
+
+// For all of the functions below: If canUseLoopsToInitialize is set, for loops are used instead of
+// a large number of initializers where it can make sense, such as for initializing large arrays.
+
+// Return a sequence of assignment operations to initialize "initializedSymbol". initializedSymbol
+// may be an array, struct or any combination of these, as long as it contains only basic types.
+TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol,
+                                bool canUseLoopsToInitialize,
+                                bool highPrecisionSupported,
+                                TSymbolTable *symbolTable);
+
+// Initialize all uninitialized local variables, so that undefined behavior is avoided.
+void InitializeUninitializedLocals(TIntermBlock *root,
+                                   int shaderVersion,
+                                   bool canUseLoopsToInitialize,
+                                   bool highPrecisionSupported,
+                                   TSymbolTable *symbolTable);
+
+// This function can initialize all the types that CreateInitCode is able to initialize. All
+// variables must be globals which can be found in the symbol table. For now it is used for the
+// following two scenarios:
+//   1. Initializing gl_Position;
+//   2. Initializing output variables referred to in the shader source.
+// Note: The type of each lvalue in an initializer is retrieved from the symbol table. gl_FragData
+// requires special handling because the number of indices which can be initialized is determined by
+// enabled extensions.
+void InitializeVariables(TIntermBlock *root,
+                         const InitVariableList &vars,
+                         TSymbolTable *symbolTable,
+                         int shaderVersion,
+                         const TExtensionBehavior &extensionBehavior,
+                         bool canUseLoopsToInitialize,
+                         bool highPrecisionSupported);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_INITIALIZEVARIABLES_H_
--- a/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.cpp
@@ -259,17 +259,17 @@ bool TIntermAggregate::replaceChildNode(
 
 bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
 {
     return replaceChildNodeInternal(original, replacement);
 }
 
 bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
 {
-    return false;
+    return replaceChildNodeInternal(original, replacement);
 }
 
 bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
 {
     return replaceChildNodeInternal(original, replacement);
 }
 
 bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
@@ -684,16 +684,22 @@ void TIntermBlock::appendStatement(TInte
     // need to add the declaration to the AST in that case because it might be relevant to the
     // validity of switch/case.
     if (statement != nullptr)
     {
         mStatements.push_back(statement);
     }
 }
 
+void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
+{
+    ASSERT(parameter != nullptr);
+    mParameters.push_back(parameter);
+}
+
 void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
 {
     ASSERT(declarator != nullptr);
     ASSERT(declarator->getAsSymbolNode() != nullptr ||
            (declarator->getAsBinaryNode() != nullptr &&
             declarator->getAsBinaryNode()->getOp() == EOpInitialize));
     ASSERT(mDeclarators.empty() ||
            declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
@@ -790,33 +796,30 @@ TIntermAggregate *TIntermAggregate::shal
 }
 
 TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
 {
     TIntermTyped *operandCopy = node.mOperand->deepCopy();
     ASSERT(operandCopy != nullptr);
     mOperand = operandCopy;
     mSwizzleOffsets = node.mSwizzleOffsets;
-    mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets;
 }
 
 TIntermBinary::TIntermBinary(const TIntermBinary &node)
     : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
 {
     TIntermTyped *leftCopy  = node.mLeft->deepCopy();
     TIntermTyped *rightCopy = node.mRight->deepCopy();
     ASSERT(leftCopy != nullptr && rightCopy != nullptr);
     mLeft  = leftCopy;
     mRight = rightCopy;
 }
 
 TIntermUnary::TIntermUnary(const TIntermUnary &node)
-    : TIntermOperator(node),
-      mUseEmulatedFunction(node.mUseEmulatedFunction),
-      mFunction(node.mFunction)
+    : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
 {
     TIntermTyped *operandCopy = node.mOperand->deepCopy();
     ASSERT(operandCopy != nullptr);
     mOperand = operandCopy;
 }
 
 TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
 {
@@ -1039,25 +1042,24 @@ void TIntermUnary::promote()
             mType.setQualifier(resultQualifier);
             break;
     }
 }
 
 TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
     : TIntermExpression(TType(EbtFloat, EbpUndefined)),
       mOperand(operand),
-      mSwizzleOffsets(swizzleOffsets),
-      mHasFoldedDuplicateOffsets(false)
+      mSwizzleOffsets(swizzleOffsets)
 {
     ASSERT(mSwizzleOffsets.size() <= 4);
     promote();
 }
 
-TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
-    : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
+TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
+    : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
 {
     promote();
 }
 
 TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
     : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
 {
     promote();
@@ -1166,37 +1168,28 @@ void TIntermSwizzle::promote()
 
     auto numFields = mSwizzleOffsets.size();
     setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
                   static_cast<unsigned char>(numFields)));
 }
 
 bool TIntermSwizzle::hasDuplicateOffsets() const
 {
-    if (mHasFoldedDuplicateOffsets)
-    {
-        return true;
-    }
     int offsetCount[4] = {0u, 0u, 0u, 0u};
     for (const auto offset : mSwizzleOffsets)
     {
         offsetCount[offset]++;
         if (offsetCount[offset] > 1)
         {
             return true;
         }
     }
     return false;
 }
 
-void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
-{
-    mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
-}
-
 bool TIntermSwizzle::offsetsMatch(int offset) const
 {
     return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
 }
 
 void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
 {
     for (const int offset : mSwizzleOffsets)
@@ -1480,34 +1473,16 @@ const TConstantUnion *TIntermConstantUni
     {
         UNREACHABLE();
         return nullptr;
     }
 }
 
 TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
 {
-    TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
-    if (operandSwizzle)
-    {
-        // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
-        // overflow in ParseContext::checkCanBeLValue().
-        bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
-        TVector<int> foldedOffsets;
-        for (int offset : mSwizzleOffsets)
-        {
-            // Offset should already be validated.
-            ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
-            foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
-        }
-        operandSwizzle->mSwizzleOffsets = foldedOffsets;
-        operandSwizzle->setType(getType());
-        operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
-        return operandSwizzle;
-    }
     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
     if (operandConstant == nullptr)
     {
         return this;
     }
 
     TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
     for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
--- a/gfx/angle/checkout/src/compiler/translator/IntermNode.h
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode.h
@@ -426,25 +426,23 @@ class TIntermSwizzle : public TIntermExp
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
 
     bool hasSideEffects() const override { return mOperand->hasSideEffects(); }
 
     TIntermTyped *getOperand() { return mOperand; }
     void writeOffsetsAsXYZW(TInfoSinkBase *out) const;
 
     bool hasDuplicateOffsets() const;
-    void setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets);
     bool offsetsMatch(int offset) const;
 
     TIntermTyped *fold(TDiagnostics *diagnostics) override;
 
   protected:
     TIntermTyped *mOperand;
     TVector<int> mSwizzleOffsets;
-    bool mHasFoldedDuplicateOffsets;
 
   private:
     void promote();
 
     TIntermSwizzle(const TIntermSwizzle &node);  // Note: not deleted, just private!
 };
 
 //
@@ -500,43 +498,39 @@ class TIntermBinary : public TIntermOper
 };
 
 //
 // Nodes for unary math operators.
 //
 class TIntermUnary : public TIntermOperator
 {
   public:
-    TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function);
+    TIntermUnary(TOperator op, TIntermTyped *operand);
 
     TIntermTyped *deepCopy() const override { return new TIntermUnary(*this); }
 
     void traverse(TIntermTraverser *it) override;
     TIntermUnary *getAsUnaryNode() override { return this; }
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
 
     bool hasSideEffects() const override { return isAssignment() || mOperand->hasSideEffects(); }
 
     TIntermTyped *getOperand() { return mOperand; }
     TIntermTyped *fold(TDiagnostics *diagnostics) override;
 
-    const TFunction *getFunction() const { return mFunction; }
-
     void setUseEmulatedFunction() { mUseEmulatedFunction = true; }
     bool getUseEmulatedFunction() { return mUseEmulatedFunction; }
 
   protected:
     TIntermTyped *mOperand;
 
     // If set to true, replace the built-in function call with an emulated one
     // to work around driver bugs.
     bool mUseEmulatedFunction;
 
-    const TFunction *const mFunction;
-
   private:
     void promote();
 
     TIntermUnary(const TIntermUnary &node);  // note: not deleted, just private!
 };
 
 typedef TVector<TIntermNode *> TIntermSequence;
 typedef TVector<int> TQualifierList;
@@ -661,17 +655,17 @@ class TIntermBlock : public TIntermNode,
     const TIntermSequence *getSequence() const override { return &mStatements; }
 
   protected:
     TIntermSequence mStatements;
 };
 
 // Function prototype. May be in the AST either as a function prototype declaration or as a part of
 // a function definition. The type of the node is the function return type.
-class TIntermFunctionPrototype : public TIntermTyped
+class TIntermFunctionPrototype : public TIntermTyped, public TIntermAggregateBase
 {
   public:
     TIntermFunctionPrototype(const TFunction *function);
     ~TIntermFunctionPrototype() {}
 
     TIntermFunctionPrototype *getAsFunctionPrototypeNode() override { return this; }
     void traverse(TIntermTraverser *it) override;
     bool replaceChildNode(TIntermNode *original, TIntermNode *replacement) override;
@@ -684,19 +678,27 @@ class TIntermFunctionPrototype : public 
         return nullptr;
     }
     bool hasSideEffects() const override
     {
         UNREACHABLE();
         return true;
     }
 
+    // Only intended for initially building the declaration.
+    void appendParameter(TIntermSymbol *parameter);
+
+    TIntermSequence *getSequence() override { return &mParameters; }
+    const TIntermSequence *getSequence() const override { return &mParameters; }
+
     const TFunction *getFunction() const { return mFunction; }
 
   protected:
+    TIntermSequence mParameters;
+
     const TFunction *const mFunction;
 };
 
 // Node for function definitions. The prototype child node stores the function header including
 // parameters, and the body child node stores the function body.
 class TIntermFunctionDefinition : public TIntermNode
 {
   public:
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNodePatternMatcher.cpp
@@ -0,0 +1,199 @@
+//
+// Copyright (c) 2016 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.
+//
+// IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
+// It can be used whenever the same checks for certain node structures are common to multiple AST
+// traversers.
+//
+
+#include "compiler/translator/IntermNodePatternMatcher.h"
+
+#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+bool ContainsMatrixNode(const TIntermSequence &sequence)
+{
+    for (size_t ii = 0; ii < sequence.size(); ++ii)
+    {
+        TIntermTyped *node = sequence[ii]->getAsTyped();
+        if (node && node->isMatrix())
+            return true;
+    }
+    return false;
+}
+
+bool ContainsVectorNode(const TIntermSequence &sequence)
+{
+    for (size_t ii = 0; ii < sequence.size(); ++ii)
+    {
+        TIntermTyped *node = sequence[ii]->getAsTyped();
+        if (node && node->isVector())
+            return true;
+    }
+    return false;
+}
+
+}  // anonymous namespace
+
+IntermNodePatternMatcher::IntermNodePatternMatcher(const unsigned int mask) : mMask(mask)
+{
+}
+
+// static
+bool IntermNodePatternMatcher::IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node)
+{
+    return node->getOp() == EOpIndexIndirect && !node->getLeft()->isArray() &&
+           node->getLeft()->getBasicType() != EbtStruct;
+}
+
+bool IntermNodePatternMatcher::matchInternal(TIntermBinary *node, TIntermNode *parentNode)
+{
+    if ((mMask & kExpressionReturningArray) != 0)
+    {
+        if (node->isArray() && node->getOp() == EOpAssign && parentNode != nullptr &&
+            !parentNode->getAsBlock())
+        {
+            return true;
+        }
+    }
+
+    if ((mMask & kUnfoldedShortCircuitExpression) != 0)
+    {
+        if (node->getRight()->hasSideEffects() &&
+            (node->getOp() == EOpLogicalOr || node->getOp() == EOpLogicalAnd))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermUnary *node)
+{
+    if ((mMask & kArrayLengthMethod) != 0)
+    {
+        if (node->getOp() == EOpArrayLength)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermBinary *node, TIntermNode *parentNode)
+{
+    // L-value tracking information is needed to check for dynamic indexing in L-value.
+    // Traversers that don't track l-values can still use this class and match binary nodes with
+    // this variation of this method if they don't need to check for dynamic indexing in l-values.
+    ASSERT((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) == 0);
+    return matchInternal(node, parentNode);
+}
+
+bool IntermNodePatternMatcher::match(TIntermBinary *node,
+                                     TIntermNode *parentNode,
+                                     bool isLValueRequiredHere)
+{
+    if (matchInternal(node, parentNode))
+    {
+        return true;
+    }
+    if ((mMask & kDynamicIndexingOfVectorOrMatrixInLValue) != 0)
+    {
+        if (isLValueRequiredHere && IsDynamicIndexingOfVectorOrMatrix(node))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermAggregate *node, TIntermNode *parentNode)
+{
+    if ((mMask & kExpressionReturningArray) != 0)
+    {
+        if (parentNode != nullptr)
+        {
+            TIntermBinary *parentBinary = parentNode->getAsBinaryNode();
+            bool parentIsAssignment =
+                (parentBinary != nullptr &&
+                 (parentBinary->getOp() == EOpAssign || parentBinary->getOp() == EOpInitialize));
+
+            if (node->getType().isArray() && !parentIsAssignment &&
+                (node->isConstructor() || node->isFunctionCall()) && !parentNode->getAsBlock())
+            {
+                return true;
+            }
+        }
+    }
+    if ((mMask & kScalarizedVecOrMatConstructor) != 0)
+    {
+        if (node->getOp() == EOpConstruct)
+        {
+            if (node->getType().isVector() && ContainsMatrixNode(*(node->getSequence())))
+            {
+                return true;
+            }
+            else if (node->getType().isMatrix() && ContainsVectorNode(*(node->getSequence())))
+            {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermTernary *node)
+{
+    if ((mMask & kUnfoldedShortCircuitExpression) != 0)
+    {
+        return true;
+    }
+    return false;
+}
+
+bool IntermNodePatternMatcher::match(TIntermDeclaration *node)
+{
+    if ((mMask & kMultiDeclaration) != 0)
+    {
+        if (node->getSequence()->size() > 1)
+        {
+            return true;
+        }
+    }
+    if ((mMask & kArrayDeclaration) != 0)
+    {
+        if (node->getSequence()->front()->getAsTyped()->getType().isStructureContainingArrays())
+        {
+            return true;
+        }
+        // Need to check from all declarators whether they are arrays since that may vary between
+        // declarators.
+        for (TIntermNode *declarator : *node->getSequence())
+        {
+            if (declarator->getAsTyped()->isArray())
+            {
+                return true;
+            }
+        }
+    }
+    if ((mMask & kNamelessStructDeclaration) != 0)
+    {
+        TIntermTyped *declarator = node->getSequence()->front()->getAsTyped();
+        if (declarator->getBasicType() == EbtStruct &&
+            declarator->getType().getStruct()->symbolType() == SymbolType::Empty)
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNodePatternMatcher.h
@@ -0,0 +1,79 @@
+//
+// Copyright (c) 2016 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.
+//
+// IntermNodePatternMatcher is a helper class for matching node trees to given patterns.
+// It can be used whenever the same checks for certain node structures are common to multiple AST
+// traversers.
+//
+
+#ifndef COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
+#define COMPILER_TRANSLATOR_INTERMNODEPATTERNMATCHER_H_
+
+namespace sh
+{
+
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermDeclaration;
+class TIntermNode;
+class TIntermTernary;
+class TIntermUnary;
+
+class IntermNodePatternMatcher
+{
+  public:
+    static bool IsDynamicIndexingOfVectorOrMatrix(TIntermBinary *node);
+
+    enum PatternType
+    {
+        // Matches expressions that are unfolded to if statements by UnfoldShortCircuitToIf
+        kUnfoldedShortCircuitExpression = 0x0001,
+
+        // Matches expressions that return arrays with the exception of simple statements where a
+        // constructor or function call result is assigned.
+        kExpressionReturningArray = 0x0001 << 1,
+
+        // Matches dynamic indexing of vectors or matrices in l-values.
+        kDynamicIndexingOfVectorOrMatrixInLValue = 0x0001 << 2,
+
+        // Matches declarations with more than one declared variables.
+        kMultiDeclaration = 0x0001 << 3,
+
+        // Matches declarations of arrays.
+        kArrayDeclaration = 0x0001 << 4,
+
+        // Matches declarations of structs where the struct type does not have a name.
+        kNamelessStructDeclaration = 0x0001 << 5,
+
+        // Matches array length() method.
+        kArrayLengthMethod = 0x0001 << 6,
+
+        // Matches a vector or matrix constructor whose arguments are scalarized by the
+        // SH_SCALARIZE_VEC_OR_MAT_CONSTRUCTOR_ARGUMENTS workaround.
+        kScalarizedVecOrMatConstructor = 0x0001 << 7
+    };
+    IntermNodePatternMatcher(const unsigned int mask);
+
+    bool match(TIntermUnary *node);
+
+    bool match(TIntermBinary *node, TIntermNode *parentNode);
+
+    // Use this version for checking binary node matches in case you're using flag
+    // kDynamicIndexingOfVectorOrMatrixInLValue.
+    bool match(TIntermBinary *node, TIntermNode *parentNode, bool isLValueRequiredHere);
+
+    bool match(TIntermAggregate *node, TIntermNode *parentNode);
+    bool match(TIntermTernary *node);
+    bool match(TIntermDeclaration *node);
+
+  private:
+    const unsigned int mMask;
+
+    bool matchInternal(TIntermBinary *node, TIntermNode *parentNode);
+};
+
+}  // namespace sh
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode_util.cpp
@@ -0,0 +1,269 @@
+//
+// 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.
+//
+// IntermNode_util.cpp: High-level utilities for creating AST nodes and node hierarchies. Mostly
+// meant to be used in AST transforms.
+
+#include "compiler/translator/IntermNode_util.h"
+
+#include "compiler/translator/FunctionLookup.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+const TFunction *LookUpBuiltInFunction(const char *name,
+                                       const TIntermSequence *arguments,
+                                       const TSymbolTable &symbolTable,
+                                       int shaderVersion)
+{
+    const ImmutableString &mangledName = TFunctionLookup::GetMangledName(name, *arguments);
+    const TSymbol *symbol              = symbolTable.findBuiltIn(mangledName, shaderVersion);
+    if (symbol)
+    {
+        ASSERT(symbol->isFunction());
+        return static_cast<const TFunction *>(symbol);
+    }
+    return nullptr;
+}
+
+}  // anonymous namespace
+
+TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func)
+{
+    return new TIntermFunctionPrototype(&func);
+}
+
+TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
+                                                                TIntermBlock *functionBody)
+{
+    return new TIntermFunctionDefinition(new TIntermFunctionPrototype(&func), functionBody);
+}
+
+TIntermTyped *CreateZeroNode(const TType &type)
+{
+    TType constType(type);
+    constType.setQualifier(EvqConst);
+
+    if (!type.isArray() && type.getBasicType() != EbtStruct)
+    {
+        size_t size       = constType.getObjectSize();
+        TConstantUnion *u = new TConstantUnion[size];
+        for (size_t i = 0; i < size; ++i)
+        {
+            switch (type.getBasicType())
+            {
+                case EbtFloat:
+                    u[i].setFConst(0.0f);
+                    break;
+                case EbtInt:
+                    u[i].setIConst(0);
+                    break;
+                case EbtUInt:
+                    u[i].setUConst(0u);
+                    break;
+                case EbtBool:
+                    u[i].setBConst(false);
+                    break;
+                default:
+                    // CreateZeroNode is called by ParseContext that keeps parsing even when an
+                    // error occurs, so it is possible for CreateZeroNode to be called with
+                    // non-basic types. This happens only on error condition but CreateZeroNode
+                    // needs to return a value with the correct type to continue the typecheck.
+                    // That's why we handle non-basic type by setting whatever value, we just need
+                    // the type to be right.
+                    u[i].setIConst(42);
+                    break;
+            }
+        }
+
+        TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
+        return node;
+    }
+
+    if (type.getBasicType() == EbtVoid)
+    {
+        // Void array. This happens only on error condition, similarly to the case above. We don't
+        // have a constructor operator for void, so this needs special handling. We'll end up with a
+        // value without the array type, but that should not be a problem.
+        while (constType.isArray())
+        {
+            constType.toArrayElementType();
+        }
+        return CreateZeroNode(constType);
+    }
+
+    TIntermSequence *arguments = new TIntermSequence();
+
+    if (type.isArray())
+    {
+        TType elementType(type);
+        elementType.toArrayElementType();
+
+        size_t arraySize = type.getOutermostArraySize();
+        for (size_t i = 0; i < arraySize; ++i)
+        {
+            arguments->push_back(CreateZeroNode(elementType));
+        }
+    }
+    else
+    {
+        ASSERT(type.getBasicType() == EbtStruct);
+
+        const TStructure *structure = type.getStruct();
+        for (const auto &field : structure->fields())
+        {
+            arguments->push_back(CreateZeroNode(*field->type()));
+        }
+    }
+
+    return TIntermAggregate::CreateConstructor(constType, arguments);
+}
+
+TIntermConstantUnion *CreateIndexNode(int index)
+{
+    TConstantUnion *u = new TConstantUnion[1];
+    u[0].setIConst(index);
+
+    TType type(EbtInt, EbpUndefined, EvqConst, 1);
+    TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+    return node;
+}
+
+TIntermConstantUnion *CreateBoolNode(bool value)
+{
+    TConstantUnion *u = new TConstantUnion[1];
+    u[0].setBConst(value);
+
+    TType type(EbtBool, EbpUndefined, EvqConst, 1);
+    TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+    return node;
+}
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type)
+{
+    ASSERT(symbolTable != nullptr);
+    // TODO(oetuaho): Might be useful to sanitize layout qualifier etc. on the type of the created
+    // variable. This might need to be done in other places as well.
+    return new TVariable(symbolTable, ImmutableString(""), type, SymbolType::AngleInternal);
+}
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier)
+{
+    ASSERT(symbolTable != nullptr);
+    if (type->getQualifier() == qualifier)
+    {
+        return CreateTempVariable(symbolTable, type);
+    }
+    TType *typeWithQualifier = new TType(*type);
+    typeWithQualifier->setQualifier(qualifier);
+    return CreateTempVariable(symbolTable, typeWithQualifier);
+}
+
+TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable)
+{
+    ASSERT(tempVariable->symbolType() == SymbolType::AngleInternal);
+    ASSERT(tempVariable->getType().getQualifier() == EvqTemporary ||
+           tempVariable->getType().getQualifier() == EvqConst ||
+           tempVariable->getType().getQualifier() == EvqGlobal);
+    return new TIntermSymbol(tempVariable);
+}
+
+TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable)
+{
+    TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
+    tempDeclaration->appendDeclarator(CreateTempSymbolNode(tempVariable));
+    return tempDeclaration;
+}
+
+TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
+                                                  TIntermTyped *initializer)
+{
+    ASSERT(initializer != nullptr);
+    TIntermSymbol *tempSymbol           = CreateTempSymbolNode(tempVariable);
+    TIntermDeclaration *tempDeclaration = new TIntermDeclaration();
+    TIntermBinary *tempInit             = new TIntermBinary(EOpInitialize, tempSymbol, initializer);
+    tempDeclaration->appendDeclarator(tempInit);
+    return tempDeclaration;
+}
+
+TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode)
+{
+    ASSERT(rightNode != nullptr);
+    TIntermSymbol *tempSymbol = CreateTempSymbolNode(tempVariable);
+    return new TIntermBinary(EOpAssign, tempSymbol, rightNode);
+}
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+                               const TType *type,
+                               TQualifier qualifier,
+                               TIntermDeclaration **declarationOut)
+{
+    TVariable *variable = CreateTempVariable(symbolTable, type, qualifier);
+    *declarationOut     = CreateTempDeclarationNode(variable);
+    return variable;
+}
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+                               TIntermTyped *initializer,
+                               TQualifier qualifier,
+                               TIntermDeclaration **declarationOut)
+{
+    TVariable *variable =
+        CreateTempVariable(symbolTable, new TType(initializer->getType()), qualifier);
+    *declarationOut     = CreateTempInitDeclarationNode(variable, initializer);
+    return variable;
+}
+
+TIntermBlock *EnsureBlock(TIntermNode *node)
+{
+    if (node == nullptr)
+        return nullptr;
+    TIntermBlock *blockNode = node->getAsBlock();
+    if (blockNode != nullptr)
+        return blockNode;
+
+    blockNode = new TIntermBlock();
+    blockNode->setLine(node->getLine());
+    blockNode->appendStatement(node);
+    return blockNode;
+}
+
+TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name, const TSymbolTable &symbolTable)
+{
+    const TVariable *var = reinterpret_cast<const TVariable *>(symbolTable.findGlobal(name));
+    ASSERT(var);
+    return new TIntermSymbol(var);
+}
+
+TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
+                                        const TSymbolTable &symbolTable,
+                                        int shaderVersion)
+{
+    const TVariable *var =
+        reinterpret_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion, true));
+    ASSERT(var);
+    return new TIntermSymbol(var);
+}
+
+TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
+                                            TIntermSequence *arguments,
+                                            const TSymbolTable &symbolTable,
+                                            int shaderVersion)
+{
+    const TFunction *fn = LookUpBuiltInFunction(name, arguments, symbolTable, shaderVersion);
+    ASSERT(fn);
+    TOperator op = fn->getBuiltInOp();
+    if (op != EOpCallBuiltInFunction && arguments->size() == 1)
+    {
+        return new TIntermUnary(op, arguments->at(0)->getAsTyped());
+    }
+    return TIntermAggregate::CreateBuiltInFunctionCall(*fn, arguments);
+}
+
+}  // namespace sh
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermNode_util.h
@@ -0,0 +1,67 @@
+//
+// 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.
+//
+// IntermNode_util.h: High-level utilities for creating AST nodes and node hierarchies. Mostly meant
+// to be used in AST transforms.
+
+#ifndef COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
+#define COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+class TVariable;
+
+TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(const TFunction &func);
+TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(const TFunction &func,
+                                                                TIntermBlock *functionBody);
+
+TIntermTyped *CreateZeroNode(const TType &type);
+TIntermConstantUnion *CreateIndexNode(int index);
+TIntermConstantUnion *CreateBoolNode(bool value);
+
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type);
+TVariable *CreateTempVariable(TSymbolTable *symbolTable, const TType *type, TQualifier qualifier);
+
+TIntermSymbol *CreateTempSymbolNode(const TVariable *tempVariable);
+TIntermDeclaration *CreateTempDeclarationNode(const TVariable *tempVariable);
+TIntermDeclaration *CreateTempInitDeclarationNode(const TVariable *tempVariable,
+                                                  TIntermTyped *initializer);
+TIntermBinary *CreateTempAssignmentNode(const TVariable *tempVariable, TIntermTyped *rightNode);
+
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+                               const TType *type,
+                               TQualifier qualifier,
+                               TIntermDeclaration **declarationOut);
+TVariable *DeclareTempVariable(TSymbolTable *symbolTable,
+                               TIntermTyped *initializer,
+                               TQualifier qualifier,
+                               TIntermDeclaration **declarationOut);
+
+// If the input node is nullptr, return nullptr.
+// If the input node is a block node, return it.
+// If the input node is not a block node, put it inside a block node and return that.
+TIntermBlock *EnsureBlock(TIntermNode *node);
+
+// Should be called from inside Compiler::compileTreeImpl() where the global level is in scope.
+TIntermSymbol *ReferenceGlobalVariable(const ImmutableString &name,
+                                       const TSymbolTable &symbolTable);
+
+// Note: this can access desktop GLSL built-ins that are hidden from the parser.
+TIntermSymbol *ReferenceBuiltInVariable(const ImmutableString &name,
+                                        const TSymbolTable &symbolTable,
+                                        int shaderVersion);
+
+TIntermTyped *CreateBuiltInFunctionCallNode(const char *name,
+                                            TIntermSequence *arguments,
+                                            const TSymbolTable &symbolTable,
+                                            int shaderVersion);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_INTERMNODEUTIL_H_
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/IntermTraverse.cpp
@@ -0,0 +1,851 @@
+//
+// Copyright (c) 2002-2010 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.
+//
+
+#include "compiler/translator/IntermTraverse.h"
+
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermNode_util.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+void TIntermSymbol::traverse(TIntermTraverser *it)
+{
+    it->traverseSymbol(this);
+}
+
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+    it->traverseRaw(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser *it)
+{
+    it->traverseConstantUnion(this);
+}
+
+void TIntermSwizzle::traverse(TIntermTraverser *it)
+{
+    it->traverseSwizzle(this);
+}
+
+void TIntermBinary::traverse(TIntermTraverser *it)
+{
+    it->traverseBinary(this);
+}
+
+void TIntermUnary::traverse(TIntermTraverser *it)
+{
+    it->traverseUnary(this);
+}
+
+void TIntermTernary::traverse(TIntermTraverser *it)
+{
+    it->traverseTernary(this);
+}
+
+void TIntermIfElse::traverse(TIntermTraverser *it)
+{
+    it->traverseIfElse(this);
+}
+
+void TIntermSwitch::traverse(TIntermTraverser *it)
+{
+    it->traverseSwitch(this);
+}
+
+void TIntermCase::traverse(TIntermTraverser *it)
+{
+    it->traverseCase(this);
+}
+
+void TIntermFunctionDefinition::traverse(TIntermTraverser *it)
+{
+    it->traverseFunctionDefinition(this);
+}
+
+void TIntermBlock::traverse(TIntermTraverser *it)
+{
+    it->traverseBlock(this);
+}
+
+void TIntermInvariantDeclaration::traverse(TIntermTraverser *it)
+{
+    it->traverseInvariantDeclaration(this);
+}
+
+void TIntermDeclaration::traverse(TIntermTraverser *it)
+{
+    it->traverseDeclaration(this);
+}
+
+void TIntermFunctionPrototype::traverse(TIntermTraverser *it)
+{
+    it->traverseFunctionPrototype(this);
+}
+
+void TIntermAggregate::traverse(TIntermTraverser *it)
+{
+    it->traverseAggregate(this);
+}
+
+void TIntermLoop::traverse(TIntermTraverser *it)
+{
+    it->traverseLoop(this);
+}
+
+void TIntermBranch::traverse(TIntermTraverser *it)
+{
+    it->traverseBranch(this);
+}
+
+TIntermTraverser::TIntermTraverser(bool preVisit,
+                                   bool inVisit,
+                                   bool postVisit,
+                                   TSymbolTable *symbolTable)
+    : preVisit(preVisit),
+      inVisit(inVisit),
+      postVisit(postVisit),
+      mDepth(-1),
+      mMaxDepth(0),
+      mInGlobalScope(true),
+      mSymbolTable(symbolTable)
+{
+}
+
+TIntermTraverser::~TIntermTraverser()
+{
+}
+
+const TIntermBlock *TIntermTraverser::getParentBlock() const
+{
+    if (!mParentBlockStack.empty())
+    {
+        return mParentBlockStack.back().node;
+    }
+    return nullptr;
+}
+
+void TIntermTraverser::pushParentBlock(TIntermBlock *node)
+{
+    mParentBlockStack.push_back(ParentBlock(node, 0));
+}
+
+void TIntermTraverser::incrementParentBlockPos()
+{
+    ++mParentBlockStack.back().pos;
+}
+
+void TIntermTraverser::popParentBlock()
+{
+    ASSERT(!mParentBlockStack.empty());
+    mParentBlockStack.pop_back();
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertions)
+{
+    TIntermSequence emptyInsertionsAfter;
+    insertStatementsInParentBlock(insertions, emptyInsertionsAfter);
+}
+
+void TIntermTraverser::insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+                                                     const TIntermSequence &insertionsAfter)
+{
+    ASSERT(!mParentBlockStack.empty());
+    ParentBlock &parentBlock = mParentBlockStack.back();
+    if (mPath.back() == parentBlock.node)
+    {
+        ASSERT(mParentBlockStack.size() >= 2u);
+        // The current node is a block node, so the parent block is not the topmost one in the block
+        // stack, but the one below that.
+        parentBlock = mParentBlockStack.at(mParentBlockStack.size() - 2u);
+    }
+    NodeInsertMultipleEntry insert(parentBlock.node, parentBlock.pos, insertionsBefore,
+                                   insertionsAfter);
+    mInsertions.push_back(insert);
+}
+
+void TIntermTraverser::insertStatementInParentBlock(TIntermNode *statement)
+{
+    TIntermSequence insertions;
+    insertions.push_back(statement);
+    insertStatementsInParentBlock(insertions);
+}
+
+void TLValueTrackingTraverser::setInFunctionCallOutParameter(bool inOutParameter)
+{
+    mInFunctionCallOutParameter = inOutParameter;
+}
+
+bool TLValueTrackingTraverser::isInFunctionCallOutParameter() const
+{
+    return mInFunctionCallOutParameter;
+}
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermTraverser::traverseSymbol(TIntermSymbol *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+    visitSymbol(node);
+}
+
+void TIntermTraverser::traverseConstantUnion(TIntermConstantUnion *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+    visitConstantUnion(node);
+}
+
+void TIntermTraverser::traverseSwizzle(TIntermSwizzle *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    if (preVisit)
+        visit = visitSwizzle(PreVisit, node);
+
+    if (visit)
+    {
+        node->getOperand()->traverse(this);
+    }
+
+    if (visit && postVisit)
+        visitSwizzle(PostVisit, node);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermTraverser::traverseBinary(TIntermBinary *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    //
+    // visit the node before children if pre-visiting.
+    //
+    if (preVisit)
+        visit = visitBinary(PreVisit, node);
+
+    //
+    // Visit the children, in the right order.
+    //
+    if (visit)
+    {
+        if (node->getLeft())
+            node->getLeft()->traverse(this);
+
+        if (inVisit)
+            visit = visitBinary(InVisit, node);
+
+        if (visit && node->getRight())
+            node->getRight()->traverse(this);
+    }
+
+    //
+    // Visit the node after the children, if requested and the traversal
+    // hasn't been cancelled yet.
+    //
+    if (visit && postVisit)
+        visitBinary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseBinary(TIntermBinary *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    //
+    // visit the node before children if pre-visiting.
+    //
+    if (preVisit)
+        visit = visitBinary(PreVisit, node);
+
+    //
+    // Visit the children, in the right order.
+    //
+    if (visit)
+    {
+        // Some binary operations like indexing can be inside an expression which must be an
+        // l-value.
+        bool parentOperatorRequiresLValue     = operatorRequiresLValue();
+        bool parentInFunctionCallOutParameter = isInFunctionCallOutParameter();
+        if (node->isAssignment())
+        {
+            ASSERT(!isLValueRequiredHere());
+            setOperatorRequiresLValue(true);
+        }
+
+        if (node->getLeft())
+            node->getLeft()->traverse(this);
+
+        if (inVisit)
+            visit = visitBinary(InVisit, node);
+
+        if (node->isAssignment())
+            setOperatorRequiresLValue(false);
+
+        // Index is not required to be an l-value even when the surrounding expression is required
+        // to be an l-value.
+        TOperator op = node->getOp();
+        if (op == EOpIndexDirect || op == EOpIndexDirectInterfaceBlock ||
+            op == EOpIndexDirectStruct || op == EOpIndexIndirect)
+        {
+            setOperatorRequiresLValue(false);
+            setInFunctionCallOutParameter(false);
+        }
+
+        if (visit && node->getRight())
+            node->getRight()->traverse(this);
+
+        setOperatorRequiresLValue(parentOperatorRequiresLValue);
+        setInFunctionCallOutParameter(parentInFunctionCallOutParameter);
+    }
+
+    //
+    // Visit the node after the children, if requested and the traversal
+    // hasn't been cancelled yet.
+    //
+    if (visit && postVisit)
+        visitBinary(PostVisit, node);
+}
+
+//
+// Traverse a unary node.  Same comments in binary node apply here.
+//
+void TIntermTraverser::traverseUnary(TIntermUnary *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    if (preVisit)
+        visit = visitUnary(PreVisit, node);
+
+    if (visit)
+    {
+        node->getOperand()->traverse(this);
+    }
+
+    if (visit && postVisit)
+        visitUnary(PostVisit, node);
+}
+
+void TLValueTrackingTraverser::traverseUnary(TIntermUnary *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    if (preVisit)
+        visit = visitUnary(PreVisit, node);
+
+    if (visit)
+    {
+        ASSERT(!operatorRequiresLValue());
+        switch (node->getOp())
+        {
+            case EOpPostIncrement:
+            case EOpPostDecrement:
+            case EOpPreIncrement:
+            case EOpPreDecrement:
+                setOperatorRequiresLValue(true);
+                break;
+            default:
+                break;
+        }
+
+        node->getOperand()->traverse(this);
+
+        setOperatorRequiresLValue(false);
+    }
+
+    if (visit && postVisit)
+        visitUnary(PostVisit, node);
+}
+
+// Traverse a function definition node.
+void TIntermTraverser::traverseFunctionDefinition(TIntermFunctionDefinition *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    if (preVisit)
+        visit = visitFunctionDefinition(PreVisit, node);
+
+    if (visit)
+    {
+        mInGlobalScope = false;
+
+        node->getFunctionPrototype()->traverse(this);
+        if (inVisit)
+            visit = visitFunctionDefinition(InVisit, node);
+        node->getBody()->traverse(this);
+
+        mInGlobalScope = true;
+    }
+
+    if (visit && postVisit)
+        visitFunctionDefinition(PostVisit, node);
+}
+
+// Traverse a block node.
+void TIntermTraverser::traverseBlock(TIntermBlock *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+    pushParentBlock(node);
+
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitBlock(PreVisit, node);
+
+    if (visit)
+    {
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitBlock(InVisit, node);
+            }
+
+            incrementParentBlockPos();
+        }
+    }
+
+    if (visit && postVisit)
+        visitBlock(PostVisit, node);
+
+    popParentBlock();
+}
+
+void TIntermTraverser::traverseInvariantDeclaration(TIntermInvariantDeclaration *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    if (preVisit)
+    {
+        visit = visitInvariantDeclaration(PreVisit, node);
+    }
+
+    if (visit)
+    {
+        node->getSymbol()->traverse(this);
+        if (postVisit)
+        {
+            visitInvariantDeclaration(PostVisit, node);
+        }
+    }
+}
+
+// Traverse a declaration node.
+void TIntermTraverser::traverseDeclaration(TIntermDeclaration *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitDeclaration(PreVisit, node);
+
+    if (visit)
+    {
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitDeclaration(InVisit, node);
+            }
+        }
+    }
+
+    if (visit && postVisit)
+        visitDeclaration(PostVisit, node);
+}
+
+void TIntermTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitFunctionPrototype(PreVisit, node);
+
+    if (visit)
+    {
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitFunctionPrototype(InVisit, node);
+            }
+        }
+    }
+
+    if (visit && postVisit)
+        visitFunctionPrototype(PostVisit, node);
+}
+
+// Traverse an aggregate node.  Same comments in binary node apply here.
+void TIntermTraverser::traverseAggregate(TIntermAggregate *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitAggregate(PreVisit, node);
+
+    if (visit)
+    {
+        for (auto *child : *sequence)
+        {
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitAggregate(InVisit, node);
+            }
+        }
+    }
+
+    if (visit && postVisit)
+        visitAggregate(PostVisit, node);
+}
+
+bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
+                                        const NodeInsertMultipleEntry &b)
+{
+    if (a.parent != b.parent)
+    {
+        return a.parent > b.parent;
+    }
+    return a.position > b.position;
+}
+
+void TIntermTraverser::updateTree()
+{
+    // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
+    // the same parent node are handled correctly.
+    std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
+    for (size_t ii = 0; ii < mInsertions.size(); ++ii)
+    {
+        // We can't know here what the intended ordering of two insertions to the same position is,
+        // so it is not supported.
+        ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
+               mInsertions[ii].parent != mInsertions[ii - 1].parent);
+        const NodeInsertMultipleEntry &insertion = mInsertions[ii];
+        ASSERT(insertion.parent);
+        if (!insertion.insertionsAfter.empty())
+        {
+            bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+                                                               insertion.insertionsAfter);
+            ASSERT(inserted);
+        }
+        if (!insertion.insertionsBefore.empty())
+        {
+            bool inserted =
+                insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+            ASSERT(inserted);
+        }
+    }
+    for (size_t ii = 0; ii < mReplacements.size(); ++ii)
+    {
+        const NodeUpdateEntry &replacement = mReplacements[ii];
+        ASSERT(replacement.parent);
+        bool replaced =
+            replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
+        ASSERT(replaced);
+
+        if (!replacement.originalBecomesChildOfReplacement)
+        {
+            // In AST traversing, a parent is visited before its children.
+            // After we replace a node, if its immediate child is to
+            // be replaced, we need to make sure we don't update the replaced
+            // node; instead, we update the replacement node.
+            for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
+            {
+                NodeUpdateEntry &replacement2 = mReplacements[jj];
+                if (replacement2.parent == replacement.original)
+                    replacement2.parent = replacement.replacement;
+            }
+        }
+    }
+    for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
+    {
+        const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
+        ASSERT(replacement.parent);
+        bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
+                                                                         replacement.replacements);
+        ASSERT(replaced);
+    }
+
+    clearReplacementQueue();
+}
+
+void TIntermTraverser::clearReplacementQueue()
+{
+    mReplacements.clear();
+    mMultiReplacements.clear();
+    mInsertions.clear();
+}
+
+void TIntermTraverser::queueReplacement(TIntermNode *replacement, OriginalNode originalStatus)
+{
+    queueReplacementWithParent(getParentNode(), mPath.back(), replacement, originalStatus);
+}
+
+void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
+                                                  TIntermNode *original,
+                                                  TIntermNode *replacement,
+                                                  OriginalNode originalStatus)
+{
+    bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
+    mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
+}
+
+TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
+                                                   bool inVisit,
+                                                   bool postVisit,
+                                                   TSymbolTable *symbolTable)
+    : TIntermTraverser(preVisit, inVisit, postVisit, symbolTable),
+      mOperatorRequiresLValue(false),
+      mInFunctionCallOutParameter(false)
+{
+    ASSERT(symbolTable);
+}
+
+void TLValueTrackingTraverser::traverseAggregate(TIntermAggregate *node)
+{
+    ScopedNodeInTraversalPath addToPath(this, node);
+
+    bool visit = true;
+
+    TIntermSequence *sequence = node->getSequence();
+
+    if (preVisit)
+        visit = visitAggregate(PreVisit, node);
+
+    if (visit)
+    {
+        size_t paramIndex = 0u;
+        for (auto *child : *sequence)
+        {
+            if (node->getFunction())
+            {
+                // Both built-ins and user defined functions should have the function symbol set.
+                ASSERT(paramIndex < node->getFunction()->getParamCount());
+                TQualifier qualifier =
+                    node->getFunction()->getParam(paramIndex).type->getQualifier();
+                setInFunctionCallOutParameter(qualifier == EvqOut || qualifier == EvqInOut);
+                ++paramIndex;
+            }
+            else
+            {
+                ASSERT(node->isConstructor());
+            }
+
+            child->traverse(this);
+            if (visit && inVisit)
+            {
+                if (child != sequence->back())
+                    visit = visitAggregate(InVisit, node);
+            }
+        }
+        setInFunctionCallOutParameter(false);
+    }
+
+    if (visit && postVisit)