Merge pull request #919 from billhollings/VK_EXTX_portability_subset

Update from master branch.
diff --git a/.travis.yml b/.travis.yml
index 04394cf..3856b71 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,13 +2,11 @@
 
 # macOS and Xcode Version
 os: osx
-osx_image: xcode11.3
+osx_image: xcode11.5
 
-# Build dependencies
-# Travis has trouble with python3, which SPIRV-Tools requires,
-# so skip the SPIRV-Tools build, and use templeted headers instead.
+# Build dependencies with verbose logging to avoid Travis timing out.
 install:
-  - ./fetchDependencies -v --skip-spirv-tools-build
+  - ./fetchDependencies -v
 
 script:
   - xcodebuild -project MoltenVKPackaging.xcodeproj -scheme "MoltenVK Package"
diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h
index 8e7e821..83adaae 100644
--- a/Common/MVKOSExtensions.h
+++ b/Common/MVKOSExtensions.h
@@ -18,12 +18,17 @@
 
 #pragma once
 
+#include "MVKCommonEnvironment.h"
 #include <dispatch/dispatch.h>
 #include <string>
+#include <limits>
 
 
 typedef float MVKOSVersion;
 
+/*** Constant indicating unsupported functionality in an OS. */
+static const MVKOSVersion kMVKOSVersionUnsupported = std::numeric_limits<MVKOSVersion>::max();
+
 /**
  * Returns the operating system version as an MVKOSVersion, which is a float in which the
  * whole number portion indicates the major version, and the fractional portion indicates 
@@ -33,10 +38,30 @@
  */
 MVKOSVersion mvkOSVersion();
 
+/** Returns a MVKOSVersion built from the version components. */
+inline MVKOSVersion mvkMakeOSVersion(uint32_t major, uint32_t minor, uint32_t patch) {
+	return (float)major + ((float)minor / 100.0f) + ((float)patch / 10000.0f);
+}
+
 /** Returns whether the operating system version is at least minVer. */
 inline bool mvkOSVersionIsAtLeast(MVKOSVersion minVer) { return mvkOSVersion() >= minVer; }
 
 /**
+ * Returns whether the operating system version is at least the appropriate min version.
+ * The constant kMVKOSVersionUnsupported can be used for either value to cause the test
+ * to always fail on that OS, which is useful for indidicating functionalty guarded by
+ * this test is not supported on that OS.
+ */
+inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer, MVKOSVersion iOSMinVer) {
+#if MVK_MACOS
+	return mvkOSVersionIsAtLeast(macOSMinVer);
+#endif
+#if MVK_IOS
+	return mvkOSVersionIsAtLeast(iOSMinVer);
+#endif
+}
+
+/**
  * Returns a monotonic timestamp value for use in Vulkan and performance timestamping.
  *
  * The returned value corresponds to the number of CPU "ticks" since the app was initialized.
diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm
index f04484c..2783777 100644
--- a/Common/MVKOSExtensions.mm
+++ b/Common/MVKOSExtensions.mm
@@ -29,17 +29,13 @@
 
 using namespace std;
 
-static const MVKOSVersion kMVKOSVersionUnknown = 0.0f;
-static MVKOSVersion _mvkOSVersion = kMVKOSVersionUnknown;
 MVKOSVersion mvkOSVersion() {
-    if (_mvkOSVersion == kMVKOSVersionUnknown) {
-        NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion];
-        float maj = osVer.majorVersion;
-        float min = osVer.minorVersion;
-        float pat = osVer.patchVersion;
-        _mvkOSVersion = maj + (min / 100.0f) +  + (pat / 10000.0f);
-    }
-    return _mvkOSVersion;
+	static MVKOSVersion _mvkOSVersion = 0;
+	if ( !_mvkOSVersion ) {
+		NSOperatingSystemVersion osVer = [[NSProcessInfo processInfo] operatingSystemVersion];
+		_mvkOSVersion = mvkMakeOSVersion((uint32_t)osVer.majorVersion, (uint32_t)osVer.minorVersion, (uint32_t)osVer.patchVersion);
+	}
+	return _mvkOSVersion;
 }
 
 static uint64_t _mvkTimestampBase;
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
index b63defa..145fcef 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
@@ -547,7 +547,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */;
 			compatibilityVersion = "Xcode 8.0";
@@ -659,7 +659,6 @@
 				PRODUCT_NAME = "API-Samples";
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
@@ -681,7 +680,6 @@
 				PRODUCT_NAME = "API-Samples";
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -738,6 +736,7 @@
 		C01FCF4F08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
@@ -768,6 +767,7 @@
 		C01FCF5008A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
index 620a035..fd267bd 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
index 283d573..029bc89 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/generateSPIRVShaders b/Demos/LunarG-VulkanSamples/API-Samples/generateSPIRVShaders
index b234111..3233861 100755
--- a/Demos/LunarG-VulkanSamples/API-Samples/generateSPIRVShaders
+++ b/Demos/LunarG-VulkanSamples/API-Samples/generateSPIRVShaders
@@ -10,27 +10,14 @@
 set -e
 
 echo
-echo ========== Building MoltenVKShaderConverter tool ==========
+echo ========== Converting API-Samples shader files ==========
 echo
 
 cd "../../.."
 
-XC_PROJ="MoltenVKPackaging.xcodeproj"
-XC_SCHEME="MVKShaderConverterTool Package"
-
-xcodebuild  \
-	-project "MoltenVKPackaging.xcodeproj"  \
-	-scheme "MVKShaderConverterTool Package"  \
-	-quiet  \
-	build
-
-echo
-echo ========== Converting API-Samples shader files ==========
-echo
-
 "Package/Latest/MoltenVKShaderConverter/Tools/MoltenVKShaderConverter"  \
  -r -gi -so -oh -xs . -q  \
- -d "Demos/LunarG-VulkanSamples/VulkanSamples/API-Samples"
+ -d "Demos/LunarG-VulkanSamples/VulkanSamples/API-Samples" > /dev/null
 
 cd -  > /dev/null
 
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
index afb8606..2766dab 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
@@ -234,7 +234,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */;
 			compatibilityVersion = "Xcode 8.0";
@@ -359,7 +359,6 @@
 				PRODUCT_NAME = Cube;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
@@ -380,13 +379,13 @@
 				PRODUCT_NAME = Cube;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
 		C01FCF4F08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
@@ -417,6 +416,7 @@
 		C01FCF5008A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
index b6cace4..23b9271 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
index 7a4cf00..756dba9 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
index 9058306..3f77a1b 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
@@ -265,7 +265,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */;
 			compatibilityVersion = "Xcode 8.0";
@@ -360,7 +360,6 @@
 				LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/iOS/static\"";
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
@@ -375,7 +374,6 @@
 				LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../../../MoltenVK/iOS/static\"";
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -416,6 +414,7 @@
 		C01FCF4F08A954540054247B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
@@ -448,6 +447,7 @@
 		C01FCF5008A954540054247B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = YES;
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
index 38a9ae3..d2069b0 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
index 7ad255a..30d2b38 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 826bfee..80528d5 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -63,7 +63,7 @@
 *Vulkan*, which uses *SPIR-V*. **MoltenVK** automatically converts your *SPIR-V* shaders 
 to their *MSL* equivalents. This can be performed transparently at run time, using the 
 **Runtime Shader Conversion** feature of **MoltenVK**, or at development time using the 
-[**MoltenVKShaderConverter**] (#shader_converter_tool) tool provided with this **MoltenVK** 
+[**MoltenVKShaderConverter**](#shader_converter_tool) tool provided with this **MoltenVK** 
 distribution package.
 
 To provide *Vulkan* capability to the *iOS* and *macOS* platforms, **MoltenVK** uses *Apple's* 
@@ -256,6 +256,7 @@
 - `VK_KHR_push_descriptor`
 - `VK_KHR_relaxed_block_layout`
 - `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
+- `VK_KHR_sampler_ycbcr_conversion`
 - `VK_KHR_shader_draw_parameters`
 - `VK_KHR_shader_float16_int8`
 - `VK_KHR_storage_buffer_storage_class`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index ca421d0..10448f5 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -13,21 +13,90 @@
 
 
 
-
-MoltenVK 1.0.42
+MoltenVK 1.0.44
 ---------------
 
 Released TBD
 
+- Remove use of `@available()` directive as it was causing issues in some build environments
+- Refactor **MoltenVK** *Xcode* build architectures
+- Demo `API-Samples generateSPIRVShaders` no longer builds `MoltenVKShaderController` tool.
+
+
+MoltenVK 1.0.43
+---------------
+
+Released 2020/06/09
+
+- Fix issue in reporting properties of substitutable `VkFormats`.
+- Fix vertex attribute offset adjustments when vertex buffer stride is zero.
+- Update `fetchDependencies` script to use pre-built `spirv-tools` files by default.
+- Update `maxVertexInputBindingStride` and `maxVertexInputAttributeOffset` 
+  to minimum Vulkan values.
+- Numerous documentation typo corrections.
+- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to `26`.
+- Update Travis CI to Xcode 11.5.
+
+
+
+MoltenVK 1.0.42
+---------------
+
+Released 2020/06/01
+
+- Add support for extensions:
+	- `VK_GOOGLE_display_timing`
+	- `VK_KHR_external_memory` (non-functional groundwork for future 
+	  Metal-resource Vulkan extension).
+	- `VK_KHR_external_memory_capabilities` (non-functional groundwork 
+	   for future Metal-resource Vulkan extension).
+- Memory consumption improvements in command handling and vector pre-allocation optimizations.
+- `vkQueuePresentKHR()` returns a `VkResult` for each swapchain.
+- `MVKPipeline` disable fragment shader outputs for unused attachments.
+- `MVKBuffer` support texel buffers in host-coherent memory on Mac.
+- `MVKDescriptor` pass buffers to shaders that do atomic image accesses.
+- Support vertex attribute offsets larger than the vertex buffer stride.
+- Fix crash when more than two GPUs.
+- Fix issue where `vkGetPhysicalDeviceFormatProperties()` incorrectly returned 
+  properties for unsupported formats.
+- Fix stack overflow in when logging and reporting very long messages.
+- Fix situation where compute pipeline state not retained across copy and renderpass operations.
+- Fix buffer offset calculation.
+- Fixes to maximum FPS calculations.
+- Fix buffer size passed to shaders when `VkDescriptorBufferInfo.range` set to `VK_WHOLE_SIZE`.
+- Update maximum number of framebuffer layers to 2048.
+- Support stencil only image formats in identity swizzle case.
+- Enables format atomic capabilities only when format supports it.
+- Add `MVKSmallVector` as a more memory efficient substitute of `MVKVector`.
 - Reinstate `VulkanSamples API-Samples` demo apps and add 
   `input_attachment` and `push_descriptors` demos.
-- `vkQueuePresentKHR()` returns a `VkResult` for each swapchain.
+- Add `MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE` environment variable 
+  to support capturing GPU traces to a file.
 - Consolidate frame and non-frame performance reporting.
 	- Remove `vkGetSwapchainPerformanceMVK()` from API.
 	- Swapchain performance can be retrieved with other activity performance 
 	  through `vkGetPerformanceStatisticsMVK()`.
 	- Add `MVK_CONFIG_PERFORMANCE_LOGGING_INLINE` env var to enable/disable
 	  logging of performance of each activity when it happens. 
+	- Reduce thread locking on performance statistics collection.
+- Numerous documentation typo corrections.
+- Support Xcode 11.5.
+- Update dependency libraries to match *Vulkan SDK 1.2.141*.
+- Update to latest SPIRV-Cross version:
+	- MSL: mark `BuiltInFragCoord` as implicitly used for subpass reads.
+	- MSL: Deal with cases where builtin is implicitly needed, declared, but unused.
+	- MSL: Do not use base expression with PhysicalTypeID `OpCompositeExtract`.
+	- MSL: Add options to control emission of fragment outputs.
+	- MSL: Force disabled fragment builtins to have the right name.
+	- MSL: Allow removing clip distance user varyings.
+	- MSL: Support edge case with DX layout in scalar block layout.
+	- MSL: Deal correctly with initializers on Private variables.
+	- MSL: Fix case where `subpassInput` is passed to leaf functions.
+	- MSL: Redirect member indices when buffer has been sorted by Offset.
+	- MSL: If the packed type is scalar, don't emit "pack_" prefix.
+	- MSL: Avoid packed arrays in more cases.
+	- Do not add NonWritable/NonReadable decorations for regular images.
+	- Expose a query if samplers or images are comparison resources.
 
 
 
diff --git a/ExternalDependencies.xcodeproj/project.pbxproj b/ExternalDependencies.xcodeproj/project.pbxproj
index 1b0f51c..578b93f 100644
--- a/ExternalDependencies.xcodeproj/project.pbxproj
+++ b/ExternalDependencies.xcodeproj/project.pbxproj
@@ -54,776 +54,6 @@
 		450A4F66221C5A95007203D7 /* spirv_reflect.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F63221C5A95007203D7 /* spirv_reflect.hpp */; };
 		450A4F67221C5A95007203D7 /* spirv_reflect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F64221C5A95007203D7 /* spirv_reflect.cpp */; };
 		450A4F68221C5A95007203D7 /* spirv_reflect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F64221C5A95007203D7 /* spirv_reflect.cpp */; };
-		A9415A87243667F700566F16 /* spirv_target_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941583F243667F600566F16 /* spirv_target_env.cpp */; };
-		A9415A88243667F700566F16 /* spirv_target_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941583F243667F600566F16 /* spirv_target_env.cpp */; };
-		A9415A89243667F700566F16 /* spirv_fuzzer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415841243667F600566F16 /* spirv_fuzzer_options.h */; };
-		A9415A8A243667F700566F16 /* spirv_fuzzer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415841243667F600566F16 /* spirv_fuzzer_options.h */; };
-		A9415A8B243667F700566F16 /* assembly_grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415842243667F600566F16 /* assembly_grammar.h */; };
-		A9415A8C243667F700566F16 /* assembly_grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415842243667F600566F16 /* assembly_grammar.h */; };
-		A9415A8D243667F700566F16 /* enum_set.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415843243667F600566F16 /* enum_set.h */; };
-		A9415A8E243667F700566F16 /* enum_set.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415843243667F600566F16 /* enum_set.h */; };
-		A9415A8F243667F700566F16 /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415846243667F600566F16 /* text.cpp */; };
-		A9415A90243667F700566F16 /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415846243667F600566F16 /* text.cpp */; };
-		A9415A91243667F700566F16 /* assembly_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415847243667F600566F16 /* assembly_grammar.cpp */; };
-		A9415A92243667F700566F16 /* assembly_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415847243667F600566F16 /* assembly_grammar.cpp */; };
-		A9415A93243667F700566F16 /* text.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415848243667F600566F16 /* text.h */; };
-		A9415A94243667F700566F16 /* text.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415848243667F600566F16 /* text.h */; };
-		A9415A95243667F700566F16 /* extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415849243667F600566F16 /* extensions.cpp */; };
-		A9415A96243667F700566F16 /* extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415849243667F600566F16 /* extensions.cpp */; };
-		A9415A97243667F700566F16 /* pch_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941584A243667F600566F16 /* pch_source.cpp */; };
-		A9415A98243667F700566F16 /* pch_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941584A243667F600566F16 /* pch_source.cpp */; };
-		A9415A99243667F700566F16 /* parse_number.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584C243667F600566F16 /* parse_number.h */; };
-		A9415A9A243667F700566F16 /* parse_number.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584C243667F600566F16 /* parse_number.h */; };
-		A9415A9B243667F700566F16 /* ilist_node.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584D243667F600566F16 /* ilist_node.h */; };
-		A9415A9C243667F700566F16 /* ilist_node.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584D243667F600566F16 /* ilist_node.h */; };
-		A9415A9D243667F700566F16 /* make_unique.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584E243667F600566F16 /* make_unique.h */; };
-		A9415A9E243667F700566F16 /* make_unique.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584E243667F600566F16 /* make_unique.h */; };
-		A9415A9F243667F700566F16 /* string_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584F243667F600566F16 /* string_utils.h */; };
-		A9415AA0243667F700566F16 /* string_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A941584F243667F600566F16 /* string_utils.h */; };
-		A9415AA1243667F700566F16 /* small_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415850243667F600566F16 /* small_vector.h */; };
-		A9415AA2243667F700566F16 /* small_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415850243667F600566F16 /* small_vector.h */; };
-		A9415AA3243667F700566F16 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415851243667F600566F16 /* timer.cpp */; };
-		A9415AA4243667F700566F16 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415851243667F600566F16 /* timer.cpp */; };
-		A9415AA5243667F700566F16 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415852243667F600566F16 /* timer.h */; };
-		A9415AA6243667F700566F16 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415852243667F600566F16 /* timer.h */; };
-		A9415AA7243667F700566F16 /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415853243667F600566F16 /* string_utils.cpp */; };
-		A9415AA8243667F700566F16 /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415853243667F600566F16 /* string_utils.cpp */; };
-		A9415AA9243667F700566F16 /* bit_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415854243667F600566F16 /* bit_vector.h */; };
-		A9415AAA243667F700566F16 /* bit_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415854243667F600566F16 /* bit_vector.h */; };
-		A9415AAB243667F700566F16 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415855243667F600566F16 /* bitutils.h */; };
-		A9415AAC243667F700566F16 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415855243667F600566F16 /* bitutils.h */; };
-		A9415AAD243667F700566F16 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415856243667F600566F16 /* hex_float.h */; };
-		A9415AAE243667F700566F16 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415856243667F600566F16 /* hex_float.h */; };
-		A9415AAF243667F700566F16 /* parse_number.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415857243667F600566F16 /* parse_number.cpp */; };
-		A9415AB0243667F700566F16 /* parse_number.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415857243667F600566F16 /* parse_number.cpp */; };
-		A9415AB1243667F700566F16 /* bit_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415858243667F600566F16 /* bit_vector.cpp */; };
-		A9415AB2243667F700566F16 /* bit_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415858243667F600566F16 /* bit_vector.cpp */; };
-		A9415AB3243667F700566F16 /* ilist.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415859243667F600566F16 /* ilist.h */; };
-		A9415AB4243667F700566F16 /* ilist.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415859243667F600566F16 /* ilist.h */; };
-		A9415AB5243667F700566F16 /* spirv_target_env.h in Headers */ = {isa = PBXBuildFile; fileRef = A941585A243667F600566F16 /* spirv_target_env.h */; };
-		A9415AB6243667F700566F16 /* spirv_target_env.h in Headers */ = {isa = PBXBuildFile; fileRef = A941585A243667F600566F16 /* spirv_target_env.h */; };
-		A9415AB7243667F700566F16 /* table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941585B243667F600566F16 /* table.cpp */; };
-		A9415AB8243667F700566F16 /* table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941585B243667F600566F16 /* table.cpp */; };
-		A9415AB9243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941585E243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.h */; };
-		A9415ABA243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941585E243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.h */; };
-		A9415ABB243667F700566F16 /* remove_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941585F243667F600566F16 /* remove_selection_reduction_opportunity.cpp */; };
-		A9415ABC243667F700566F16 /* remove_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941585F243667F600566F16 /* remove_selection_reduction_opportunity.cpp */; };
-		A9415ABD243667F700566F16 /* remove_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415860243667F600566F16 /* remove_block_reduction_opportunity.h */; };
-		A9415ABE243667F700566F16 /* remove_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415860243667F600566F16 /* remove_block_reduction_opportunity.h */; };
-		A9415ABF243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415861243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h */; };
-		A9415AC0243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415861243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h */; };
-		A9415AC1243667F700566F16 /* reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415862243667F600566F16 /* reduction_pass.cpp */; };
-		A9415AC2243667F700566F16 /* reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415862243667F600566F16 /* reduction_pass.cpp */; };
-		A9415AC3243667F700566F16 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415863243667F600566F16 /* operand_to_const_reduction_opportunity_finder.cpp */; };
-		A9415AC4243667F700566F16 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415863243667F600566F16 /* operand_to_const_reduction_opportunity_finder.cpp */; };
-		A9415AC5243667F700566F16 /* operand_to_const_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415864243667F600566F16 /* operand_to_const_reduction_opportunity_finder.h */; };
-		A9415AC6243667F700566F16 /* operand_to_const_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415864243667F600566F16 /* operand_to_const_reduction_opportunity_finder.h */; };
-		A9415AC7243667F700566F16 /* reduction_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415866243667F600566F16 /* reduction_util.cpp */; };
-		A9415AC8243667F700566F16 /* reduction_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415866243667F600566F16 /* reduction_util.cpp */; };
-		A9415AC9243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415867243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */; };
-		A9415ACA243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415867243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */; };
-		A9415ACB243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415868243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h */; };
-		A9415ACC243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415868243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h */; };
-		A9415ACD243667F700566F16 /* remove_function_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415869243667F600566F16 /* remove_function_reduction_opportunity_finder.cpp */; };
-		A9415ACE243667F700566F16 /* remove_function_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415869243667F600566F16 /* remove_function_reduction_opportunity_finder.cpp */; };
-		A9415ACF243667F700566F16 /* remove_instruction_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941586A243667F600566F16 /* remove_instruction_reduction_opportunity.h */; };
-		A9415AD0243667F700566F16 /* remove_instruction_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941586A243667F600566F16 /* remove_instruction_reduction_opportunity.h */; };
-		A9415AD1243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941586B243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */; };
-		A9415AD2243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941586B243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */; };
-		A9415AD3243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586C243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */; };
-		A9415AD4243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586C243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */; };
-		A9415AD5243667F700566F16 /* remove_function_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586D243667F600566F16 /* remove_function_reduction_opportunity.cpp */; };
-		A9415AD6243667F700566F16 /* remove_function_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586D243667F600566F16 /* remove_function_reduction_opportunity.cpp */; };
-		A9415AD7243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586E243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */; };
-		A9415AD8243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586E243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */; };
-		A9415AD9243667F700566F16 /* remove_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586F243667F600566F16 /* remove_selection_reduction_opportunity_finder.cpp */; };
-		A9415ADA243667F700566F16 /* remove_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941586F243667F600566F16 /* remove_selection_reduction_opportunity_finder.cpp */; };
-		A9415ADB243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415870243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */; };
-		A9415ADC243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415870243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */; };
-		A9415ADD243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415871243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h */; };
-		A9415ADE243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415871243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h */; };
-		A9415ADF243667F700566F16 /* merge_blocks_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415872243667F600566F16 /* merge_blocks_reduction_opportunity.cpp */; };
-		A9415AE0243667F700566F16 /* merge_blocks_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415872243667F600566F16 /* merge_blocks_reduction_opportunity.cpp */; };
-		A9415AE1243667F700566F16 /* change_operand_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415873243667F600566F16 /* change_operand_reduction_opportunity.cpp */; };
-		A9415AE2243667F700566F16 /* change_operand_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415873243667F600566F16 /* change_operand_reduction_opportunity.cpp */; };
-		A9415AE3243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415874243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.h */; };
-		A9415AE4243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415874243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.h */; };
-		A9415AE5243667F700566F16 /* remove_function_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415875243667F600566F16 /* remove_function_reduction_opportunity.h */; };
-		A9415AE6243667F700566F16 /* remove_function_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415875243667F600566F16 /* remove_function_reduction_opportunity.h */; };
-		A9415AE7243667F700566F16 /* change_operand_to_undef_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415876243667F600566F16 /* change_operand_to_undef_reduction_opportunity.h */; };
-		A9415AE8243667F700566F16 /* change_operand_to_undef_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415876243667F600566F16 /* change_operand_to_undef_reduction_opportunity.h */; };
-		A9415AE9243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415877243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp */; };
-		A9415AEA243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415877243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp */; };
-		A9415AEB243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415878243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h */; };
-		A9415AEC243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415878243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h */; };
-		A9415AED243667F700566F16 /* remove_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415879243667F600566F16 /* remove_selection_reduction_opportunity.h */; };
-		A9415AEE243667F700566F16 /* remove_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415879243667F600566F16 /* remove_selection_reduction_opportunity.h */; };
-		A9415AEF243667F700566F16 /* remove_instruction_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587A243667F600566F16 /* remove_instruction_reduction_opportunity.cpp */; };
-		A9415AF0243667F700566F16 /* remove_instruction_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587A243667F600566F16 /* remove_instruction_reduction_opportunity.cpp */; };
-		A9415AF1243667F700566F16 /* remove_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941587B243667F600566F16 /* remove_selection_reduction_opportunity_finder.h */; };
-		A9415AF2243667F700566F16 /* remove_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941587B243667F600566F16 /* remove_selection_reduction_opportunity_finder.h */; };
-		A9415AF3243667F700566F16 /* merge_blocks_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941587C243667F600566F16 /* merge_blocks_reduction_opportunity_finder.h */; };
-		A9415AF4243667F700566F16 /* merge_blocks_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941587C243667F600566F16 /* merge_blocks_reduction_opportunity_finder.h */; };
-		A9415AF5243667F700566F16 /* pch_source_reduce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587D243667F600566F16 /* pch_source_reduce.cpp */; };
-		A9415AF6243667F700566F16 /* pch_source_reduce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587D243667F600566F16 /* pch_source_reduce.cpp */; };
-		A9415AF7243667F700566F16 /* reducer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587E243667F600566F16 /* reducer.cpp */; };
-		A9415AF8243667F700566F16 /* reducer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587E243667F600566F16 /* reducer.cpp */; };
-		A9415AF9243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587F243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.cpp */; };
-		A9415AFA243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941587F243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.cpp */; };
-		A9415AFB243667F700566F16 /* remove_function_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415880243667F600566F16 /* remove_function_reduction_opportunity_finder.h */; };
-		A9415AFC243667F700566F16 /* remove_function_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415880243667F600566F16 /* remove_function_reduction_opportunity_finder.h */; };
-		A9415AFD243667F700566F16 /* pch_source_reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415881243667F600566F16 /* pch_source_reduce.h */; };
-		A9415AFE243667F700566F16 /* pch_source_reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415881243667F600566F16 /* pch_source_reduce.h */; };
-		A9415AFF243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415882243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h */; };
-		A9415B00243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415882243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h */; };
-		A9415B01243667F700566F16 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415883243667F600566F16 /* merge_blocks_reduction_opportunity_finder.cpp */; };
-		A9415B02243667F700566F16 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415883243667F600566F16 /* merge_blocks_reduction_opportunity_finder.cpp */; };
-		A9415B03243667F700566F16 /* reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415884243667F600566F16 /* reduction_opportunity.cpp */; };
-		A9415B04243667F700566F16 /* reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415884243667F600566F16 /* reduction_opportunity.cpp */; };
-		A9415B05243667F700566F16 /* reducer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415885243667F600566F16 /* reducer.h */; };
-		A9415B06243667F700566F16 /* reducer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415885243667F600566F16 /* reducer.h */; };
-		A9415B07243667F700566F16 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415886243667F600566F16 /* change_operand_to_undef_reduction_opportunity.cpp */; };
-		A9415B08243667F700566F16 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415886243667F600566F16 /* change_operand_to_undef_reduction_opportunity.cpp */; };
-		A9415B09243667F700566F16 /* reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415887243667F600566F16 /* reduction_opportunity.h */; };
-		A9415B0A243667F700566F16 /* reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415887243667F600566F16 /* reduction_opportunity.h */; };
-		A9415B0B243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415888243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */; };
-		A9415B0C243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415888243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */; };
-		A9415B0D243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415889243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */; };
-		A9415B0E243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415889243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */; };
-		A9415B0F243667F700566F16 /* reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588A243667F600566F16 /* reduction_opportunity_finder.h */; };
-		A9415B10243667F700566F16 /* reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588A243667F600566F16 /* reduction_opportunity_finder.h */; };
-		A9415B11243667F700566F16 /* change_operand_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588B243667F600566F16 /* change_operand_reduction_opportunity.h */; };
-		A9415B12243667F700566F16 /* change_operand_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588B243667F600566F16 /* change_operand_reduction_opportunity.h */; };
-		A9415B13243667F700566F16 /* remove_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588C243667F600566F16 /* remove_block_reduction_opportunity_finder.h */; };
-		A9415B14243667F700566F16 /* remove_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588C243667F600566F16 /* remove_block_reduction_opportunity_finder.h */; };
-		A9415B15243667F700566F16 /* remove_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941588D243667F600566F16 /* remove_block_reduction_opportunity_finder.cpp */; };
-		A9415B16243667F700566F16 /* remove_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941588D243667F600566F16 /* remove_block_reduction_opportunity_finder.cpp */; };
-		A9415B17243667F700566F16 /* reduction_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588E243667F600566F16 /* reduction_util.h */; };
-		A9415B18243667F700566F16 /* reduction_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588E243667F600566F16 /* reduction_util.h */; };
-		A9415B19243667F700566F16 /* merge_blocks_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588F243667F600566F16 /* merge_blocks_reduction_opportunity.h */; };
-		A9415B1A243667F700566F16 /* merge_blocks_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A941588F243667F600566F16 /* merge_blocks_reduction_opportunity.h */; };
-		A9415B1B243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415890243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */; };
-		A9415B1C243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415890243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */; };
-		A9415B1D243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415891243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.cpp */; };
-		A9415B1E243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415891243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.cpp */; };
-		A9415B1F243667F700566F16 /* remove_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415892243667F600566F16 /* remove_block_reduction_opportunity.cpp */; };
-		A9415B20243667F700566F16 /* remove_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415892243667F600566F16 /* remove_block_reduction_opportunity.cpp */; };
-		A9415B21243667F700566F16 /* reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415893243667F600566F16 /* reduction_pass.h */; };
-		A9415B22243667F700566F16 /* reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415893243667F600566F16 /* reduction_pass.h */; };
-		A9415B23243667F700566F16 /* latest_version_opencl_std_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415894243667F600566F16 /* latest_version_opencl_std_header.h */; };
-		A9415B24243667F700566F16 /* latest_version_opencl_std_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415894243667F600566F16 /* latest_version_opencl_std_header.h */; };
-		A9415B25243667F700566F16 /* spirv_optimizer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415895243667F600566F16 /* spirv_optimizer_options.cpp */; };
-		A9415B26243667F700566F16 /* spirv_optimizer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415895243667F600566F16 /* spirv_optimizer_options.cpp */; };
-		A9415B27243667F700566F16 /* cfa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415896243667F600566F16 /* cfa.h */; };
-		A9415B28243667F800566F16 /* cfa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415896243667F600566F16 /* cfa.h */; };
-		A9415B29243667F800566F16 /* pch_source.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415897243667F600566F16 /* pch_source.h */; };
-		A9415B2A243667F800566F16 /* pch_source.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415897243667F600566F16 /* pch_source.h */; };
-		A9415B2B243667F800566F16 /* enum_string_mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415898243667F600566F16 /* enum_string_mapping.h */; };
-		A9415B2C243667F800566F16 /* enum_string_mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415898243667F600566F16 /* enum_string_mapping.h */; };
-		A9415B2D243667F800566F16 /* spirv_fuzzer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415899243667F600566F16 /* spirv_fuzzer_options.cpp */; };
-		A9415B2E243667F800566F16 /* spirv_fuzzer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415899243667F600566F16 /* spirv_fuzzer_options.cpp */; };
-		A9415B2F243667F800566F16 /* spirv_reducer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589A243667F600566F16 /* spirv_reducer_options.h */; };
-		A9415B30243667F800566F16 /* spirv_reducer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589A243667F600566F16 /* spirv_reducer_options.h */; };
-		A9415B31243667F800566F16 /* spirv_validator_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941589B243667F600566F16 /* spirv_validator_options.cpp */; };
-		A9415B32243667F800566F16 /* spirv_validator_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941589B243667F600566F16 /* spirv_validator_options.cpp */; };
-		A9415B33243667F800566F16 /* print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941589D243667F600566F16 /* print.cpp */; };
-		A9415B34243667F800566F16 /* print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941589D243667F600566F16 /* print.cpp */; };
-		A9415B35243667F800566F16 /* spirv_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589E243667F600566F16 /* spirv_definition.h */; };
-		A9415B36243667F800566F16 /* spirv_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589E243667F600566F16 /* spirv_definition.h */; };
-		A9415B37243667F800566F16 /* operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589F243667F600566F16 /* operand.h */; };
-		A9415B38243667F800566F16 /* operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A941589F243667F600566F16 /* operand.h */; };
-		A9415B39243667F800566F16 /* spirv_endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A0243667F600566F16 /* spirv_endian.cpp */; };
-		A9415B3A243667F800566F16 /* spirv_endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A0243667F600566F16 /* spirv_endian.cpp */; };
-		A9415B3B243667F800566F16 /* macro.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A1243667F600566F16 /* macro.h */; };
-		A9415B3C243667F800566F16 /* macro.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A1243667F600566F16 /* macro.h */; };
-		A9415B3D243667F800566F16 /* spirv_constant.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A2243667F600566F16 /* spirv_constant.h */; };
-		A9415B3E243667F800566F16 /* spirv_constant.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A2243667F600566F16 /* spirv_constant.h */; };
-		A9415B3F243667F800566F16 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A4243667F600566F16 /* binary.cpp */; };
-		A9415B40243667F800566F16 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A4243667F600566F16 /* binary.cpp */; };
-		A9415B41243667F800566F16 /* spirv_validator_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A5243667F600566F16 /* spirv_validator_options.h */; };
-		A9415B42243667F800566F16 /* spirv_validator_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A5243667F600566F16 /* spirv_validator_options.h */; };
-		A9415B43243667F800566F16 /* enum_string_mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A6243667F600566F16 /* enum_string_mapping.cpp */; };
-		A9415B44243667F800566F16 /* enum_string_mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158A6243667F600566F16 /* enum_string_mapping.cpp */; };
-		A9415B45243667F800566F16 /* text_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A7243667F600566F16 /* text_handler.h */; };
-		A9415B46243667F800566F16 /* text_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A7243667F600566F16 /* text_handler.h */; };
-		A9415B47243667F800566F16 /* parsed_operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A8243667F600566F16 /* parsed_operand.h */; };
-		A9415B48243667F800566F16 /* parsed_operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A8243667F600566F16 /* parsed_operand.h */; };
-		A9415B49243667F800566F16 /* name_mapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A9243667F600566F16 /* name_mapper.h */; };
-		A9415B4A243667F800566F16 /* name_mapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158A9243667F600566F16 /* name_mapper.h */; };
-		A9415B4B243667F800566F16 /* spirv_reducer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AA243667F600566F16 /* spirv_reducer_options.cpp */; };
-		A9415B4C243667F800566F16 /* spirv_reducer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AA243667F600566F16 /* spirv_reducer_options.cpp */; };
-		A9415B4D243667F800566F16 /* parsed_operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AB243667F600566F16 /* parsed_operand.cpp */; };
-		A9415B4E243667F800566F16 /* parsed_operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AB243667F600566F16 /* parsed_operand.cpp */; };
-		A9415B4F243667F800566F16 /* diagnostic.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158AC243667F600566F16 /* diagnostic.h */; };
-		A9415B50243667F800566F16 /* diagnostic.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158AC243667F600566F16 /* diagnostic.h */; };
-		A9415B51243667F800566F16 /* spirv_endian.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158AD243667F600566F16 /* spirv_endian.h */; };
-		A9415B52243667F800566F16 /* spirv_endian.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158AD243667F600566F16 /* spirv_endian.h */; };
-		A9415B53243667F800566F16 /* name_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AE243667F600566F16 /* name_mapper.cpp */; };
-		A9415B54243667F800566F16 /* name_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158AE243667F600566F16 /* name_mapper.cpp */; };
-		A9415B55243667F800566F16 /* linker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B2243667F600566F16 /* linker.cpp */; };
-		A9415B56243667F800566F16 /* linker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B2243667F600566F16 /* linker.cpp */; };
-		A9415B57243667F800566F16 /* software_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B3243667F600566F16 /* software_version.cpp */; };
-		A9415B58243667F800566F16 /* software_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B3243667F600566F16 /* software_version.cpp */; };
-		A9415B59243667F800566F16 /* opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B4243667F600566F16 /* opcode.cpp */; };
-		A9415B5A243667F800566F16 /* opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B4243667F600566F16 /* opcode.cpp */; };
-		A9415B5B243667F800566F16 /* print.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158B5243667F600566F16 /* print.h */; };
-		A9415B5C243667F800566F16 /* print.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158B5243667F600566F16 /* print.h */; };
-		A9415B5D243667F800566F16 /* ext_inst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B6243667F600566F16 /* ext_inst.cpp */; };
-		A9415B5E243667F800566F16 /* ext_inst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B6243667F600566F16 /* ext_inst.cpp */; };
-		A9415B5F243667F800566F16 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158B7243667F600566F16 /* disassemble.h */; };
-		A9415B60243667F800566F16 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158B7243667F600566F16 /* disassemble.h */; };
-		A9415B61243667F800566F16 /* optimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B9243667F600566F16 /* optimizer.cpp */; };
-		A9415B62243667F800566F16 /* optimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158B9243667F600566F16 /* optimizer.cpp */; };
-		A9415B63243667F800566F16 /* if_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BA243667F600566F16 /* if_conversion.h */; };
-		A9415B64243667F800566F16 /* if_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BA243667F600566F16 /* if_conversion.h */; };
-		A9415B65243667F800566F16 /* register_pressure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158BB243667F600566F16 /* register_pressure.cpp */; };
-		A9415B66243667F800566F16 /* register_pressure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158BB243667F600566F16 /* register_pressure.cpp */; };
-		A9415B67243667F800566F16 /* loop_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158BC243667F600566F16 /* loop_utils.cpp */; };
-		A9415B68243667F800566F16 /* loop_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158BC243667F600566F16 /* loop_utils.cpp */; };
-		A9415B69243667F800566F16 /* merge_return_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BD243667F600566F16 /* merge_return_pass.h */; };
-		A9415B6A243667F800566F16 /* merge_return_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BD243667F600566F16 /* merge_return_pass.h */; };
-		A9415B6B243667F800566F16 /* inline_opaque_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BE243667F600566F16 /* inline_opaque_pass.h */; };
-		A9415B6C243667F800566F16 /* inline_opaque_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BE243667F600566F16 /* inline_opaque_pass.h */; };
-		A9415B6D243667F800566F16 /* loop_fusion.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BF243667F600566F16 /* loop_fusion.h */; };
-		A9415B6E243667F800566F16 /* loop_fusion.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158BF243667F600566F16 /* loop_fusion.h */; };
-		A9415B6F243667F800566F16 /* combine_access_chains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158C0243667F600566F16 /* combine_access_chains.cpp */; };
-		A9415B70243667F800566F16 /* combine_access_chains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158C0243667F600566F16 /* combine_access_chains.cpp */; };
-		A9415B71243667F800566F16 /* build_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158C1243667F600566F16 /* build_module.cpp */; };
-		A9415B72243667F800566F16 /* build_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158C1243667F600566F16 /* build_module.cpp */; };
-		A9415B73243667F800566F16 /* composite.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C2243667F600566F16 /* composite.h */; };
-		A9415B74243667F800566F16 /* composite.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C2243667F600566F16 /* composite.h */; };
-		A9415B75243667F800566F16 /* compact_ids_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C3243667F600566F16 /* compact_ids_pass.h */; };
-		A9415B76243667F800566F16 /* compact_ids_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C3243667F600566F16 /* compact_ids_pass.h */; };
-		A9415B77243667F800566F16 /* register_pressure.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C4243667F600566F16 /* register_pressure.h */; };
-		A9415B78243667F800566F16 /* register_pressure.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C4243667F600566F16 /* register_pressure.h */; };
-		A9415B79243667F800566F16 /* tree_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C5243667F600566F16 /* tree_iterator.h */; };
-		A9415B7A243667F800566F16 /* tree_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C5243667F600566F16 /* tree_iterator.h */; };
-		A9415B7B243667F800566F16 /* graphics_robust_access_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C6243667F600566F16 /* graphics_robust_access_pass.h */; };
-		A9415B7C243667F800566F16 /* graphics_robust_access_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C6243667F600566F16 /* graphics_robust_access_pass.h */; };
-		A9415B7D243667F800566F16 /* strip_atomic_counter_memory_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C7243667F600566F16 /* strip_atomic_counter_memory_pass.h */; };
-		A9415B7E243667F800566F16 /* strip_atomic_counter_memory_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C7243667F600566F16 /* strip_atomic_counter_memory_pass.h */; };
-		A9415B7F243667F800566F16 /* legalize_vector_shuffle_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C8243667F600566F16 /* legalize_vector_shuffle_pass.h */; };
-		A9415B80243667F800566F16 /* legalize_vector_shuffle_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C8243667F600566F16 /* legalize_vector_shuffle_pass.h */; };
-		A9415B81243667F800566F16 /* local_single_store_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C9243667F600566F16 /* local_single_store_elim_pass.h */; };
-		A9415B82243667F800566F16 /* local_single_store_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158C9243667F600566F16 /* local_single_store_elim_pass.h */; };
-		A9415B83243667F800566F16 /* reduce_load_size.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CA243667F600566F16 /* reduce_load_size.h */; };
-		A9415B84243667F800566F16 /* reduce_load_size.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CA243667F600566F16 /* reduce_load_size.h */; };
-		A9415B85243667F800566F16 /* code_sink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CB243667F600566F16 /* code_sink.cpp */; };
-		A9415B86243667F800566F16 /* code_sink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CB243667F600566F16 /* code_sink.cpp */; };
-		A9415B87243667F800566F16 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CC243667F600566F16 /* types.cpp */; };
-		A9415B88243667F800566F16 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CC243667F600566F16 /* types.cpp */; };
-		A9415B89243667F800566F16 /* scalar_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CD243667F600566F16 /* scalar_analysis.h */; };
-		A9415B8A243667F800566F16 /* scalar_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CD243667F600566F16 /* scalar_analysis.h */; };
-		A9415B8B243667F800566F16 /* strip_debug_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CE243667F600566F16 /* strip_debug_info_pass.h */; };
-		A9415B8C243667F800566F16 /* strip_debug_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158CE243667F600566F16 /* strip_debug_info_pass.h */; };
-		A9415B8D243667F800566F16 /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CF243667F600566F16 /* cfg.cpp */; };
-		A9415B8E243667F800566F16 /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158CF243667F600566F16 /* cfg.cpp */; };
-		A9415B8F243667F800566F16 /* strip_atomic_counter_memory_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D0243667F600566F16 /* strip_atomic_counter_memory_pass.cpp */; };
-		A9415B90243667F800566F16 /* strip_atomic_counter_memory_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D0243667F600566F16 /* strip_atomic_counter_memory_pass.cpp */; };
-		A9415B91243667F800566F16 /* decoration_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D1243667F600566F16 /* decoration_manager.cpp */; };
-		A9415B92243667F800566F16 /* decoration_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D1243667F600566F16 /* decoration_manager.cpp */; };
-		A9415B93243667F800566F16 /* local_single_block_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D2243667F600566F16 /* local_single_block_elim_pass.cpp */; };
-		A9415B94243667F800566F16 /* local_single_block_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D2243667F600566F16 /* local_single_block_elim_pass.cpp */; };
-		A9415B95243667F800566F16 /* freeze_spec_constant_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D3243667F600566F16 /* freeze_spec_constant_value_pass.cpp */; };
-		A9415B96243667F800566F16 /* freeze_spec_constant_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D3243667F600566F16 /* freeze_spec_constant_value_pass.cpp */; };
-		A9415B97243667F800566F16 /* replace_invalid_opc.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158D4243667F600566F16 /* replace_invalid_opc.h */; };
-		A9415B98243667F800566F16 /* replace_invalid_opc.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158D4243667F600566F16 /* replace_invalid_opc.h */; };
-		A9415B99243667F800566F16 /* local_access_chain_convert_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158D5243667F600566F16 /* local_access_chain_convert_pass.h */; };
-		A9415B9A243667F800566F16 /* local_access_chain_convert_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158D5243667F600566F16 /* local_access_chain_convert_pass.h */; };
-		A9415B9B243667F800566F16 /* inst_bindless_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D6243667F600566F16 /* inst_bindless_check_pass.cpp */; };
-		A9415B9C243667F800566F16 /* inst_bindless_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D6243667F600566F16 /* inst_bindless_check_pass.cpp */; };
-		A9415B9D243667F800566F16 /* local_redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D7243667F600566F16 /* local_redundancy_elimination.cpp */; };
-		A9415B9E243667F800566F16 /* local_redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D7243667F600566F16 /* local_redundancy_elimination.cpp */; };
-		A9415B9F243667F800566F16 /* instrument_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D9243667F600566F16 /* instrument_pass.cpp */; };
-		A9415BA0243667F800566F16 /* instrument_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158D9243667F600566F16 /* instrument_pass.cpp */; };
-		A9415BA1243667F800566F16 /* propagator.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158DA243667F600566F16 /* propagator.h */; };
-		A9415BA2243667F800566F16 /* propagator.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158DA243667F600566F16 /* propagator.h */; };
-		A9415BA3243667F800566F16 /* instruction_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158DB243667F600566F16 /* instruction_list.h */; };
-		A9415BA4243667F800566F16 /* instruction_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158DB243667F600566F16 /* instruction_list.h */; };
-		A9415BA5243667F800566F16 /* feature_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DC243667F600566F16 /* feature_manager.cpp */; };
-		A9415BA6243667F800566F16 /* feature_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DC243667F600566F16 /* feature_manager.cpp */; };
-		A9415BA7243667F800566F16 /* pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DD243667F600566F16 /* pass.cpp */; };
-		A9415BA8243667F800566F16 /* pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DD243667F600566F16 /* pass.cpp */; };
-		A9415BA9243667F800566F16 /* loop_fission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DE243667F600566F16 /* loop_fission.cpp */; };
-		A9415BAA243667F800566F16 /* loop_fission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DE243667F600566F16 /* loop_fission.cpp */; };
-		A9415BAB243667F800566F16 /* dominator_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DF243667F600566F16 /* dominator_tree.cpp */; };
-		A9415BAC243667F800566F16 /* dominator_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158DF243667F600566F16 /* dominator_tree.cpp */; };
-		A9415BAD243667F800566F16 /* amd_ext_to_khr.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E0243667F600566F16 /* amd_ext_to_khr.h */; };
-		A9415BAE243667F800566F16 /* amd_ext_to_khr.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E0243667F600566F16 /* amd_ext_to_khr.h */; };
-		A9415BAF243667F800566F16 /* merge_return_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E1243667F600566F16 /* merge_return_pass.cpp */; };
-		A9415BB0243667F800566F16 /* merge_return_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E1243667F600566F16 /* merge_return_pass.cpp */; };
-		A9415BB1243667F800566F16 /* ir_context.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E2243667F600566F16 /* ir_context.h */; };
-		A9415BB2243667F800566F16 /* ir_context.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E2243667F600566F16 /* ir_context.h */; };
-		A9415BB3243667F800566F16 /* eliminate_dead_constant_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E3243667F600566F16 /* eliminate_dead_constant_pass.cpp */; };
-		A9415BB4243667F800566F16 /* eliminate_dead_constant_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E3243667F600566F16 /* eliminate_dead_constant_pass.cpp */; };
-		A9415BB5243667F800566F16 /* cfg_cleanup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E4243667F600566F16 /* cfg_cleanup_pass.cpp */; };
-		A9415BB6243667F800566F16 /* cfg_cleanup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E4243667F600566F16 /* cfg_cleanup_pass.cpp */; };
-		A9415BB7243667F800566F16 /* wrap_opkill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E5243667F600566F16 /* wrap_opkill.cpp */; };
-		A9415BB8243667F800566F16 /* wrap_opkill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E5243667F600566F16 /* wrap_opkill.cpp */; };
-		A9415BB9243667F800566F16 /* const_folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E6243667F600566F16 /* const_folding_rules.cpp */; };
-		A9415BBA243667F800566F16 /* const_folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E6243667F600566F16 /* const_folding_rules.cpp */; };
-		A9415BBB243667F800566F16 /* loop_unroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E7243667F600566F16 /* loop_unroller.h */; };
-		A9415BBC243667F800566F16 /* loop_unroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158E7243667F600566F16 /* loop_unroller.h */; };
-		A9415BBD243667F800566F16 /* strip_debug_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E8243667F600566F16 /* strip_debug_info_pass.cpp */; };
-		A9415BBE243667F800566F16 /* strip_debug_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E8243667F600566F16 /* strip_debug_info_pass.cpp */; };
-		A9415BBF243667F800566F16 /* ssa_rewrite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E9243667F600566F16 /* ssa_rewrite_pass.cpp */; };
-		A9415BC0243667F800566F16 /* ssa_rewrite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158E9243667F600566F16 /* ssa_rewrite_pass.cpp */; };
-		A9415BC1243667F800566F16 /* loop_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158EA243667F600566F16 /* loop_dependence.cpp */; };
-		A9415BC2243667F800566F16 /* loop_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158EA243667F600566F16 /* loop_dependence.cpp */; };
-		A9415BC3243667F800566F16 /* unify_const_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EB243667F600566F16 /* unify_const_pass.h */; };
-		A9415BC4243667F800566F16 /* unify_const_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EB243667F600566F16 /* unify_const_pass.h */; };
-		A9415BC5243667F800566F16 /* ir_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EC243667F600566F16 /* ir_loader.h */; };
-		A9415BC6243667F800566F16 /* ir_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EC243667F600566F16 /* ir_loader.h */; };
-		A9415BC7243667F800566F16 /* inst_debug_printf_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158ED243667F600566F16 /* inst_debug_printf_pass.cpp */; };
-		A9415BC8243667F800566F16 /* inst_debug_printf_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158ED243667F600566F16 /* inst_debug_printf_pass.cpp */; };
-		A9415BC9243667F800566F16 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EE243667F600566F16 /* types.h */; };
-		A9415BCA243667F800566F16 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EE243667F600566F16 /* types.h */; };
-		A9415BCB243667F800566F16 /* fold_spec_constant_op_and_composite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EF243667F600566F16 /* fold_spec_constant_op_and_composite_pass.h */; };
-		A9415BCC243667F800566F16 /* fold_spec_constant_op_and_composite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158EF243667F600566F16 /* fold_spec_constant_op_and_composite_pass.h */; };
-		A9415BCD243667F800566F16 /* mem_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F0243667F600566F16 /* mem_pass.cpp */; };
-		A9415BCE243667F800566F16 /* mem_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F0243667F600566F16 /* mem_pass.cpp */; };
-		A9415BCF243667F800566F16 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158F1243667F600566F16 /* basic_block.h */; };
-		A9415BD0243667F800566F16 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158F1243667F600566F16 /* basic_block.h */; };
-		A9415BD1243667F800566F16 /* remove_duplicates_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F2243667F600566F16 /* remove_duplicates_pass.cpp */; };
-		A9415BD2243667F800566F16 /* remove_duplicates_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F2243667F600566F16 /* remove_duplicates_pass.cpp */; };
-		A9415BD3243667F800566F16 /* dead_variable_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F3243667F600566F16 /* dead_variable_elimination.cpp */; };
-		A9415BD4243667F800566F16 /* dead_variable_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F3243667F600566F16 /* dead_variable_elimination.cpp */; };
-		A9415BD5243667F800566F16 /* block_merge_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158F4243667F600566F16 /* block_merge_pass.h */; };
-		A9415BD6243667F800566F16 /* block_merge_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158F4243667F600566F16 /* block_merge_pass.h */; };
-		A9415BD7243667F800566F16 /* module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F5243667F600566F16 /* module.cpp */; };
-		A9415BD8243667F800566F16 /* module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F5243667F600566F16 /* module.cpp */; };
-		A9415BD9243667F800566F16 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F6243667F600566F16 /* fold_spec_constant_op_and_composite_pass.cpp */; };
-		A9415BDA243667F800566F16 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F6243667F600566F16 /* fold_spec_constant_op_and_composite_pass.cpp */; };
-		A9415BDB243667F800566F16 /* loop_unswitch_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F7243667F600566F16 /* loop_unswitch_pass.cpp */; };
-		A9415BDC243667F800566F16 /* loop_unswitch_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F7243667F600566F16 /* loop_unswitch_pass.cpp */; };
-		A9415BDD243667F800566F16 /* unify_const_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F8243667F600566F16 /* unify_const_pass.cpp */; };
-		A9415BDE243667F800566F16 /* unify_const_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F8243667F600566F16 /* unify_const_pass.cpp */; };
-		A9415BDF243667F800566F16 /* type_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F9243667F600566F16 /* type_manager.cpp */; };
-		A9415BE0243667F800566F16 /* type_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158F9243667F600566F16 /* type_manager.cpp */; };
-		A9415BE1243667F800566F16 /* generate_webgpu_initializers_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158FA243667F600566F16 /* generate_webgpu_initializers_pass.cpp */; };
-		A9415BE2243667F800566F16 /* generate_webgpu_initializers_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158FA243667F600566F16 /* generate_webgpu_initializers_pass.cpp */; };
-		A9415BE3243667F800566F16 /* private_to_local_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FB243667F600566F16 /* private_to_local_pass.h */; };
-		A9415BE4243667F800566F16 /* private_to_local_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FB243667F600566F16 /* private_to_local_pass.h */; };
-		A9415BE5243667F800566F16 /* convert_to_half_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FC243667F600566F16 /* convert_to_half_pass.h */; };
-		A9415BE6243667F800566F16 /* convert_to_half_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FC243667F600566F16 /* convert_to_half_pass.h */; };
-		A9415BE7243667F800566F16 /* relax_float_ops_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FD243667F600566F16 /* relax_float_ops_pass.h */; };
-		A9415BE8243667F800566F16 /* relax_float_ops_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FD243667F600566F16 /* relax_float_ops_pass.h */; };
-		A9415BE9243667F800566F16 /* inline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158FE243667F600566F16 /* inline_pass.cpp */; };
-		A9415BEA243667F800566F16 /* inline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A94158FE243667F600566F16 /* inline_pass.cpp */; };
-		A9415BEB243667F800566F16 /* def_use_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FF243667F600566F16 /* def_use_manager.h */; };
-		A9415BEC243667F800566F16 /* def_use_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A94158FF243667F600566F16 /* def_use_manager.h */; };
-		A9415BED243667F800566F16 /* ir_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415900243667F600566F16 /* ir_loader.cpp */; };
-		A9415BEE243667F800566F16 /* ir_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415900243667F600566F16 /* ir_loader.cpp */; };
-		A9415BEF243667F800566F16 /* cfg_cleanup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415901243667F600566F16 /* cfg_cleanup_pass.h */; };
-		A9415BF0243667F800566F16 /* cfg_cleanup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415901243667F600566F16 /* cfg_cleanup_pass.h */; };
-		A9415BF1243667F800566F16 /* licm_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415902243667F600566F16 /* licm_pass.cpp */; };
-		A9415BF2243667F800566F16 /* licm_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415902243667F600566F16 /* licm_pass.cpp */; };
-		A9415BF3243667F800566F16 /* eliminate_dead_functions_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415903243667F600566F16 /* eliminate_dead_functions_pass.cpp */; };
-		A9415BF4243667F800566F16 /* eliminate_dead_functions_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415903243667F600566F16 /* eliminate_dead_functions_pass.cpp */; };
-		A9415BF5243667F800566F16 /* local_redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415904243667F600566F16 /* local_redundancy_elimination.h */; };
-		A9415BF6243667F800566F16 /* local_redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415904243667F600566F16 /* local_redundancy_elimination.h */; };
-		A9415BF7243667F800566F16 /* split_invalid_unreachable_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415905243667F600566F16 /* split_invalid_unreachable_pass.cpp */; };
-		A9415BF8243667F800566F16 /* split_invalid_unreachable_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415905243667F600566F16 /* split_invalid_unreachable_pass.cpp */; };
-		A9415BF9243667F800566F16 /* loop_peeling.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415906243667F600566F16 /* loop_peeling.h */; };
-		A9415BFA243667F800566F16 /* loop_peeling.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415906243667F600566F16 /* loop_peeling.h */; };
-		A9415BFB243667F800566F16 /* vector_dce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415907243667F600566F16 /* vector_dce.cpp */; };
-		A9415BFC243667F800566F16 /* vector_dce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415907243667F600566F16 /* vector_dce.cpp */; };
-		A9415BFD243667F800566F16 /* block_merge_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415908243667F600566F16 /* block_merge_util.h */; };
-		A9415BFE243667F800566F16 /* block_merge_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415908243667F600566F16 /* block_merge_util.h */; };
-		A9415BFF243667F800566F16 /* loop_unroller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415909243667F600566F16 /* loop_unroller.cpp */; };
-		A9415C00243667F800566F16 /* loop_unroller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415909243667F600566F16 /* loop_unroller.cpp */; };
-		A9415C01243667F800566F16 /* desc_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590A243667F600566F16 /* desc_sroa.h */; };
-		A9415C02243667F800566F16 /* desc_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590A243667F600566F16 /* desc_sroa.h */; };
-		A9415C03243667F800566F16 /* constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590B243667F600566F16 /* constants.cpp */; };
-		A9415C04243667F800566F16 /* constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590B243667F600566F16 /* constants.cpp */; };
-		A9415C05243667F800566F16 /* loop_fusion_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590C243667F600566F16 /* loop_fusion_pass.h */; };
-		A9415C06243667F800566F16 /* loop_fusion_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590C243667F600566F16 /* loop_fusion_pass.h */; };
-		A9415C07243667F800566F16 /* struct_cfg_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590D243667F600566F16 /* struct_cfg_analysis.h */; };
-		A9415C08243667F800566F16 /* struct_cfg_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A941590D243667F600566F16 /* struct_cfg_analysis.h */; };
-		A9415C09243667F800566F16 /* inst_buff_addr_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590E243667F600566F16 /* inst_buff_addr_check_pass.cpp */; };
-		A9415C0A243667F800566F16 /* inst_buff_addr_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590E243667F600566F16 /* inst_buff_addr_check_pass.cpp */; };
-		A9415C0B243667F800566F16 /* def_use_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590F243667F600566F16 /* def_use_manager.cpp */; };
-		A9415C0C243667F800566F16 /* def_use_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941590F243667F600566F16 /* def_use_manager.cpp */; };
-		A9415C0D243667F800566F16 /* wrap_opkill.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415910243667F600566F16 /* wrap_opkill.h */; };
-		A9415C0E243667F800566F16 /* wrap_opkill.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415910243667F600566F16 /* wrap_opkill.h */; };
-		A9415C0F243667F800566F16 /* strip_reflect_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415911243667F600566F16 /* strip_reflect_info_pass.cpp */; };
-		A9415C10243667F800566F16 /* strip_reflect_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415911243667F600566F16 /* strip_reflect_info_pass.cpp */; };
-		A9415C11243667F800566F16 /* decoration_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415912243667F600566F16 /* decoration_manager.h */; };
-		A9415C12243667F800566F16 /* decoration_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415912243667F600566F16 /* decoration_manager.h */; };
-		A9415C13243667F800566F16 /* ccp_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415913243667F600566F16 /* ccp_pass.cpp */; };
-		A9415C14243667F800566F16 /* ccp_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415913243667F600566F16 /* ccp_pass.cpp */; };
-		A9415C15243667F800566F16 /* process_lines_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415914243667F600566F16 /* process_lines_pass.h */; };
-		A9415C16243667F800566F16 /* process_lines_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415914243667F600566F16 /* process_lines_pass.h */; };
-		A9415C17243667F800566F16 /* local_single_block_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415915243667F600566F16 /* local_single_block_elim_pass.h */; };
-		A9415C18243667F800566F16 /* local_single_block_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415915243667F600566F16 /* local_single_block_elim_pass.h */; };
-		A9415C19243667F800566F16 /* pch_source_opt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415916243667F600566F16 /* pch_source_opt.cpp */; };
-		A9415C1A243667F800566F16 /* pch_source_opt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415916243667F600566F16 /* pch_source_opt.cpp */; };
-		A9415C1B243667F800566F16 /* inst_buff_addr_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415917243667F600566F16 /* inst_buff_addr_check_pass.h */; };
-		A9415C1C243667F800566F16 /* inst_buff_addr_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415917243667F600566F16 /* inst_buff_addr_check_pass.h */; };
-		A9415C1D243667F800566F16 /* strength_reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415918243667F600566F16 /* strength_reduction_pass.h */; };
-		A9415C1E243667F800566F16 /* strength_reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415918243667F600566F16 /* strength_reduction_pass.h */; };
-		A9415C1F243667F800566F16 /* aggressive_dead_code_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415919243667F600566F16 /* aggressive_dead_code_elim_pass.cpp */; };
-		A9415C20243667F800566F16 /* aggressive_dead_code_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415919243667F600566F16 /* aggressive_dead_code_elim_pass.cpp */; };
-		A9415C21243667F800566F16 /* eliminate_dead_functions_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591A243667F600566F16 /* eliminate_dead_functions_util.cpp */; };
-		A9415C22243667F800566F16 /* eliminate_dead_functions_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591A243667F600566F16 /* eliminate_dead_functions_util.cpp */; };
-		A9415C23243667F800566F16 /* inst_debug_printf_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941591B243667F600566F16 /* inst_debug_printf_pass.h */; };
-		A9415C24243667F800566F16 /* inst_debug_printf_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941591B243667F600566F16 /* inst_debug_printf_pass.h */; };
-		A9415C25243667F800566F16 /* simplification_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591C243667F600566F16 /* simplification_pass.cpp */; };
-		A9415C26243667F800566F16 /* simplification_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591C243667F600566F16 /* simplification_pass.cpp */; };
-		A9415C27243667F800566F16 /* dead_branch_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591D243667F600566F16 /* dead_branch_elim_pass.cpp */; };
-		A9415C28243667F800566F16 /* dead_branch_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591D243667F600566F16 /* dead_branch_elim_pass.cpp */; };
-		A9415C29243667F800566F16 /* flatten_decoration_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591E243667F600566F16 /* flatten_decoration_pass.cpp */; };
-		A9415C2A243667F800566F16 /* flatten_decoration_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941591E243667F600566F16 /* flatten_decoration_pass.cpp */; };
-		A9415C2B243667F800566F16 /* dead_insert_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941591F243667F600566F16 /* dead_insert_elim_pass.h */; };
-		A9415C2C243667F800566F16 /* dead_insert_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941591F243667F600566F16 /* dead_insert_elim_pass.h */; };
-		A9415C2D243667F800566F16 /* folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415920243667F600566F16 /* folding_rules.cpp */; };
-		A9415C2E243667F800566F16 /* folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415920243667F600566F16 /* folding_rules.cpp */; };
-		A9415C2F243667F800566F16 /* freeze_spec_constant_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415921243667F600566F16 /* freeze_spec_constant_value_pass.h */; };
-		A9415C30243667F800566F16 /* freeze_spec_constant_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415921243667F600566F16 /* freeze_spec_constant_value_pass.h */; };
-		A9415C31243667F800566F16 /* ir_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415922243667F600566F16 /* ir_context.cpp */; };
-		A9415C32243667F800566F16 /* ir_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415922243667F600566F16 /* ir_context.cpp */; };
-		A9415C33243667F800566F16 /* instrument_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415923243667F600566F16 /* instrument_pass.h */; };
-		A9415C34243667F800566F16 /* instrument_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415923243667F600566F16 /* instrument_pass.h */; };
-		A9415C35243667F800566F16 /* mem_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415924243667F600566F16 /* mem_pass.h */; };
-		A9415C36243667F800566F16 /* mem_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415924243667F600566F16 /* mem_pass.h */; };
-		A9415C37243667F800566F16 /* loop_descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415925243667F600566F16 /* loop_descriptor.cpp */; };
-		A9415C38243667F800566F16 /* loop_descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415925243667F600566F16 /* loop_descriptor.cpp */; };
-		A9415C39243667F800566F16 /* eliminate_dead_members_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415926243667F600566F16 /* eliminate_dead_members_pass.h */; };
-		A9415C3A243667F800566F16 /* eliminate_dead_members_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415926243667F600566F16 /* eliminate_dead_members_pass.h */; };
-		A9415C3B243667F800566F16 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415927243667F600566F16 /* function.cpp */; };
-		A9415C3C243667F800566F16 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415927243667F600566F16 /* function.cpp */; };
-		A9415C3D243667F800566F16 /* instruction_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415928243667F600566F16 /* instruction_list.cpp */; };
-		A9415C3E243667F800566F16 /* instruction_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415928243667F600566F16 /* instruction_list.cpp */; };
-		A9415C3F243667F800566F16 /* composite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415929243667F600566F16 /* composite.cpp */; };
-		A9415C40243667F800566F16 /* composite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415929243667F600566F16 /* composite.cpp */; };
-		A9415C41243667F800566F16 /* convert_to_half_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941592A243667F600566F16 /* convert_to_half_pass.cpp */; };
-		A9415C42243667F800566F16 /* convert_to_half_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941592A243667F600566F16 /* convert_to_half_pass.cpp */; };
-		A9415C43243667F800566F16 /* process_lines_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941592B243667F600566F16 /* process_lines_pass.cpp */; };
-		A9415C44243667F800566F16 /* process_lines_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941592B243667F600566F16 /* process_lines_pass.cpp */; };
-		A9415C45243667F800566F16 /* inline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592C243667F600566F16 /* inline_pass.h */; };
-		A9415C46243667F800566F16 /* inline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592C243667F600566F16 /* inline_pass.h */; };
-		A9415C47243667F800566F16 /* loop_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592D243667F600566F16 /* loop_dependence.h */; };
-		A9415C48243667F800566F16 /* loop_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592D243667F600566F16 /* loop_dependence.h */; };
-		A9415C49243667F800566F16 /* value_number_table.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592E243667F600566F16 /* value_number_table.h */; };
-		A9415C4A243667F800566F16 /* value_number_table.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592E243667F600566F16 /* value_number_table.h */; };
-		A9415C4B243667F800566F16 /* flatten_decoration_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592F243667F600566F16 /* flatten_decoration_pass.h */; };
-		A9415C4C243667F800566F16 /* flatten_decoration_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941592F243667F600566F16 /* flatten_decoration_pass.h */; };
-		A9415C4D243667F800566F16 /* if_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415930243667F600566F16 /* if_conversion.cpp */; };
-		A9415C4E243667F800566F16 /* if_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415930243667F600566F16 /* if_conversion.cpp */; };
-		A9415C4F243667F800566F16 /* inline_exhaustive_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415931243667F600566F16 /* inline_exhaustive_pass.h */; };
-		A9415C50243667F800566F16 /* inline_exhaustive_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415931243667F600566F16 /* inline_exhaustive_pass.h */; };
-		A9415C51243667F800566F16 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415932243667F600566F16 /* constants.h */; };
-		A9415C52243667F800566F16 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415932243667F600566F16 /* constants.h */; };
-		A9415C53243667F800566F16 /* eliminate_dead_members_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415933243667F600566F16 /* eliminate_dead_members_pass.cpp */; };
-		A9415C54243667F800566F16 /* eliminate_dead_members_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415933243667F600566F16 /* eliminate_dead_members_pass.cpp */; };
-		A9415C55243667F800566F16 /* strength_reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415934243667F600566F16 /* strength_reduction_pass.cpp */; };
-		A9415C56243667F800566F16 /* strength_reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415934243667F600566F16 /* strength_reduction_pass.cpp */; };
-		A9415C57243667F800566F16 /* desc_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415935243667F600566F16 /* desc_sroa.cpp */; };
-		A9415C58243667F800566F16 /* desc_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415935243667F600566F16 /* desc_sroa.cpp */; };
-		A9415C59243667F800566F16 /* block_merge_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415936243667F600566F16 /* block_merge_util.cpp */; };
-		A9415C5A243667F800566F16 /* block_merge_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415936243667F600566F16 /* block_merge_util.cpp */; };
-		A9415C5B243667F800566F16 /* upgrade_memory_model.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415937243667F600566F16 /* upgrade_memory_model.h */; };
-		A9415C5C243667F800566F16 /* upgrade_memory_model.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415937243667F600566F16 /* upgrade_memory_model.h */; };
-		A9415C5D243667F800566F16 /* copy_prop_arrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415938243667F600566F16 /* copy_prop_arrays.cpp */; };
-		A9415C5E243667F800566F16 /* copy_prop_arrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415938243667F600566F16 /* copy_prop_arrays.cpp */; };
-		A9415C5F243667F800566F16 /* pass_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415939243667F600566F16 /* pass_manager.cpp */; };
-		A9415C60243667F800566F16 /* pass_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415939243667F600566F16 /* pass_manager.cpp */; };
-		A9415C61243667F800566F16 /* inline_exhaustive_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941593A243667F600566F16 /* inline_exhaustive_pass.cpp */; };
-		A9415C62243667F800566F16 /* inline_exhaustive_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941593A243667F600566F16 /* inline_exhaustive_pass.cpp */; };
-		A9415C63243667F800566F16 /* loop_fission.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593B243667F600566F16 /* loop_fission.h */; };
-		A9415C64243667F800566F16 /* loop_fission.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593B243667F600566F16 /* loop_fission.h */; };
-		A9415C65243667F800566F16 /* workaround1209.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593C243667F600566F16 /* workaround1209.h */; };
-		A9415C66243667F800566F16 /* workaround1209.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593C243667F600566F16 /* workaround1209.h */; };
-		A9415C67243667F800566F16 /* loop_fusion_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941593D243667F600566F16 /* loop_fusion_pass.cpp */; };
-		A9415C68243667F800566F16 /* loop_fusion_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941593D243667F600566F16 /* loop_fusion_pass.cpp */; };
-		A9415C69243667F800566F16 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593E243667F600566F16 /* log.h */; };
-		A9415C6A243667F800566F16 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593E243667F600566F16 /* log.h */; };
-		A9415C6B243667F800566F16 /* split_invalid_unreachable_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593F243667F600566F16 /* split_invalid_unreachable_pass.h */; };
-		A9415C6C243667F800566F16 /* split_invalid_unreachable_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941593F243667F600566F16 /* split_invalid_unreachable_pass.h */; };
-		A9415C6D243667F800566F16 /* copy_prop_arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415940243667F600566F16 /* copy_prop_arrays.h */; };
-		A9415C6E243667F800566F16 /* copy_prop_arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415940243667F600566F16 /* copy_prop_arrays.h */; };
-		A9415C6F243667F800566F16 /* eliminate_dead_constant_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415941243667F600566F16 /* eliminate_dead_constant_pass.h */; };
-		A9415C70243667F800566F16 /* eliminate_dead_constant_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415941243667F600566F16 /* eliminate_dead_constant_pass.h */; };
-		A9415C71243667F800566F16 /* dead_insert_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415942243667F600566F16 /* dead_insert_elim_pass.cpp */; };
-		A9415C72243667F800566F16 /* dead_insert_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415942243667F600566F16 /* dead_insert_elim_pass.cpp */; };
-		A9415C73243667F800566F16 /* ssa_rewrite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415943243667F600566F16 /* ssa_rewrite_pass.h */; };
-		A9415C74243667F800566F16 /* ssa_rewrite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415943243667F600566F16 /* ssa_rewrite_pass.h */; };
-		A9415C75243667F800566F16 /* scalar_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415944243667F600566F16 /* scalar_analysis.cpp */; };
-		A9415C76243667F800566F16 /* scalar_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415944243667F600566F16 /* scalar_analysis.cpp */; };
-		A9415C77243667F800566F16 /* dead_variable_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415945243667F600566F16 /* dead_variable_elimination.h */; };
-		A9415C78243667F800566F16 /* dead_variable_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415945243667F600566F16 /* dead_variable_elimination.h */; };
-		A9415C79243667F800566F16 /* block_merge_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415946243667F600566F16 /* block_merge_pass.cpp */; };
-		A9415C7A243667F800566F16 /* block_merge_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415946243667F600566F16 /* block_merge_pass.cpp */; };
-		A9415C7B243667F800566F16 /* dominator_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415947243667F600566F16 /* dominator_analysis.h */; };
-		A9415C7C243667F800566F16 /* dominator_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415947243667F600566F16 /* dominator_analysis.h */; };
-		A9415C7D243667F800566F16 /* pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415948243667F600566F16 /* pass.h */; };
-		A9415C7E243667F800566F16 /* pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415948243667F600566F16 /* pass.h */; };
-		A9415C7F243667F800566F16 /* folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415949243667F600566F16 /* folding_rules.h */; };
-		A9415C80243667F800566F16 /* folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415949243667F600566F16 /* folding_rules.h */; };
-		A9415C81243667F800566F16 /* eliminate_dead_functions_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594A243667F600566F16 /* eliminate_dead_functions_pass.h */; };
-		A9415C82243667F800566F16 /* eliminate_dead_functions_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594A243667F600566F16 /* eliminate_dead_functions_pass.h */; };
-		A9415C83243667F800566F16 /* eliminate_dead_functions_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594B243667F600566F16 /* eliminate_dead_functions_util.h */; };
-		A9415C84243667F800566F16 /* eliminate_dead_functions_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594B243667F600566F16 /* eliminate_dead_functions_util.h */; };
-		A9415C85243667F800566F16 /* fold.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594C243667F600566F16 /* fold.h */; };
-		A9415C86243667F800566F16 /* fold.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594C243667F600566F16 /* fold.h */; };
-		A9415C87243667F800566F16 /* local_single_store_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941594D243667F600566F16 /* local_single_store_elim_pass.cpp */; };
-		A9415C88243667F800566F16 /* local_single_store_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941594D243667F600566F16 /* local_single_store_elim_pass.cpp */; };
-		A9415C89243667F800566F16 /* dead_branch_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594E243667F600566F16 /* dead_branch_elim_pass.h */; };
-		A9415C8A243667F800566F16 /* dead_branch_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941594E243667F600566F16 /* dead_branch_elim_pass.h */; };
-		A9415C8B243667F800566F16 /* private_to_local_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941594F243667F600566F16 /* private_to_local_pass.cpp */; };
-		A9415C8C243667F800566F16 /* private_to_local_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941594F243667F600566F16 /* private_to_local_pass.cpp */; };
-		A9415C8D243667F800566F16 /* scalar_analysis_nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415950243667F600566F16 /* scalar_analysis_nodes.h */; };
-		A9415C8E243667F800566F16 /* scalar_analysis_nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415950243667F600566F16 /* scalar_analysis_nodes.h */; };
-		A9415C8F243667F800566F16 /* propagator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415951243667F600566F16 /* propagator.cpp */; };
-		A9415C90243667F800566F16 /* propagator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415951243667F600566F16 /* propagator.cpp */; };
-		A9415C91243667F800566F16 /* fix_storage_class.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415952243667F600566F16 /* fix_storage_class.h */; };
-		A9415C92243667F800566F16 /* fix_storage_class.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415952243667F600566F16 /* fix_storage_class.h */; };
-		A9415C93243667F800566F16 /* loop_dependence_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415953243667F600566F16 /* loop_dependence_helpers.cpp */; };
-		A9415C94243667F800566F16 /* loop_dependence_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415953243667F600566F16 /* loop_dependence_helpers.cpp */; };
-		A9415C95243667F800566F16 /* set_spec_constant_default_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415954243667F600566F16 /* set_spec_constant_default_value_pass.cpp */; };
-		A9415C96243667F800566F16 /* set_spec_constant_default_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415954243667F600566F16 /* set_spec_constant_default_value_pass.cpp */; };
-		A9415C97243667F800566F16 /* passes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415955243667F600566F16 /* passes.h */; };
-		A9415C98243667F800566F16 /* passes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415955243667F600566F16 /* passes.h */; };
-		A9415C99243667F800566F16 /* fold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415956243667F600566F16 /* fold.cpp */; };
-		A9415C9A243667F800566F16 /* fold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415956243667F600566F16 /* fold.cpp */; };
-		A9415C9B243667F800566F16 /* amd_ext_to_khr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415957243667F600566F16 /* amd_ext_to_khr.cpp */; };
-		A9415C9C243667F800566F16 /* amd_ext_to_khr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415957243667F600566F16 /* amd_ext_to_khr.cpp */; };
-		A9415C9D243667F800566F16 /* strip_reflect_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415958243667F600566F16 /* strip_reflect_info_pass.h */; };
-		A9415C9E243667F800566F16 /* strip_reflect_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415958243667F600566F16 /* strip_reflect_info_pass.h */; };
-		A9415C9F243667F800566F16 /* scalar_replacement_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415959243667F600566F16 /* scalar_replacement_pass.cpp */; };
-		A9415CA0243667F800566F16 /* scalar_replacement_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415959243667F600566F16 /* scalar_replacement_pass.cpp */; };
-		A9415CA1243667F800566F16 /* simplification_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595A243667F600566F16 /* simplification_pass.h */; };
-		A9415CA2243667F800566F16 /* simplification_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595A243667F600566F16 /* simplification_pass.h */; };
-		A9415CA3243667F800566F16 /* remove_duplicates_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595B243667F600566F16 /* remove_duplicates_pass.h */; };
-		A9415CA4243667F800566F16 /* remove_duplicates_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595B243667F600566F16 /* remove_duplicates_pass.h */; };
-		A9415CA5243667F800566F16 /* redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941595C243667F600566F16 /* redundancy_elimination.cpp */; };
-		A9415CA6243667F800566F16 /* redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941595C243667F600566F16 /* redundancy_elimination.cpp */; };
-		A9415CA7243667F800566F16 /* reflect.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595D243667F600566F16 /* reflect.h */; };
-		A9415CA8243667F800566F16 /* reflect.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595D243667F600566F16 /* reflect.h */; };
-		A9415CA9243667F800566F16 /* workaround1209.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941595E243667F600566F16 /* workaround1209.cpp */; };
-		A9415CAA243667F800566F16 /* workaround1209.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941595E243667F600566F16 /* workaround1209.cpp */; };
-		A9415CAB243667F800566F16 /* null_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595F243667F600566F16 /* null_pass.h */; };
-		A9415CAC243667F800566F16 /* null_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941595F243667F600566F16 /* null_pass.h */; };
-		A9415CAD243667F800566F16 /* relax_float_ops_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415960243667F600566F16 /* relax_float_ops_pass.cpp */; };
-		A9415CAE243667F800566F16 /* relax_float_ops_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415960243667F600566F16 /* relax_float_ops_pass.cpp */; };
-		A9415CAF243667F800566F16 /* const_folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415961243667F600566F16 /* const_folding_rules.h */; };
-		A9415CB0243667F800566F16 /* const_folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415961243667F600566F16 /* const_folding_rules.h */; };
-		A9415CB1243667F800566F16 /* scalar_replacement_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415962243667F600566F16 /* scalar_replacement_pass.h */; };
-		A9415CB2243667F800566F16 /* scalar_replacement_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415962243667F600566F16 /* scalar_replacement_pass.h */; };
-		A9415CB3243667F800566F16 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415963243667F600566F16 /* instruction.cpp */; };
-		A9415CB4243667F800566F16 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415963243667F600566F16 /* instruction.cpp */; };
-		A9415CB5243667F800566F16 /* pch_source_opt.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415964243667F600566F16 /* pch_source_opt.h */; };
-		A9415CB6243667F800566F16 /* pch_source_opt.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415964243667F600566F16 /* pch_source_opt.h */; };
-		A9415CB7243667F800566F16 /* reduce_load_size.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415965243667F600566F16 /* reduce_load_size.cpp */; };
-		A9415CB8243667F800566F16 /* reduce_load_size.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415965243667F600566F16 /* reduce_load_size.cpp */; };
-		A9415CB9243667F800566F16 /* redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415966243667F600566F16 /* redundancy_elimination.h */; };
-		A9415CBA243667F800566F16 /* redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415966243667F600566F16 /* redundancy_elimination.h */; };
-		A9415CBB243667F800566F16 /* fix_storage_class.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415967243667F600566F16 /* fix_storage_class.cpp */; };
-		A9415CBC243667F800566F16 /* fix_storage_class.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415967243667F600566F16 /* fix_storage_class.cpp */; };
-		A9415CBD243667F800566F16 /* value_number_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415968243667F600566F16 /* value_number_table.cpp */; };
-		A9415CBE243667F800566F16 /* value_number_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415968243667F600566F16 /* value_number_table.cpp */; };
-		A9415CBF243667F800566F16 /* inline_opaque_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415969243667F600566F16 /* inline_opaque_pass.cpp */; };
-		A9415CC0243667F800566F16 /* inline_opaque_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415969243667F600566F16 /* inline_opaque_pass.cpp */; };
-		A9415CC1243667F800566F16 /* replace_invalid_opc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596A243667F600566F16 /* replace_invalid_opc.cpp */; };
-		A9415CC2243667F800566F16 /* replace_invalid_opc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596A243667F600566F16 /* replace_invalid_opc.cpp */; };
-		A9415CC3243667F800566F16 /* loop_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596B243667F600566F16 /* loop_utils.h */; };
-		A9415CC4243667F800566F16 /* loop_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596B243667F600566F16 /* loop_utils.h */; };
-		A9415CC5243667F800566F16 /* module.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596C243667F700566F16 /* module.h */; };
-		A9415CC6243667F800566F16 /* module.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596C243667F700566F16 /* module.h */; };
-		A9415CC7243667F800566F16 /* dominator_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596D243667F700566F16 /* dominator_analysis.cpp */; };
-		A9415CC8243667F800566F16 /* dominator_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596D243667F700566F16 /* dominator_analysis.cpp */; };
-		A9415CC9243667F800566F16 /* decompose_initialized_variables_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596E243667F700566F16 /* decompose_initialized_variables_pass.cpp */; };
-		A9415CCA243667F800566F16 /* decompose_initialized_variables_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941596E243667F700566F16 /* decompose_initialized_variables_pass.cpp */; };
-		A9415CCB243667F800566F16 /* ir_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596F243667F700566F16 /* ir_builder.h */; };
-		A9415CCC243667F800566F16 /* ir_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = A941596F243667F700566F16 /* ir_builder.h */; };
-		A9415CCD243667F800566F16 /* loop_unswitch_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415970243667F700566F16 /* loop_unswitch_pass.h */; };
-		A9415CCE243667F800566F16 /* loop_unswitch_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415970243667F700566F16 /* loop_unswitch_pass.h */; };
-		A9415CCF243667F800566F16 /* cfg.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415971243667F700566F16 /* cfg.h */; };
-		A9415CD0243667F800566F16 /* cfg.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415971243667F700566F16 /* cfg.h */; };
-		A9415CD1243667F800566F16 /* code_sink.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415972243667F700566F16 /* code_sink.h */; };
-		A9415CD2243667F800566F16 /* code_sink.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415972243667F700566F16 /* code_sink.h */; };
-		A9415CD3243667F800566F16 /* loop_descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415973243667F700566F16 /* loop_descriptor.h */; };
-		A9415CD4243667F800566F16 /* loop_descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415973243667F700566F16 /* loop_descriptor.h */; };
-		A9415CD5243667F800566F16 /* generate_webgpu_initializers_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415974243667F700566F16 /* generate_webgpu_initializers_pass.h */; };
-		A9415CD6243667F800566F16 /* generate_webgpu_initializers_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415974243667F700566F16 /* generate_webgpu_initializers_pass.h */; };
-		A9415CD7243667F800566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415975243667F700566F16 /* instruction.h */; };
-		A9415CD8243667F800566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415975243667F700566F16 /* instruction.h */; };
-		A9415CD9243667F800566F16 /* aggressive_dead_code_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415976243667F700566F16 /* aggressive_dead_code_elim_pass.h */; };
-		A9415CDA243667F800566F16 /* aggressive_dead_code_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415976243667F700566F16 /* aggressive_dead_code_elim_pass.h */; };
-		A9415CDB243667F800566F16 /* struct_cfg_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415977243667F700566F16 /* struct_cfg_analysis.cpp */; };
-		A9415CDC243667F800566F16 /* struct_cfg_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415977243667F700566F16 /* struct_cfg_analysis.cpp */; };
-		A9415CDD243667F800566F16 /* vector_dce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415978243667F700566F16 /* vector_dce.h */; };
-		A9415CDE243667F800566F16 /* vector_dce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415978243667F700566F16 /* vector_dce.h */; };
-		A9415CDF243667F800566F16 /* combine_access_chains.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415979243667F700566F16 /* combine_access_chains.h */; };
-		A9415CE0243667F800566F16 /* combine_access_chains.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415979243667F700566F16 /* combine_access_chains.h */; };
-		A9415CE1243667F800566F16 /* pass_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597A243667F700566F16 /* pass_manager.h */; };
-		A9415CE2243667F800566F16 /* pass_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597A243667F700566F16 /* pass_manager.h */; };
-		A9415CE3243667F800566F16 /* local_access_chain_convert_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941597B243667F700566F16 /* local_access_chain_convert_pass.cpp */; };
-		A9415CE4243667F800566F16 /* local_access_chain_convert_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941597B243667F700566F16 /* local_access_chain_convert_pass.cpp */; };
-		A9415CE5243667F800566F16 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941597C243667F700566F16 /* basic_block.cpp */; };
-		A9415CE6243667F800566F16 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941597C243667F700566F16 /* basic_block.cpp */; };
-		A9415CE7243667F800566F16 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597D243667F700566F16 /* iterator.h */; };
-		A9415CE8243667F800566F16 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597D243667F700566F16 /* iterator.h */; };
-		A9415CE9243667F800566F16 /* licm_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597E243667F700566F16 /* licm_pass.h */; };
-		A9415CEA243667F800566F16 /* licm_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597E243667F700566F16 /* licm_pass.h */; };
-		A9415CEB243667F800566F16 /* build_module.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597F243667F700566F16 /* build_module.h */; };
-		A9415CEC243667F800566F16 /* build_module.h in Headers */ = {isa = PBXBuildFile; fileRef = A941597F243667F700566F16 /* build_module.h */; };
-		A9415CED243667F800566F16 /* ccp_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415980243667F700566F16 /* ccp_pass.h */; };
-		A9415CEE243667F800566F16 /* ccp_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415980243667F700566F16 /* ccp_pass.h */; };
-		A9415CEF243667F800566F16 /* graphics_robust_access_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415981243667F700566F16 /* graphics_robust_access_pass.cpp */; };
-		A9415CF0243667F800566F16 /* graphics_robust_access_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415981243667F700566F16 /* graphics_robust_access_pass.cpp */; };
-		A9415CF1243667F800566F16 /* decompose_initialized_variables_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415982243667F700566F16 /* decompose_initialized_variables_pass.h */; };
-		A9415CF2243667F800566F16 /* decompose_initialized_variables_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415982243667F700566F16 /* decompose_initialized_variables_pass.h */; };
-		A9415CF3243667F800566F16 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415983243667F700566F16 /* function.h */; };
-		A9415CF4243667F800566F16 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415983243667F700566F16 /* function.h */; };
-		A9415CF5243667F800566F16 /* loop_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415984243667F700566F16 /* loop_fusion.cpp */; };
-		A9415CF6243667F800566F16 /* loop_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415984243667F700566F16 /* loop_fusion.cpp */; };
-		A9415CF7243667F800566F16 /* upgrade_memory_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415985243667F700566F16 /* upgrade_memory_model.cpp */; };
-		A9415CF8243667F800566F16 /* upgrade_memory_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415985243667F700566F16 /* upgrade_memory_model.cpp */; };
-		A9415CF9243667F800566F16 /* feature_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415986243667F700566F16 /* feature_manager.h */; };
-		A9415CFA243667F800566F16 /* feature_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415986243667F700566F16 /* feature_manager.h */; };
-		A9415CFB243667F800566F16 /* inst_bindless_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415987243667F700566F16 /* inst_bindless_check_pass.h */; };
-		A9415CFC243667F800566F16 /* inst_bindless_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415987243667F700566F16 /* inst_bindless_check_pass.h */; };
-		A9415CFD243667F800566F16 /* scalar_analysis_simplification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415988243667F700566F16 /* scalar_analysis_simplification.cpp */; };
-		A9415CFE243667F800566F16 /* scalar_analysis_simplification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415988243667F700566F16 /* scalar_analysis_simplification.cpp */; };
-		A9415CFF243667F800566F16 /* set_spec_constant_default_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415989243667F700566F16 /* set_spec_constant_default_value_pass.h */; };
-		A9415D00243667F800566F16 /* set_spec_constant_default_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415989243667F700566F16 /* set_spec_constant_default_value_pass.h */; };
-		A9415D01243667F800566F16 /* dominator_tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598A243667F700566F16 /* dominator_tree.h */; };
-		A9415D02243667F800566F16 /* dominator_tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598A243667F700566F16 /* dominator_tree.h */; };
-		A9415D03243667F800566F16 /* legalize_vector_shuffle_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598B243667F700566F16 /* legalize_vector_shuffle_pass.cpp */; };
-		A9415D04243667F800566F16 /* legalize_vector_shuffle_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598B243667F700566F16 /* legalize_vector_shuffle_pass.cpp */; };
-		A9415D05243667F800566F16 /* type_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598C243667F700566F16 /* type_manager.h */; };
-		A9415D06243667F800566F16 /* type_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598C243667F700566F16 /* type_manager.h */; };
-		A9415D07243667F800566F16 /* compact_ids_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598D243667F700566F16 /* compact_ids_pass.cpp */; };
-		A9415D08243667F800566F16 /* compact_ids_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598D243667F700566F16 /* compact_ids_pass.cpp */; };
-		A9415D09243667F800566F16 /* loop_peeling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598E243667F700566F16 /* loop_peeling.cpp */; };
-		A9415D0A243667F800566F16 /* loop_peeling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A941598E243667F700566F16 /* loop_peeling.cpp */; };
-		A9415D0B243667F800566F16 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598F243667F700566F16 /* table.h */; };
-		A9415D0C243667F800566F16 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = A941598F243667F700566F16 /* table.h */; };
-		A9415E77243667F900566F16 /* ext_inst.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A48243667F700566F16 /* ext_inst.h */; };
-		A9415E78243667F900566F16 /* ext_inst.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A48243667F700566F16 /* ext_inst.h */; };
-		A9415E79243667F900566F16 /* diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A49243667F700566F16 /* diagnostic.cpp */; };
-		A9415E7A243667F900566F16 /* diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A49243667F700566F16 /* diagnostic.cpp */; };
-		A9415E7B243667F900566F16 /* latest_version_spirv_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4A243667F700566F16 /* latest_version_spirv_header.h */; };
-		A9415E7C243667F900566F16 /* latest_version_spirv_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4A243667F700566F16 /* latest_version_spirv_header.h */; };
-		A9415E7D243667F900566F16 /* libspirv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A4B243667F700566F16 /* libspirv.cpp */; };
-		A9415E7E243667F900566F16 /* libspirv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A4B243667F700566F16 /* libspirv.cpp */; };
-		A9415E7F243667F900566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4C243667F700566F16 /* instruction.h */; };
-		A9415E80243667F900566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4C243667F700566F16 /* instruction.h */; };
-		A9415E81243667F900566F16 /* spirv_optimizer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4D243667F700566F16 /* spirv_optimizer_options.h */; };
-		A9415E82243667F900566F16 /* spirv_optimizer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4D243667F700566F16 /* spirv_optimizer_options.h */; };
-		A9415E83243667F900566F16 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4E243667F700566F16 /* opcode.h */; };
-		A9415E84243667F900566F16 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A4E243667F700566F16 /* opcode.h */; };
-		A9415E85243667F900566F16 /* operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A4F243667F700566F16 /* operand.cpp */; };
-		A9415E86243667F900566F16 /* operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A4F243667F700566F16 /* operand.cpp */; };
-		A9415E87243667F900566F16 /* latest_version_glsl_std_450_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A50243667F700566F16 /* latest_version_glsl_std_450_header.h */; };
-		A9415E88243667F900566F16 /* latest_version_glsl_std_450_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A50243667F700566F16 /* latest_version_glsl_std_450_header.h */; };
-		A9415E89243667F900566F16 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A51243667F700566F16 /* extensions.h */; };
-		A9415E8A243667F900566F16 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A51243667F700566F16 /* extensions.h */; };
-		A9415E8B243667F900566F16 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A52243667F700566F16 /* disassemble.cpp */; };
-		A9415E8C243667F900566F16 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A52243667F700566F16 /* disassemble.cpp */; };
-		A9415E8D243667F900566F16 /* binary.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A53243667F700566F16 /* binary.h */; };
-		A9415E8E243667F900566F16 /* binary.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A53243667F700566F16 /* binary.h */; };
-		A9415E8F243667F900566F16 /* text_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A54243667F700566F16 /* text_handler.cpp */; };
-		A9415E90243667F900566F16 /* text_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A54243667F700566F16 /* text_handler.cpp */; };
-		A9415E91243667F900566F16 /* validate_annotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A56243667F700566F16 /* validate_annotation.cpp */; };
-		A9415E92243667F900566F16 /* validate_annotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A56243667F700566F16 /* validate_annotation.cpp */; };
-		A9415E93243667F900566F16 /* validate_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A57243667F700566F16 /* validate_misc.cpp */; };
-		A9415E94243667F900566F16 /* validate_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A57243667F700566F16 /* validate_misc.cpp */; };
-		A9415E95243667F900566F16 /* validate_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A58243667F700566F16 /* validate_cfg.cpp */; };
-		A9415E96243667F900566F16 /* validate_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A58243667F700566F16 /* validate_cfg.cpp */; };
-		A9415E97243667F900566F16 /* validate_capability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A59243667F700566F16 /* validate_capability.cpp */; };
-		A9415E98243667F900566F16 /* validate_capability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A59243667F700566F16 /* validate_capability.cpp */; };
-		A9415E99243667F900566F16 /* construct.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A5A243667F700566F16 /* construct.h */; };
-		A9415E9A243667F900566F16 /* construct.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A5A243667F700566F16 /* construct.h */; };
-		A9415E9B243667F900566F16 /* validate_barriers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5B243667F700566F16 /* validate_barriers.cpp */; };
-		A9415E9C243667F900566F16 /* validate_barriers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5B243667F700566F16 /* validate_barriers.cpp */; };
-		A9415E9D243667F900566F16 /* validate_non_uniform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5C243667F700566F16 /* validate_non_uniform.cpp */; };
-		A9415E9E243667F900566F16 /* validate_non_uniform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5C243667F700566F16 /* validate_non_uniform.cpp */; };
-		A9415E9F243667F900566F16 /* validate_scopes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5D243667F700566F16 /* validate_scopes.cpp */; };
-		A9415EA0243667F900566F16 /* validate_scopes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5D243667F700566F16 /* validate_scopes.cpp */; };
-		A9415EA1243667F900566F16 /* validate_atomics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5E243667F700566F16 /* validate_atomics.cpp */; };
-		A9415EA2243667F900566F16 /* validate_atomics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A5E243667F700566F16 /* validate_atomics.cpp */; };
-		A9415EA3243667F900566F16 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A5F243667F700566F16 /* basic_block.h */; };
-		A9415EA4243667F900566F16 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A5F243667F700566F16 /* basic_block.h */; };
-		A9415EA5243667F900566F16 /* validate_instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A60243667F700566F16 /* validate_instruction.cpp */; };
-		A9415EA6243667F900566F16 /* validate_instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A60243667F700566F16 /* validate_instruction.cpp */; };
-		A9415EA7243667F900566F16 /* validate_decorations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A61243667F700566F16 /* validate_decorations.cpp */; };
-		A9415EA8243667F900566F16 /* validate_decorations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A61243667F700566F16 /* validate_decorations.cpp */; };
-		A9415EA9243667F900566F16 /* validate_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A62243667F700566F16 /* validate_debug.cpp */; };
-		A9415EAA243667F900566F16 /* validate_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A62243667F700566F16 /* validate_debug.cpp */; };
-		A9415EAB243667F900566F16 /* validate_builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A63243667F700566F16 /* validate_builtins.cpp */; };
-		A9415EAC243667F900566F16 /* validate_builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A63243667F700566F16 /* validate_builtins.cpp */; };
-		A9415EAD243667F900566F16 /* validate_interfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A64243667F700566F16 /* validate_interfaces.cpp */; };
-		A9415EAE243667F900566F16 /* validate_interfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A64243667F700566F16 /* validate_interfaces.cpp */; };
-		A9415EAF243667F900566F16 /* validate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A65243667F700566F16 /* validate.cpp */; };
-		A9415EB0243667F900566F16 /* validate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A65243667F700566F16 /* validate.cpp */; };
-		A9415EB1243667F900566F16 /* validation_state.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A66243667F700566F16 /* validation_state.h */; };
-		A9415EB2243667F900566F16 /* validation_state.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A66243667F700566F16 /* validation_state.h */; };
-		A9415EB3243667F900566F16 /* validate_constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A67243667F700566F16 /* validate_constants.cpp */; };
-		A9415EB4243667F900566F16 /* validate_constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A67243667F700566F16 /* validate_constants.cpp */; };
-		A9415EB5243667F900566F16 /* validate_bitwise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A68243667F700566F16 /* validate_bitwise.cpp */; };
-		A9415EB6243667F900566F16 /* validate_bitwise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A68243667F700566F16 /* validate_bitwise.cpp */; };
-		A9415EB7243667F900566F16 /* validate_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A69243667F700566F16 /* validate_extensions.cpp */; };
-		A9415EB8243667F900566F16 /* validate_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A69243667F700566F16 /* validate_extensions.cpp */; };
-		A9415EB9243667F900566F16 /* construct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6A243667F700566F16 /* construct.cpp */; };
-		A9415EBA243667F900566F16 /* construct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6A243667F700566F16 /* construct.cpp */; };
-		A9415EBB243667F900566F16 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6B243667F700566F16 /* function.cpp */; };
-		A9415EBC243667F900566F16 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6B243667F700566F16 /* function.cpp */; };
-		A9415EBD243667F900566F16 /* validate.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A6C243667F700566F16 /* validate.h */; };
-		A9415EBE243667F900566F16 /* validate.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A6C243667F700566F16 /* validate.h */; };
-		A9415EBF243667F900566F16 /* validate_adjacency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6D243667F700566F16 /* validate_adjacency.cpp */; };
-		A9415EC0243667F900566F16 /* validate_adjacency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6D243667F700566F16 /* validate_adjacency.cpp */; };
-		A9415EC1243667F900566F16 /* validate_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6E243667F700566F16 /* validate_conversion.cpp */; };
-		A9415EC2243667F900566F16 /* validate_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6E243667F700566F16 /* validate_conversion.cpp */; };
-		A9415EC3243667F900566F16 /* validate_small_type_uses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6F243667F700566F16 /* validate_small_type_uses.cpp */; };
-		A9415EC4243667F900566F16 /* validate_small_type_uses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A6F243667F700566F16 /* validate_small_type_uses.cpp */; };
-		A9415EC5243667F900566F16 /* validate_scopes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A70243667F700566F16 /* validate_scopes.h */; };
-		A9415EC6243667F900566F16 /* validate_scopes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A70243667F700566F16 /* validate_scopes.h */; };
-		A9415EC7243667F900566F16 /* validate_id.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A71243667F700566F16 /* validate_id.cpp */; };
-		A9415EC8243667F900566F16 /* validate_id.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A71243667F700566F16 /* validate_id.cpp */; };
-		A9415EC9243667F900566F16 /* validate_memory_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A72243667F700566F16 /* validate_memory_semantics.h */; };
-		A9415ECA243667F900566F16 /* validate_memory_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A72243667F700566F16 /* validate_memory_semantics.h */; };
-		A9415ECB243667F900566F16 /* validate_arithmetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A73243667F700566F16 /* validate_arithmetics.cpp */; };
-		A9415ECC243667F900566F16 /* validate_arithmetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A73243667F700566F16 /* validate_arithmetics.cpp */; };
-		A9415ECD243667F900566F16 /* validate_mode_setting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A74243667F700566F16 /* validate_mode_setting.cpp */; };
-		A9415ECE243667F900566F16 /* validate_mode_setting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A74243667F700566F16 /* validate_mode_setting.cpp */; };
-		A9415ECF243667F900566F16 /* validate_memory_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A75243667F700566F16 /* validate_memory_semantics.cpp */; };
-		A9415ED0243667F900566F16 /* validate_memory_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A75243667F700566F16 /* validate_memory_semantics.cpp */; };
-		A9415ED1243667F900566F16 /* validate_logicals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A76243667F700566F16 /* validate_logicals.cpp */; };
-		A9415ED2243667F900566F16 /* validate_logicals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A76243667F700566F16 /* validate_logicals.cpp */; };
-		A9415ED3243667F900566F16 /* validate_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A77243667F700566F16 /* validate_derivatives.cpp */; };
-		A9415ED4243667F900566F16 /* validate_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A77243667F700566F16 /* validate_derivatives.cpp */; };
-		A9415ED5243667F900566F16 /* validate_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A78243667F700566F16 /* validate_memory.cpp */; };
-		A9415ED6243667F900566F16 /* validate_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A78243667F700566F16 /* validate_memory.cpp */; };
-		A9415ED7243667F900566F16 /* validate_image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A79243667F700566F16 /* validate_image.cpp */; };
-		A9415ED8243667F900566F16 /* validate_image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A79243667F700566F16 /* validate_image.cpp */; };
-		A9415ED9243667F900566F16 /* validate_literals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7A243667F700566F16 /* validate_literals.cpp */; };
-		A9415EDA243667F900566F16 /* validate_literals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7A243667F700566F16 /* validate_literals.cpp */; };
-		A9415EDB243667F900566F16 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7B243667F700566F16 /* instruction.cpp */; };
-		A9415EDC243667F900566F16 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7B243667F700566F16 /* instruction.cpp */; };
-		A9415EDD243667F900566F16 /* validate_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7C243667F700566F16 /* validate_type.cpp */; };
-		A9415EDE243667F900566F16 /* validate_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7C243667F700566F16 /* validate_type.cpp */; };
-		A9415EDF243667F900566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A7D243667F700566F16 /* instruction.h */; };
-		A9415EE0243667F900566F16 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A7D243667F700566F16 /* instruction.h */; };
-		A9415EE1243667F900566F16 /* validate_execution_limitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7E243667F700566F16 /* validate_execution_limitations.cpp */; };
-		A9415EE2243667F900566F16 /* validate_execution_limitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7E243667F700566F16 /* validate_execution_limitations.cpp */; };
-		A9415EE3243667F900566F16 /* validate_layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7F243667F700566F16 /* validate_layout.cpp */; };
-		A9415EE4243667F900566F16 /* validate_layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A7F243667F700566F16 /* validate_layout.cpp */; };
-		A9415EE5243667F900566F16 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A80243667F700566F16 /* basic_block.cpp */; };
-		A9415EE6243667F900566F16 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A80243667F700566F16 /* basic_block.cpp */; };
-		A9415EE7243667F900566F16 /* validate_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A81243667F700566F16 /* validate_function.cpp */; };
-		A9415EE8243667F900566F16 /* validate_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A81243667F700566F16 /* validate_function.cpp */; };
-		A9415EE9243667F900566F16 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A82243667F700566F16 /* function.h */; };
-		A9415EEA243667F900566F16 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A82243667F700566F16 /* function.h */; };
-		A9415EEB243667F900566F16 /* validate_composites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A83243667F700566F16 /* validate_composites.cpp */; };
-		A9415EEC243667F900566F16 /* validate_composites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A83243667F700566F16 /* validate_composites.cpp */; };
-		A9415EED243667F900566F16 /* validation_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A84243667F700566F16 /* validation_state.cpp */; };
-		A9415EEE243667F900566F16 /* validation_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A84243667F700566F16 /* validation_state.cpp */; };
-		A9415EEF243667F900566F16 /* validate_primitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A85243667F700566F16 /* validate_primitives.cpp */; };
-		A9415EF0243667F900566F16 /* validate_primitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9415A85243667F700566F16 /* validate_primitives.cpp */; };
-		A9415EF1243667F900566F16 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A86243667F700566F16 /* decoration.h */; };
-		A9415EF2243667F900566F16 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9415A86243667F700566F16 /* decoration.h */; };
 		A95D911C23A7F1E500CBCC60 /* glslang.js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A95D90AD23A7F1E500CBCC60 /* glslang.js.cpp */; };
 		A95D911D23A7F1E500CBCC60 /* glslang.js.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A95D90AD23A7F1E500CBCC60 /* glslang.js.cpp */; };
 		A95D911E23A7F1E500CBCC60 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A95D90AF23A7F1E500CBCC60 /* ossource.cpp */; };
@@ -1034,6 +264,788 @@
 		A976292621CC60BC00B52A68 /* spirv_msl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290D21CC60BC00B52A68 /* spirv_msl.cpp */; };
 		A976292721CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290E21CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp */; };
 		A976292821CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A976290E21CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp */; };
+		A9765DF12485758500FDD115 /* spirv_target_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765B9B2485758300FDD115 /* spirv_target_env.cpp */; };
+		A9765DF22485758500FDD115 /* spirv_target_env.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765B9B2485758300FDD115 /* spirv_target_env.cpp */; };
+		A9765DF32485758500FDD115 /* spirv_fuzzer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9D2485758300FDD115 /* spirv_fuzzer_options.h */; };
+		A9765DF42485758500FDD115 /* spirv_fuzzer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9D2485758300FDD115 /* spirv_fuzzer_options.h */; };
+		A9765DF52485758500FDD115 /* assembly_grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9E2485758300FDD115 /* assembly_grammar.h */; };
+		A9765DF62485758500FDD115 /* assembly_grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9E2485758300FDD115 /* assembly_grammar.h */; };
+		A9765DF72485758500FDD115 /* enum_set.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9F2485758300FDD115 /* enum_set.h */; };
+		A9765DF82485758500FDD115 /* enum_set.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765B9F2485758300FDD115 /* enum_set.h */; };
+		A9765DF92485758500FDD115 /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA22485758300FDD115 /* text.cpp */; };
+		A9765DFA2485758500FDD115 /* text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA22485758300FDD115 /* text.cpp */; };
+		A9765DFB2485758500FDD115 /* assembly_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA32485758300FDD115 /* assembly_grammar.cpp */; };
+		A9765DFC2485758500FDD115 /* assembly_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA32485758300FDD115 /* assembly_grammar.cpp */; };
+		A9765DFD2485758500FDD115 /* text.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA42485758300FDD115 /* text.h */; };
+		A9765DFE2485758500FDD115 /* text.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA42485758300FDD115 /* text.h */; };
+		A9765DFF2485758500FDD115 /* extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA52485758300FDD115 /* extensions.cpp */; };
+		A9765E002485758500FDD115 /* extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA52485758300FDD115 /* extensions.cpp */; };
+		A9765E012485758500FDD115 /* pch_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA62485758300FDD115 /* pch_source.cpp */; };
+		A9765E022485758500FDD115 /* pch_source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BA62485758300FDD115 /* pch_source.cpp */; };
+		A9765E032485758500FDD115 /* parse_number.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA82485758300FDD115 /* parse_number.h */; };
+		A9765E042485758500FDD115 /* parse_number.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA82485758300FDD115 /* parse_number.h */; };
+		A9765E052485758500FDD115 /* ilist_node.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA92485758300FDD115 /* ilist_node.h */; };
+		A9765E062485758500FDD115 /* ilist_node.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BA92485758300FDD115 /* ilist_node.h */; };
+		A9765E072485758500FDD115 /* make_unique.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAA2485758300FDD115 /* make_unique.h */; };
+		A9765E082485758500FDD115 /* make_unique.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAA2485758300FDD115 /* make_unique.h */; };
+		A9765E092485758500FDD115 /* string_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAB2485758300FDD115 /* string_utils.h */; };
+		A9765E0A2485758500FDD115 /* string_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAB2485758300FDD115 /* string_utils.h */; };
+		A9765E0B2485758500FDD115 /* small_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAC2485758300FDD115 /* small_vector.h */; };
+		A9765E0C2485758500FDD115 /* small_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAC2485758300FDD115 /* small_vector.h */; };
+		A9765E0D2485758500FDD115 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BAD2485758300FDD115 /* timer.cpp */; };
+		A9765E0E2485758500FDD115 /* timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BAD2485758300FDD115 /* timer.cpp */; };
+		A9765E0F2485758500FDD115 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAE2485758300FDD115 /* timer.h */; };
+		A9765E102485758500FDD115 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BAE2485758300FDD115 /* timer.h */; };
+		A9765E112485758500FDD115 /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BAF2485758300FDD115 /* string_utils.cpp */; };
+		A9765E122485758500FDD115 /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BAF2485758300FDD115 /* string_utils.cpp */; };
+		A9765E132485758500FDD115 /* bit_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB02485758300FDD115 /* bit_vector.h */; };
+		A9765E142485758500FDD115 /* bit_vector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB02485758300FDD115 /* bit_vector.h */; };
+		A9765E152485758500FDD115 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB12485758300FDD115 /* bitutils.h */; };
+		A9765E162485758500FDD115 /* bitutils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB12485758300FDD115 /* bitutils.h */; };
+		A9765E172485758500FDD115 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB22485758300FDD115 /* hex_float.h */; };
+		A9765E182485758500FDD115 /* hex_float.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB22485758300FDD115 /* hex_float.h */; };
+		A9765E192485758500FDD115 /* parse_number.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB32485758300FDD115 /* parse_number.cpp */; };
+		A9765E1A2485758500FDD115 /* parse_number.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB32485758300FDD115 /* parse_number.cpp */; };
+		A9765E1B2485758500FDD115 /* bit_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB42485758300FDD115 /* bit_vector.cpp */; };
+		A9765E1C2485758500FDD115 /* bit_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB42485758300FDD115 /* bit_vector.cpp */; };
+		A9765E1D2485758500FDD115 /* ilist.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB52485758300FDD115 /* ilist.h */; };
+		A9765E1E2485758500FDD115 /* ilist.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB52485758300FDD115 /* ilist.h */; };
+		A9765E1F2485758500FDD115 /* spirv_target_env.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB62485758300FDD115 /* spirv_target_env.h */; };
+		A9765E202485758500FDD115 /* spirv_target_env.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BB62485758300FDD115 /* spirv_target_env.h */; };
+		A9765E212485758500FDD115 /* table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB72485758300FDD115 /* table.cpp */; };
+		A9765E222485758500FDD115 /* table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BB72485758300FDD115 /* table.cpp */; };
+		A9765E232485758500FDD115 /* operand_to_undef_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBA2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.h */; };
+		A9765E242485758500FDD115 /* operand_to_undef_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBA2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.h */; };
+		A9765E252485758500FDD115 /* remove_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBB2485758300FDD115 /* remove_selection_reduction_opportunity.cpp */; };
+		A9765E262485758500FDD115 /* remove_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBB2485758300FDD115 /* remove_selection_reduction_opportunity.cpp */; };
+		A9765E272485758500FDD115 /* remove_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBC2485758300FDD115 /* remove_block_reduction_opportunity.h */; };
+		A9765E282485758500FDD115 /* remove_block_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBC2485758300FDD115 /* remove_block_reduction_opportunity.h */; };
+		A9765E292485758500FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBD2485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h */; };
+		A9765E2A2485758500FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BBD2485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h */; };
+		A9765E2B2485758500FDD115 /* reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBE2485758300FDD115 /* reduction_pass.cpp */; };
+		A9765E2C2485758500FDD115 /* reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBE2485758300FDD115 /* reduction_pass.cpp */; };
+		A9765E2D2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBF2485758300FDD115 /* operand_to_const_reduction_opportunity_finder.cpp */; };
+		A9765E2E2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BBF2485758300FDD115 /* operand_to_const_reduction_opportunity_finder.cpp */; };
+		A9765E2F2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC02485758300FDD115 /* operand_to_const_reduction_opportunity_finder.h */; };
+		A9765E302485758500FDD115 /* operand_to_const_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC02485758300FDD115 /* operand_to_const_reduction_opportunity_finder.h */; };
+		A9765E312485758500FDD115 /* reduction_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC22485758300FDD115 /* reduction_util.cpp */; };
+		A9765E322485758500FDD115 /* reduction_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC22485758300FDD115 /* reduction_util.cpp */; };
+		A9765E332485758500FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC32485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */; };
+		A9765E342485758500FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC32485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */; };
+		A9765E352485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC42485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h */; };
+		A9765E362485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC42485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h */; };
+		A9765E372485758500FDD115 /* remove_function_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC52485758300FDD115 /* remove_function_reduction_opportunity_finder.cpp */; };
+		A9765E382485758500FDD115 /* remove_function_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC52485758300FDD115 /* remove_function_reduction_opportunity_finder.cpp */; };
+		A9765E392485758500FDD115 /* remove_instruction_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC62485758300FDD115 /* remove_instruction_reduction_opportunity.h */; };
+		A9765E3A2485758500FDD115 /* remove_instruction_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC62485758300FDD115 /* remove_instruction_reduction_opportunity.h */; };
+		A9765E3B2485758500FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */; };
+		A9765E3C2485758500FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BC72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */; };
+		A9765E3D2485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC82485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */; };
+		A9765E3E2485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC82485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */; };
+		A9765E3F2485758500FDD115 /* remove_function_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC92485758300FDD115 /* remove_function_reduction_opportunity.cpp */; };
+		A9765E402485758500FDD115 /* remove_function_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BC92485758300FDD115 /* remove_function_reduction_opportunity.cpp */; };
+		A9765E412485758500FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCA2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */; };
+		A9765E422485758500FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCA2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */; };
+		A9765E432485758500FDD115 /* remove_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCB2485758300FDD115 /* remove_selection_reduction_opportunity_finder.cpp */; };
+		A9765E442485758600FDD115 /* remove_selection_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCB2485758300FDD115 /* remove_selection_reduction_opportunity_finder.cpp */; };
+		A9765E452485758600FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCC2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */; };
+		A9765E462485758600FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCC2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */; };
+		A9765E472485758600FDD115 /* remove_struct_member_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BCD2485758300FDD115 /* remove_struct_member_reduction_opportunity.h */; };
+		A9765E482485758600FDD115 /* remove_struct_member_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BCD2485758300FDD115 /* remove_struct_member_reduction_opportunity.h */; };
+		A9765E492485758600FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BCE2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h */; };
+		A9765E4A2485758600FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BCE2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h */; };
+		A9765E4B2485758600FDD115 /* merge_blocks_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCF2485758300FDD115 /* merge_blocks_reduction_opportunity.cpp */; };
+		A9765E4C2485758600FDD115 /* merge_blocks_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BCF2485758300FDD115 /* merge_blocks_reduction_opportunity.cpp */; };
+		A9765E4D2485758600FDD115 /* change_operand_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BD02485758300FDD115 /* change_operand_reduction_opportunity.cpp */; };
+		A9765E4E2485758600FDD115 /* change_operand_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BD02485758300FDD115 /* change_operand_reduction_opportunity.cpp */; };
+		A9765E4F2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD12485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.h */; };
+		A9765E502485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD12485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.h */; };
+		A9765E512485758600FDD115 /* remove_function_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD22485758300FDD115 /* remove_function_reduction_opportunity.h */; };
+		A9765E522485758600FDD115 /* remove_function_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD22485758300FDD115 /* remove_function_reduction_opportunity.h */; };
+		A9765E532485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD32485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h */; };
+		A9765E542485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD32485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h */; };
+		A9765E552485758600FDD115 /* change_operand_to_undef_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD42485758300FDD115 /* change_operand_to_undef_reduction_opportunity.h */; };
+		A9765E562485758600FDD115 /* change_operand_to_undef_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD42485758300FDD115 /* change_operand_to_undef_reduction_opportunity.h */; };
+		A9765E572485758600FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD52485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h */; };
+		A9765E582485758600FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD52485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h */; };
+		A9765E592485758600FDD115 /* remove_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD62485758300FDD115 /* remove_selection_reduction_opportunity.h */; };
+		A9765E5A2485758600FDD115 /* remove_selection_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD62485758300FDD115 /* remove_selection_reduction_opportunity.h */; };
+		A9765E5B2485758600FDD115 /* remove_instruction_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BD72485758300FDD115 /* remove_instruction_reduction_opportunity.cpp */; };
+		A9765E5C2485758600FDD115 /* remove_instruction_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BD72485758300FDD115 /* remove_instruction_reduction_opportunity.cpp */; };
+		A9765E5D2485758600FDD115 /* remove_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD82485758300FDD115 /* remove_selection_reduction_opportunity_finder.h */; };
+		A9765E5E2485758600FDD115 /* remove_selection_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD82485758300FDD115 /* remove_selection_reduction_opportunity_finder.h */; };
+		A9765E5F2485758600FDD115 /* merge_blocks_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD92485758300FDD115 /* merge_blocks_reduction_opportunity_finder.h */; };
+		A9765E602485758600FDD115 /* merge_blocks_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BD92485758300FDD115 /* merge_blocks_reduction_opportunity_finder.h */; };
+		A9765E612485758600FDD115 /* pch_source_reduce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDA2485758300FDD115 /* pch_source_reduce.cpp */; };
+		A9765E622485758600FDD115 /* pch_source_reduce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDA2485758300FDD115 /* pch_source_reduce.cpp */; };
+		A9765E632485758600FDD115 /* remove_struct_member_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDB2485758300FDD115 /* remove_struct_member_reduction_opportunity.cpp */; };
+		A9765E642485758600FDD115 /* remove_struct_member_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDB2485758300FDD115 /* remove_struct_member_reduction_opportunity.cpp */; };
+		A9765E652485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BDC2485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h */; };
+		A9765E662485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BDC2485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h */; };
+		A9765E672485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDD2485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp */; };
+		A9765E682485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDD2485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp */; };
+		A9765E692485758600FDD115 /* reducer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDE2485758300FDD115 /* reducer.cpp */; };
+		A9765E6A2485758600FDD115 /* reducer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDE2485758300FDD115 /* reducer.cpp */; };
+		A9765E6B2485758600FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDF2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp */; };
+		A9765E6C2485758600FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BDF2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp */; };
+		A9765E6D2485758600FDD115 /* remove_function_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE02485758300FDD115 /* remove_function_reduction_opportunity_finder.h */; };
+		A9765E6E2485758600FDD115 /* remove_function_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE02485758300FDD115 /* remove_function_reduction_opportunity_finder.h */; };
+		A9765E6F2485758600FDD115 /* pch_source_reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE12485758300FDD115 /* pch_source_reduce.h */; };
+		A9765E702485758600FDD115 /* pch_source_reduce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE12485758300FDD115 /* pch_source_reduce.h */; };
+		A9765E712485758600FDD115 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE22485758300FDD115 /* merge_blocks_reduction_opportunity_finder.cpp */; };
+		A9765E722485758600FDD115 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE22485758300FDD115 /* merge_blocks_reduction_opportunity_finder.cpp */; };
+		A9765E732485758600FDD115 /* reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE32485758300FDD115 /* reduction_opportunity.cpp */; };
+		A9765E742485758600FDD115 /* reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE32485758300FDD115 /* reduction_opportunity.cpp */; };
+		A9765E752485758600FDD115 /* reducer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE42485758300FDD115 /* reducer.h */; };
+		A9765E762485758600FDD115 /* reducer.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE42485758300FDD115 /* reducer.h */; };
+		A9765E772485758600FDD115 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE52485758300FDD115 /* change_operand_to_undef_reduction_opportunity.cpp */; };
+		A9765E782485758600FDD115 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE52485758300FDD115 /* change_operand_to_undef_reduction_opportunity.cpp */; };
+		A9765E792485758600FDD115 /* reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE62485758300FDD115 /* reduction_opportunity.h */; };
+		A9765E7A2485758600FDD115 /* reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE62485758300FDD115 /* reduction_opportunity.h */; };
+		A9765E7B2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */; };
+		A9765E7C2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */; };
+		A9765E7D2485758600FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE82485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */; };
+		A9765E7E2485758600FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BE82485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */; };
+		A9765E7F2485758600FDD115 /* reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE92485758300FDD115 /* reduction_opportunity_finder.h */; };
+		A9765E802485758600FDD115 /* reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BE92485758300FDD115 /* reduction_opportunity_finder.h */; };
+		A9765E812485758600FDD115 /* change_operand_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEA2485758300FDD115 /* change_operand_reduction_opportunity.h */; };
+		A9765E822485758600FDD115 /* change_operand_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEA2485758300FDD115 /* change_operand_reduction_opportunity.h */; };
+		A9765E832485758600FDD115 /* remove_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEB2485758300FDD115 /* remove_block_reduction_opportunity_finder.h */; };
+		A9765E842485758600FDD115 /* remove_block_reduction_opportunity_finder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEB2485758300FDD115 /* remove_block_reduction_opportunity_finder.h */; };
+		A9765E852485758600FDD115 /* remove_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BEC2485758300FDD115 /* remove_block_reduction_opportunity_finder.cpp */; };
+		A9765E862485758600FDD115 /* remove_block_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BEC2485758300FDD115 /* remove_block_reduction_opportunity_finder.cpp */; };
+		A9765E872485758600FDD115 /* reduction_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BED2485758300FDD115 /* reduction_util.h */; };
+		A9765E882485758600FDD115 /* reduction_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BED2485758300FDD115 /* reduction_util.h */; };
+		A9765E892485758600FDD115 /* merge_blocks_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEE2485758300FDD115 /* merge_blocks_reduction_opportunity.h */; };
+		A9765E8A2485758600FDD115 /* merge_blocks_reduction_opportunity.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BEE2485758300FDD115 /* merge_blocks_reduction_opportunity.h */; };
+		A9765E8B2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BEF2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */; };
+		A9765E8C2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BEF2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */; };
+		A9765E8D2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF02485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp */; };
+		A9765E8E2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF02485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp */; };
+		A9765E8F2485758600FDD115 /* remove_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF12485758300FDD115 /* remove_block_reduction_opportunity.cpp */; };
+		A9765E902485758600FDD115 /* remove_block_reduction_opportunity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF12485758300FDD115 /* remove_block_reduction_opportunity.cpp */; };
+		A9765E912485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF22485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp */; };
+		A9765E922485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF22485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp */; };
+		A9765E932485758600FDD115 /* reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF32485758300FDD115 /* reduction_pass.h */; };
+		A9765E942485758600FDD115 /* reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF32485758300FDD115 /* reduction_pass.h */; };
+		A9765E952485758600FDD115 /* latest_version_opencl_std_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF42485758300FDD115 /* latest_version_opencl_std_header.h */; };
+		A9765E962485758600FDD115 /* latest_version_opencl_std_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF42485758300FDD115 /* latest_version_opencl_std_header.h */; };
+		A9765E972485758600FDD115 /* spirv_optimizer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF52485758300FDD115 /* spirv_optimizer_options.cpp */; };
+		A9765E982485758600FDD115 /* spirv_optimizer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF52485758300FDD115 /* spirv_optimizer_options.cpp */; };
+		A9765E992485758600FDD115 /* cfa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF62485758300FDD115 /* cfa.h */; };
+		A9765E9A2485758600FDD115 /* cfa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF62485758300FDD115 /* cfa.h */; };
+		A9765E9B2485758600FDD115 /* pch_source.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF72485758300FDD115 /* pch_source.h */; };
+		A9765E9C2485758600FDD115 /* pch_source.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF72485758300FDD115 /* pch_source.h */; };
+		A9765E9D2485758600FDD115 /* enum_string_mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF82485758300FDD115 /* enum_string_mapping.h */; };
+		A9765E9E2485758600FDD115 /* enum_string_mapping.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BF82485758300FDD115 /* enum_string_mapping.h */; };
+		A9765E9F2485758600FDD115 /* spirv_fuzzer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF92485758300FDD115 /* spirv_fuzzer_options.cpp */; };
+		A9765EA02485758600FDD115 /* spirv_fuzzer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BF92485758300FDD115 /* spirv_fuzzer_options.cpp */; };
+		A9765EA12485758600FDD115 /* spirv_reducer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFA2485758300FDD115 /* spirv_reducer_options.h */; };
+		A9765EA22485758600FDD115 /* spirv_reducer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFA2485758300FDD115 /* spirv_reducer_options.h */; };
+		A9765EA32485758600FDD115 /* spirv_validator_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BFB2485758300FDD115 /* spirv_validator_options.cpp */; };
+		A9765EA42485758600FDD115 /* spirv_validator_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BFB2485758300FDD115 /* spirv_validator_options.cpp */; };
+		A9765EA52485758600FDD115 /* print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BFD2485758300FDD115 /* print.cpp */; };
+		A9765EA62485758600FDD115 /* print.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765BFD2485758300FDD115 /* print.cpp */; };
+		A9765EA72485758600FDD115 /* spirv_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFE2485758300FDD115 /* spirv_definition.h */; };
+		A9765EA82485758600FDD115 /* spirv_definition.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFE2485758300FDD115 /* spirv_definition.h */; };
+		A9765EA92485758600FDD115 /* operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFF2485758300FDD115 /* operand.h */; };
+		A9765EAA2485758600FDD115 /* operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765BFF2485758300FDD115 /* operand.h */; };
+		A9765EAB2485758600FDD115 /* spirv_endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C002485758300FDD115 /* spirv_endian.cpp */; };
+		A9765EAC2485758600FDD115 /* spirv_endian.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C002485758300FDD115 /* spirv_endian.cpp */; };
+		A9765EAD2485758600FDD115 /* macro.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C012485758300FDD115 /* macro.h */; };
+		A9765EAE2485758600FDD115 /* macro.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C012485758300FDD115 /* macro.h */; };
+		A9765EAF2485758600FDD115 /* spirv_constant.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C022485758300FDD115 /* spirv_constant.h */; };
+		A9765EB02485758600FDD115 /* spirv_constant.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C022485758300FDD115 /* spirv_constant.h */; };
+		A9765EB12485758600FDD115 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C042485758300FDD115 /* binary.cpp */; };
+		A9765EB22485758600FDD115 /* binary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C042485758300FDD115 /* binary.cpp */; };
+		A9765EB32485758600FDD115 /* spirv_validator_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C052485758300FDD115 /* spirv_validator_options.h */; };
+		A9765EB42485758600FDD115 /* spirv_validator_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C052485758300FDD115 /* spirv_validator_options.h */; };
+		A9765EB52485758600FDD115 /* enum_string_mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C062485758300FDD115 /* enum_string_mapping.cpp */; };
+		A9765EB62485758600FDD115 /* enum_string_mapping.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C062485758300FDD115 /* enum_string_mapping.cpp */; };
+		A9765EB72485758600FDD115 /* text_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C072485758300FDD115 /* text_handler.h */; };
+		A9765EB82485758600FDD115 /* text_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C072485758300FDD115 /* text_handler.h */; };
+		A9765EB92485758600FDD115 /* parsed_operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C082485758300FDD115 /* parsed_operand.h */; };
+		A9765EBA2485758600FDD115 /* parsed_operand.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C082485758300FDD115 /* parsed_operand.h */; };
+		A9765EBB2485758600FDD115 /* name_mapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C092485758300FDD115 /* name_mapper.h */; };
+		A9765EBC2485758600FDD115 /* name_mapper.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C092485758300FDD115 /* name_mapper.h */; };
+		A9765EBD2485758600FDD115 /* spirv_reducer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0A2485758300FDD115 /* spirv_reducer_options.cpp */; };
+		A9765EBE2485758600FDD115 /* spirv_reducer_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0A2485758300FDD115 /* spirv_reducer_options.cpp */; };
+		A9765EBF2485758600FDD115 /* parsed_operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0B2485758300FDD115 /* parsed_operand.cpp */; };
+		A9765EC02485758600FDD115 /* parsed_operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0B2485758300FDD115 /* parsed_operand.cpp */; };
+		A9765EC12485758600FDD115 /* diagnostic.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C0C2485758300FDD115 /* diagnostic.h */; };
+		A9765EC22485758600FDD115 /* diagnostic.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C0C2485758300FDD115 /* diagnostic.h */; };
+		A9765EC32485758600FDD115 /* spirv_endian.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C0D2485758300FDD115 /* spirv_endian.h */; };
+		A9765EC42485758600FDD115 /* spirv_endian.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C0D2485758300FDD115 /* spirv_endian.h */; };
+		A9765EC52485758600FDD115 /* name_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0E2485758300FDD115 /* name_mapper.cpp */; };
+		A9765EC62485758600FDD115 /* name_mapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C0E2485758300FDD115 /* name_mapper.cpp */; };
+		A9765EC72485758600FDD115 /* linker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C122485758300FDD115 /* linker.cpp */; };
+		A9765EC82485758600FDD115 /* linker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C122485758300FDD115 /* linker.cpp */; };
+		A9765EC92485758600FDD115 /* software_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C132485758300FDD115 /* software_version.cpp */; };
+		A9765ECA2485758600FDD115 /* software_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C132485758300FDD115 /* software_version.cpp */; };
+		A9765ECB2485758600FDD115 /* opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C142485758300FDD115 /* opcode.cpp */; };
+		A9765ECC2485758600FDD115 /* opcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C142485758300FDD115 /* opcode.cpp */; };
+		A9765ECD2485758600FDD115 /* print.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C152485758300FDD115 /* print.h */; };
+		A9765ECE2485758600FDD115 /* print.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C152485758300FDD115 /* print.h */; };
+		A9765ECF2485758600FDD115 /* ext_inst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C162485758300FDD115 /* ext_inst.cpp */; };
+		A9765ED02485758600FDD115 /* ext_inst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C162485758300FDD115 /* ext_inst.cpp */; };
+		A9765ED12485758600FDD115 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C172485758300FDD115 /* disassemble.h */; };
+		A9765ED22485758600FDD115 /* disassemble.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C172485758300FDD115 /* disassemble.h */; };
+		A9765ED32485758600FDD115 /* optimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C192485758300FDD115 /* optimizer.cpp */; };
+		A9765ED42485758600FDD115 /* optimizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C192485758300FDD115 /* optimizer.cpp */; };
+		A9765ED52485758600FDD115 /* if_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1A2485758300FDD115 /* if_conversion.h */; };
+		A9765ED62485758600FDD115 /* if_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1A2485758300FDD115 /* if_conversion.h */; };
+		A9765ED72485758600FDD115 /* register_pressure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C1B2485758300FDD115 /* register_pressure.cpp */; };
+		A9765ED82485758600FDD115 /* register_pressure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C1B2485758300FDD115 /* register_pressure.cpp */; };
+		A9765ED92485758600FDD115 /* loop_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C1C2485758300FDD115 /* loop_utils.cpp */; };
+		A9765EDA2485758600FDD115 /* loop_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C1C2485758300FDD115 /* loop_utils.cpp */; };
+		A9765EDB2485758600FDD115 /* merge_return_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1D2485758300FDD115 /* merge_return_pass.h */; };
+		A9765EDC2485758600FDD115 /* merge_return_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1D2485758300FDD115 /* merge_return_pass.h */; };
+		A9765EDD2485758600FDD115 /* inline_opaque_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1E2485758300FDD115 /* inline_opaque_pass.h */; };
+		A9765EDE2485758600FDD115 /* inline_opaque_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1E2485758300FDD115 /* inline_opaque_pass.h */; };
+		A9765EDF2485758600FDD115 /* loop_fusion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1F2485758300FDD115 /* loop_fusion.h */; };
+		A9765EE02485758600FDD115 /* loop_fusion.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C1F2485758300FDD115 /* loop_fusion.h */; };
+		A9765EE12485758600FDD115 /* combine_access_chains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C202485758300FDD115 /* combine_access_chains.cpp */; };
+		A9765EE22485758600FDD115 /* combine_access_chains.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C202485758300FDD115 /* combine_access_chains.cpp */; };
+		A9765EE32485758600FDD115 /* build_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C212485758300FDD115 /* build_module.cpp */; };
+		A9765EE42485758600FDD115 /* build_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C212485758300FDD115 /* build_module.cpp */; };
+		A9765EE52485758600FDD115 /* composite.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C222485758300FDD115 /* composite.h */; };
+		A9765EE62485758600FDD115 /* composite.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C222485758300FDD115 /* composite.h */; };
+		A9765EE72485758600FDD115 /* compact_ids_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C232485758300FDD115 /* compact_ids_pass.h */; };
+		A9765EE82485758600FDD115 /* compact_ids_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C232485758300FDD115 /* compact_ids_pass.h */; };
+		A9765EE92485758600FDD115 /* register_pressure.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C242485758300FDD115 /* register_pressure.h */; };
+		A9765EEA2485758600FDD115 /* register_pressure.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C242485758300FDD115 /* register_pressure.h */; };
+		A9765EEB2485758600FDD115 /* tree_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C252485758300FDD115 /* tree_iterator.h */; };
+		A9765EEC2485758600FDD115 /* tree_iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C252485758300FDD115 /* tree_iterator.h */; };
+		A9765EED2485758600FDD115 /* graphics_robust_access_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C262485758300FDD115 /* graphics_robust_access_pass.h */; };
+		A9765EEE2485758600FDD115 /* graphics_robust_access_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C262485758300FDD115 /* graphics_robust_access_pass.h */; };
+		A9765EEF2485758600FDD115 /* strip_atomic_counter_memory_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C272485758300FDD115 /* strip_atomic_counter_memory_pass.h */; };
+		A9765EF02485758600FDD115 /* strip_atomic_counter_memory_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C272485758300FDD115 /* strip_atomic_counter_memory_pass.h */; };
+		A9765EF12485758600FDD115 /* legalize_vector_shuffle_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C282485758300FDD115 /* legalize_vector_shuffle_pass.h */; };
+		A9765EF22485758600FDD115 /* legalize_vector_shuffle_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C282485758300FDD115 /* legalize_vector_shuffle_pass.h */; };
+		A9765EF32485758600FDD115 /* local_single_store_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C292485758300FDD115 /* local_single_store_elim_pass.h */; };
+		A9765EF42485758600FDD115 /* local_single_store_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C292485758300FDD115 /* local_single_store_elim_pass.h */; };
+		A9765EF52485758600FDD115 /* reduce_load_size.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2A2485758300FDD115 /* reduce_load_size.h */; };
+		A9765EF62485758600FDD115 /* reduce_load_size.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2A2485758300FDD115 /* reduce_load_size.h */; };
+		A9765EF72485758600FDD115 /* code_sink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2B2485758300FDD115 /* code_sink.cpp */; };
+		A9765EF82485758600FDD115 /* code_sink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2B2485758300FDD115 /* code_sink.cpp */; };
+		A9765EF92485758600FDD115 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2C2485758300FDD115 /* types.cpp */; };
+		A9765EFA2485758600FDD115 /* types.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2C2485758300FDD115 /* types.cpp */; };
+		A9765EFB2485758600FDD115 /* scalar_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2D2485758300FDD115 /* scalar_analysis.h */; };
+		A9765EFC2485758600FDD115 /* scalar_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2D2485758300FDD115 /* scalar_analysis.h */; };
+		A9765EFD2485758600FDD115 /* strip_debug_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2E2485758300FDD115 /* strip_debug_info_pass.h */; };
+		A9765EFE2485758600FDD115 /* strip_debug_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C2E2485758300FDD115 /* strip_debug_info_pass.h */; };
+		A9765EFF2485758600FDD115 /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2F2485758300FDD115 /* cfg.cpp */; };
+		A9765F002485758600FDD115 /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C2F2485758300FDD115 /* cfg.cpp */; };
+		A9765F012485758600FDD115 /* strip_atomic_counter_memory_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C302485758300FDD115 /* strip_atomic_counter_memory_pass.cpp */; };
+		A9765F022485758600FDD115 /* strip_atomic_counter_memory_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C302485758300FDD115 /* strip_atomic_counter_memory_pass.cpp */; };
+		A9765F032485758600FDD115 /* decoration_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C312485758300FDD115 /* decoration_manager.cpp */; };
+		A9765F042485758600FDD115 /* decoration_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C312485758300FDD115 /* decoration_manager.cpp */; };
+		A9765F052485758600FDD115 /* local_single_block_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C322485758300FDD115 /* local_single_block_elim_pass.cpp */; };
+		A9765F062485758600FDD115 /* local_single_block_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C322485758300FDD115 /* local_single_block_elim_pass.cpp */; };
+		A9765F072485758600FDD115 /* freeze_spec_constant_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C332485758300FDD115 /* freeze_spec_constant_value_pass.cpp */; };
+		A9765F082485758600FDD115 /* freeze_spec_constant_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C332485758300FDD115 /* freeze_spec_constant_value_pass.cpp */; };
+		A9765F092485758600FDD115 /* replace_invalid_opc.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C342485758300FDD115 /* replace_invalid_opc.h */; };
+		A9765F0A2485758600FDD115 /* replace_invalid_opc.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C342485758300FDD115 /* replace_invalid_opc.h */; };
+		A9765F0B2485758600FDD115 /* local_access_chain_convert_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C352485758300FDD115 /* local_access_chain_convert_pass.h */; };
+		A9765F0C2485758600FDD115 /* local_access_chain_convert_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C352485758300FDD115 /* local_access_chain_convert_pass.h */; };
+		A9765F0D2485758600FDD115 /* inst_bindless_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C362485758300FDD115 /* inst_bindless_check_pass.cpp */; };
+		A9765F0E2485758600FDD115 /* inst_bindless_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C362485758300FDD115 /* inst_bindless_check_pass.cpp */; };
+		A9765F0F2485758600FDD115 /* local_redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C372485758300FDD115 /* local_redundancy_elimination.cpp */; };
+		A9765F102485758600FDD115 /* local_redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C372485758300FDD115 /* local_redundancy_elimination.cpp */; };
+		A9765F112485758600FDD115 /* instrument_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C392485758300FDD115 /* instrument_pass.cpp */; };
+		A9765F122485758600FDD115 /* instrument_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C392485758300FDD115 /* instrument_pass.cpp */; };
+		A9765F132485758600FDD115 /* propagator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C3A2485758300FDD115 /* propagator.h */; };
+		A9765F142485758600FDD115 /* propagator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C3A2485758300FDD115 /* propagator.h */; };
+		A9765F152485758600FDD115 /* instruction_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C3B2485758300FDD115 /* instruction_list.h */; };
+		A9765F162485758600FDD115 /* instruction_list.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C3B2485758300FDD115 /* instruction_list.h */; };
+		A9765F172485758600FDD115 /* feature_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3C2485758300FDD115 /* feature_manager.cpp */; };
+		A9765F182485758600FDD115 /* feature_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3C2485758300FDD115 /* feature_manager.cpp */; };
+		A9765F192485758600FDD115 /* pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3D2485758300FDD115 /* pass.cpp */; };
+		A9765F1A2485758600FDD115 /* pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3D2485758300FDD115 /* pass.cpp */; };
+		A9765F1B2485758600FDD115 /* loop_fission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3E2485758300FDD115 /* loop_fission.cpp */; };
+		A9765F1C2485758600FDD115 /* loop_fission.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3E2485758300FDD115 /* loop_fission.cpp */; };
+		A9765F1D2485758600FDD115 /* dominator_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3F2485758300FDD115 /* dominator_tree.cpp */; };
+		A9765F1E2485758600FDD115 /* dominator_tree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C3F2485758300FDD115 /* dominator_tree.cpp */; };
+		A9765F1F2485758600FDD115 /* amd_ext_to_khr.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C402485758300FDD115 /* amd_ext_to_khr.h */; };
+		A9765F202485758600FDD115 /* amd_ext_to_khr.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C402485758300FDD115 /* amd_ext_to_khr.h */; };
+		A9765F212485758600FDD115 /* merge_return_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C412485758300FDD115 /* merge_return_pass.cpp */; };
+		A9765F222485758600FDD115 /* merge_return_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C412485758300FDD115 /* merge_return_pass.cpp */; };
+		A9765F232485758600FDD115 /* ir_context.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C422485758300FDD115 /* ir_context.h */; };
+		A9765F242485758600FDD115 /* ir_context.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C422485758300FDD115 /* ir_context.h */; };
+		A9765F252485758600FDD115 /* eliminate_dead_constant_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C432485758300FDD115 /* eliminate_dead_constant_pass.cpp */; };
+		A9765F262485758600FDD115 /* eliminate_dead_constant_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C432485758300FDD115 /* eliminate_dead_constant_pass.cpp */; };
+		A9765F272485758600FDD115 /* cfg_cleanup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C442485758300FDD115 /* cfg_cleanup_pass.cpp */; };
+		A9765F282485758600FDD115 /* cfg_cleanup_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C442485758300FDD115 /* cfg_cleanup_pass.cpp */; };
+		A9765F292485758600FDD115 /* wrap_opkill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C452485758300FDD115 /* wrap_opkill.cpp */; };
+		A9765F2A2485758600FDD115 /* wrap_opkill.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C452485758300FDD115 /* wrap_opkill.cpp */; };
+		A9765F2B2485758600FDD115 /* const_folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C462485758300FDD115 /* const_folding_rules.cpp */; };
+		A9765F2C2485758600FDD115 /* const_folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C462485758300FDD115 /* const_folding_rules.cpp */; };
+		A9765F2D2485758600FDD115 /* loop_unroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C472485758300FDD115 /* loop_unroller.h */; };
+		A9765F2E2485758600FDD115 /* loop_unroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C472485758300FDD115 /* loop_unroller.h */; };
+		A9765F2F2485758600FDD115 /* strip_debug_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C482485758300FDD115 /* strip_debug_info_pass.cpp */; };
+		A9765F302485758600FDD115 /* strip_debug_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C482485758300FDD115 /* strip_debug_info_pass.cpp */; };
+		A9765F312485758600FDD115 /* ssa_rewrite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C492485758300FDD115 /* ssa_rewrite_pass.cpp */; };
+		A9765F322485758600FDD115 /* ssa_rewrite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C492485758300FDD115 /* ssa_rewrite_pass.cpp */; };
+		A9765F332485758600FDD115 /* loop_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C4A2485758300FDD115 /* loop_dependence.cpp */; };
+		A9765F342485758600FDD115 /* loop_dependence.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C4A2485758300FDD115 /* loop_dependence.cpp */; };
+		A9765F352485758600FDD115 /* unify_const_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4B2485758300FDD115 /* unify_const_pass.h */; };
+		A9765F362485758600FDD115 /* unify_const_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4B2485758300FDD115 /* unify_const_pass.h */; };
+		A9765F372485758600FDD115 /* ir_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4C2485758300FDD115 /* ir_loader.h */; };
+		A9765F382485758600FDD115 /* ir_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4C2485758300FDD115 /* ir_loader.h */; };
+		A9765F392485758600FDD115 /* inst_debug_printf_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C4D2485758300FDD115 /* inst_debug_printf_pass.cpp */; };
+		A9765F3A2485758600FDD115 /* inst_debug_printf_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C4D2485758300FDD115 /* inst_debug_printf_pass.cpp */; };
+		A9765F3B2485758600FDD115 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4E2485758300FDD115 /* types.h */; };
+		A9765F3C2485758600FDD115 /* types.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4E2485758300FDD115 /* types.h */; };
+		A9765F3D2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4F2485758300FDD115 /* fold_spec_constant_op_and_composite_pass.h */; };
+		A9765F3E2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C4F2485758300FDD115 /* fold_spec_constant_op_and_composite_pass.h */; };
+		A9765F3F2485758600FDD115 /* mem_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C502485758300FDD115 /* mem_pass.cpp */; };
+		A9765F402485758600FDD115 /* mem_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C502485758300FDD115 /* mem_pass.cpp */; };
+		A9765F412485758600FDD115 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C512485758300FDD115 /* basic_block.h */; };
+		A9765F422485758600FDD115 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C512485758300FDD115 /* basic_block.h */; };
+		A9765F432485758600FDD115 /* remove_duplicates_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C522485758300FDD115 /* remove_duplicates_pass.cpp */; };
+		A9765F442485758600FDD115 /* remove_duplicates_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C522485758300FDD115 /* remove_duplicates_pass.cpp */; };
+		A9765F452485758600FDD115 /* dead_variable_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C532485758300FDD115 /* dead_variable_elimination.cpp */; };
+		A9765F462485758600FDD115 /* dead_variable_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C532485758300FDD115 /* dead_variable_elimination.cpp */; };
+		A9765F472485758600FDD115 /* block_merge_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C542485758300FDD115 /* block_merge_pass.h */; };
+		A9765F482485758600FDD115 /* block_merge_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C542485758300FDD115 /* block_merge_pass.h */; };
+		A9765F492485758600FDD115 /* module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C552485758400FDD115 /* module.cpp */; };
+		A9765F4A2485758600FDD115 /* module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C552485758400FDD115 /* module.cpp */; };
+		A9765F4B2485758600FDD115 /* debug_info_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C562485758400FDD115 /* debug_info_manager.h */; };
+		A9765F4C2485758600FDD115 /* debug_info_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C562485758400FDD115 /* debug_info_manager.h */; };
+		A9765F4D2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C572485758400FDD115 /* fold_spec_constant_op_and_composite_pass.cpp */; };
+		A9765F4E2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C572485758400FDD115 /* fold_spec_constant_op_and_composite_pass.cpp */; };
+		A9765F4F2485758600FDD115 /* loop_unswitch_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C582485758400FDD115 /* loop_unswitch_pass.cpp */; };
+		A9765F502485758600FDD115 /* loop_unswitch_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C582485758400FDD115 /* loop_unswitch_pass.cpp */; };
+		A9765F512485758600FDD115 /* unify_const_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C592485758400FDD115 /* unify_const_pass.cpp */; };
+		A9765F522485758600FDD115 /* unify_const_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C592485758400FDD115 /* unify_const_pass.cpp */; };
+		A9765F532485758600FDD115 /* type_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5A2485758400FDD115 /* type_manager.cpp */; };
+		A9765F542485758600FDD115 /* type_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5A2485758400FDD115 /* type_manager.cpp */; };
+		A9765F552485758600FDD115 /* generate_webgpu_initializers_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5B2485758400FDD115 /* generate_webgpu_initializers_pass.cpp */; };
+		A9765F562485758600FDD115 /* generate_webgpu_initializers_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5B2485758400FDD115 /* generate_webgpu_initializers_pass.cpp */; };
+		A9765F572485758600FDD115 /* private_to_local_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5C2485758400FDD115 /* private_to_local_pass.h */; };
+		A9765F582485758600FDD115 /* private_to_local_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5C2485758400FDD115 /* private_to_local_pass.h */; };
+		A9765F592485758600FDD115 /* convert_to_half_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5D2485758400FDD115 /* convert_to_half_pass.h */; };
+		A9765F5A2485758600FDD115 /* convert_to_half_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5D2485758400FDD115 /* convert_to_half_pass.h */; };
+		A9765F5B2485758600FDD115 /* relax_float_ops_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5E2485758400FDD115 /* relax_float_ops_pass.h */; };
+		A9765F5C2485758600FDD115 /* relax_float_ops_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C5E2485758400FDD115 /* relax_float_ops_pass.h */; };
+		A9765F5D2485758600FDD115 /* inline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5F2485758400FDD115 /* inline_pass.cpp */; };
+		A9765F5E2485758600FDD115 /* inline_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C5F2485758400FDD115 /* inline_pass.cpp */; };
+		A9765F5F2485758600FDD115 /* def_use_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C602485758400FDD115 /* def_use_manager.h */; };
+		A9765F602485758600FDD115 /* def_use_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C602485758400FDD115 /* def_use_manager.h */; };
+		A9765F612485758600FDD115 /* ir_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C612485758400FDD115 /* ir_loader.cpp */; };
+		A9765F622485758600FDD115 /* ir_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C612485758400FDD115 /* ir_loader.cpp */; };
+		A9765F632485758600FDD115 /* cfg_cleanup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C622485758400FDD115 /* cfg_cleanup_pass.h */; };
+		A9765F642485758600FDD115 /* cfg_cleanup_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C622485758400FDD115 /* cfg_cleanup_pass.h */; };
+		A9765F652485758600FDD115 /* licm_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C632485758400FDD115 /* licm_pass.cpp */; };
+		A9765F662485758600FDD115 /* licm_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C632485758400FDD115 /* licm_pass.cpp */; };
+		A9765F672485758600FDD115 /* eliminate_dead_functions_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C642485758400FDD115 /* eliminate_dead_functions_pass.cpp */; };
+		A9765F682485758600FDD115 /* eliminate_dead_functions_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C642485758400FDD115 /* eliminate_dead_functions_pass.cpp */; };
+		A9765F692485758600FDD115 /* local_redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C652485758400FDD115 /* local_redundancy_elimination.h */; };
+		A9765F6A2485758600FDD115 /* local_redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C652485758400FDD115 /* local_redundancy_elimination.h */; };
+		A9765F6B2485758600FDD115 /* split_invalid_unreachable_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C662485758400FDD115 /* split_invalid_unreachable_pass.cpp */; };
+		A9765F6C2485758600FDD115 /* split_invalid_unreachable_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C662485758400FDD115 /* split_invalid_unreachable_pass.cpp */; };
+		A9765F6D2485758600FDD115 /* loop_peeling.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C672485758400FDD115 /* loop_peeling.h */; };
+		A9765F6E2485758600FDD115 /* loop_peeling.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C672485758400FDD115 /* loop_peeling.h */; };
+		A9765F6F2485758600FDD115 /* vector_dce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C682485758400FDD115 /* vector_dce.cpp */; };
+		A9765F702485758600FDD115 /* vector_dce.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C682485758400FDD115 /* vector_dce.cpp */; };
+		A9765F712485758600FDD115 /* block_merge_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C692485758400FDD115 /* block_merge_util.h */; };
+		A9765F722485758600FDD115 /* block_merge_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C692485758400FDD115 /* block_merge_util.h */; };
+		A9765F732485758600FDD115 /* loop_unroller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6A2485758400FDD115 /* loop_unroller.cpp */; };
+		A9765F742485758600FDD115 /* loop_unroller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6A2485758400FDD115 /* loop_unroller.cpp */; };
+		A9765F752485758600FDD115 /* desc_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6B2485758400FDD115 /* desc_sroa.h */; };
+		A9765F762485758600FDD115 /* desc_sroa.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6B2485758400FDD115 /* desc_sroa.h */; };
+		A9765F772485758600FDD115 /* constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6C2485758400FDD115 /* constants.cpp */; };
+		A9765F782485758600FDD115 /* constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6C2485758400FDD115 /* constants.cpp */; };
+		A9765F792485758600FDD115 /* loop_fusion_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6D2485758400FDD115 /* loop_fusion_pass.h */; };
+		A9765F7A2485758600FDD115 /* loop_fusion_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6D2485758400FDD115 /* loop_fusion_pass.h */; };
+		A9765F7B2485758600FDD115 /* struct_cfg_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6E2485758400FDD115 /* struct_cfg_analysis.h */; };
+		A9765F7C2485758600FDD115 /* struct_cfg_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C6E2485758400FDD115 /* struct_cfg_analysis.h */; };
+		A9765F7D2485758600FDD115 /* inst_buff_addr_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6F2485758400FDD115 /* inst_buff_addr_check_pass.cpp */; };
+		A9765F7E2485758600FDD115 /* inst_buff_addr_check_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C6F2485758400FDD115 /* inst_buff_addr_check_pass.cpp */; };
+		A9765F7F2485758600FDD115 /* def_use_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C702485758400FDD115 /* def_use_manager.cpp */; };
+		A9765F802485758600FDD115 /* def_use_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C702485758400FDD115 /* def_use_manager.cpp */; };
+		A9765F812485758600FDD115 /* wrap_opkill.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C712485758400FDD115 /* wrap_opkill.h */; };
+		A9765F822485758600FDD115 /* wrap_opkill.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C712485758400FDD115 /* wrap_opkill.h */; };
+		A9765F832485758600FDD115 /* strip_reflect_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C722485758400FDD115 /* strip_reflect_info_pass.cpp */; };
+		A9765F842485758600FDD115 /* strip_reflect_info_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C722485758400FDD115 /* strip_reflect_info_pass.cpp */; };
+		A9765F852485758600FDD115 /* decoration_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C732485758400FDD115 /* decoration_manager.h */; };
+		A9765F862485758600FDD115 /* decoration_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C732485758400FDD115 /* decoration_manager.h */; };
+		A9765F872485758600FDD115 /* ccp_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C742485758400FDD115 /* ccp_pass.cpp */; };
+		A9765F882485758600FDD115 /* ccp_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C742485758400FDD115 /* ccp_pass.cpp */; };
+		A9765F892485758600FDD115 /* process_lines_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C752485758400FDD115 /* process_lines_pass.h */; };
+		A9765F8A2485758600FDD115 /* process_lines_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C752485758400FDD115 /* process_lines_pass.h */; };
+		A9765F8B2485758600FDD115 /* local_single_block_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C762485758400FDD115 /* local_single_block_elim_pass.h */; };
+		A9765F8C2485758600FDD115 /* local_single_block_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C762485758400FDD115 /* local_single_block_elim_pass.h */; };
+		A9765F8D2485758600FDD115 /* pch_source_opt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C772485758400FDD115 /* pch_source_opt.cpp */; };
+		A9765F8E2485758600FDD115 /* pch_source_opt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C772485758400FDD115 /* pch_source_opt.cpp */; };
+		A9765F8F2485758600FDD115 /* inst_buff_addr_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C782485758400FDD115 /* inst_buff_addr_check_pass.h */; };
+		A9765F902485758600FDD115 /* inst_buff_addr_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C782485758400FDD115 /* inst_buff_addr_check_pass.h */; };
+		A9765F912485758600FDD115 /* strength_reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C792485758400FDD115 /* strength_reduction_pass.h */; };
+		A9765F922485758600FDD115 /* strength_reduction_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C792485758400FDD115 /* strength_reduction_pass.h */; };
+		A9765F932485758600FDD115 /* aggressive_dead_code_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7A2485758400FDD115 /* aggressive_dead_code_elim_pass.cpp */; };
+		A9765F942485758600FDD115 /* aggressive_dead_code_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7A2485758400FDD115 /* aggressive_dead_code_elim_pass.cpp */; };
+		A9765F952485758600FDD115 /* eliminate_dead_functions_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7B2485758400FDD115 /* eliminate_dead_functions_util.cpp */; };
+		A9765F962485758600FDD115 /* eliminate_dead_functions_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7B2485758400FDD115 /* eliminate_dead_functions_util.cpp */; };
+		A9765F972485758600FDD115 /* inst_debug_printf_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C7C2485758400FDD115 /* inst_debug_printf_pass.h */; };
+		A9765F982485758600FDD115 /* inst_debug_printf_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C7C2485758400FDD115 /* inst_debug_printf_pass.h */; };
+		A9765F992485758600FDD115 /* simplification_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7D2485758400FDD115 /* simplification_pass.cpp */; };
+		A9765F9A2485758600FDD115 /* simplification_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7D2485758400FDD115 /* simplification_pass.cpp */; };
+		A9765F9B2485758600FDD115 /* dead_branch_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7E2485758400FDD115 /* dead_branch_elim_pass.cpp */; };
+		A9765F9C2485758600FDD115 /* dead_branch_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7E2485758400FDD115 /* dead_branch_elim_pass.cpp */; };
+		A9765F9D2485758600FDD115 /* flatten_decoration_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7F2485758400FDD115 /* flatten_decoration_pass.cpp */; };
+		A9765F9E2485758600FDD115 /* flatten_decoration_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C7F2485758400FDD115 /* flatten_decoration_pass.cpp */; };
+		A9765F9F2485758600FDD115 /* dead_insert_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C802485758400FDD115 /* dead_insert_elim_pass.h */; };
+		A9765FA02485758600FDD115 /* dead_insert_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C802485758400FDD115 /* dead_insert_elim_pass.h */; };
+		A9765FA12485758600FDD115 /* folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C812485758400FDD115 /* folding_rules.cpp */; };
+		A9765FA22485758600FDD115 /* folding_rules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C812485758400FDD115 /* folding_rules.cpp */; };
+		A9765FA32485758600FDD115 /* freeze_spec_constant_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C822485758400FDD115 /* freeze_spec_constant_value_pass.h */; };
+		A9765FA42485758600FDD115 /* freeze_spec_constant_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C822485758400FDD115 /* freeze_spec_constant_value_pass.h */; };
+		A9765FA52485758600FDD115 /* ir_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C832485758400FDD115 /* ir_context.cpp */; };
+		A9765FA62485758600FDD115 /* ir_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C832485758400FDD115 /* ir_context.cpp */; };
+		A9765FA72485758600FDD115 /* instrument_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C842485758400FDD115 /* instrument_pass.h */; };
+		A9765FA82485758600FDD115 /* instrument_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C842485758400FDD115 /* instrument_pass.h */; };
+		A9765FA92485758600FDD115 /* mem_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C852485758400FDD115 /* mem_pass.h */; };
+		A9765FAA2485758600FDD115 /* mem_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C852485758400FDD115 /* mem_pass.h */; };
+		A9765FAB2485758600FDD115 /* loop_descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C862485758400FDD115 /* loop_descriptor.cpp */; };
+		A9765FAC2485758600FDD115 /* loop_descriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C862485758400FDD115 /* loop_descriptor.cpp */; };
+		A9765FAD2485758600FDD115 /* eliminate_dead_members_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C872485758400FDD115 /* eliminate_dead_members_pass.h */; };
+		A9765FAE2485758600FDD115 /* eliminate_dead_members_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C872485758400FDD115 /* eliminate_dead_members_pass.h */; };
+		A9765FAF2485758600FDD115 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C882485758400FDD115 /* function.cpp */; };
+		A9765FB02485758600FDD115 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C882485758400FDD115 /* function.cpp */; };
+		A9765FB12485758600FDD115 /* instruction_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C892485758400FDD115 /* instruction_list.cpp */; };
+		A9765FB22485758600FDD115 /* instruction_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C892485758400FDD115 /* instruction_list.cpp */; };
+		A9765FB32485758600FDD115 /* composite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8A2485758400FDD115 /* composite.cpp */; };
+		A9765FB42485758600FDD115 /* composite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8A2485758400FDD115 /* composite.cpp */; };
+		A9765FB52485758600FDD115 /* convert_to_half_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8B2485758400FDD115 /* convert_to_half_pass.cpp */; };
+		A9765FB62485758600FDD115 /* convert_to_half_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8B2485758400FDD115 /* convert_to_half_pass.cpp */; };
+		A9765FB72485758600FDD115 /* process_lines_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8C2485758400FDD115 /* process_lines_pass.cpp */; };
+		A9765FB82485758600FDD115 /* process_lines_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C8C2485758400FDD115 /* process_lines_pass.cpp */; };
+		A9765FB92485758600FDD115 /* inline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8D2485758400FDD115 /* inline_pass.h */; };
+		A9765FBA2485758600FDD115 /* inline_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8D2485758400FDD115 /* inline_pass.h */; };
+		A9765FBB2485758600FDD115 /* loop_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8E2485758400FDD115 /* loop_dependence.h */; };
+		A9765FBC2485758600FDD115 /* loop_dependence.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8E2485758400FDD115 /* loop_dependence.h */; };
+		A9765FBD2485758600FDD115 /* value_number_table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8F2485758400FDD115 /* value_number_table.h */; };
+		A9765FBE2485758600FDD115 /* value_number_table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C8F2485758400FDD115 /* value_number_table.h */; };
+		A9765FBF2485758600FDD115 /* flatten_decoration_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C902485758400FDD115 /* flatten_decoration_pass.h */; };
+		A9765FC02485758600FDD115 /* flatten_decoration_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C902485758400FDD115 /* flatten_decoration_pass.h */; };
+		A9765FC12485758600FDD115 /* if_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C912485758400FDD115 /* if_conversion.cpp */; };
+		A9765FC22485758600FDD115 /* if_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C912485758400FDD115 /* if_conversion.cpp */; };
+		A9765FC32485758600FDD115 /* debug_info_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C922485758400FDD115 /* debug_info_manager.cpp */; };
+		A9765FC42485758600FDD115 /* debug_info_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C922485758400FDD115 /* debug_info_manager.cpp */; };
+		A9765FC52485758600FDD115 /* inline_exhaustive_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C932485758400FDD115 /* inline_exhaustive_pass.h */; };
+		A9765FC62485758600FDD115 /* inline_exhaustive_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C932485758400FDD115 /* inline_exhaustive_pass.h */; };
+		A9765FC72485758600FDD115 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C942485758400FDD115 /* constants.h */; };
+		A9765FC82485758600FDD115 /* constants.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C942485758400FDD115 /* constants.h */; };
+		A9765FC92485758600FDD115 /* eliminate_dead_members_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C952485758400FDD115 /* eliminate_dead_members_pass.cpp */; };
+		A9765FCA2485758600FDD115 /* eliminate_dead_members_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C952485758400FDD115 /* eliminate_dead_members_pass.cpp */; };
+		A9765FCB2485758600FDD115 /* strength_reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C962485758400FDD115 /* strength_reduction_pass.cpp */; };
+		A9765FCC2485758600FDD115 /* strength_reduction_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C962485758400FDD115 /* strength_reduction_pass.cpp */; };
+		A9765FCD2485758600FDD115 /* desc_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C972485758400FDD115 /* desc_sroa.cpp */; };
+		A9765FCE2485758600FDD115 /* desc_sroa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C972485758400FDD115 /* desc_sroa.cpp */; };
+		A9765FCF2485758600FDD115 /* block_merge_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C982485758400FDD115 /* block_merge_util.cpp */; };
+		A9765FD02485758600FDD115 /* block_merge_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C982485758400FDD115 /* block_merge_util.cpp */; };
+		A9765FD12485758600FDD115 /* upgrade_memory_model.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C992485758400FDD115 /* upgrade_memory_model.h */; };
+		A9765FD22485758600FDD115 /* upgrade_memory_model.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C992485758400FDD115 /* upgrade_memory_model.h */; };
+		A9765FD32485758600FDD115 /* copy_prop_arrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9A2485758400FDD115 /* copy_prop_arrays.cpp */; };
+		A9765FD42485758600FDD115 /* copy_prop_arrays.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9A2485758400FDD115 /* copy_prop_arrays.cpp */; };
+		A9765FD52485758600FDD115 /* pass_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9B2485758400FDD115 /* pass_manager.cpp */; };
+		A9765FD62485758600FDD115 /* pass_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9B2485758400FDD115 /* pass_manager.cpp */; };
+		A9765FD72485758600FDD115 /* inline_exhaustive_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9C2485758400FDD115 /* inline_exhaustive_pass.cpp */; };
+		A9765FD82485758600FDD115 /* inline_exhaustive_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9C2485758400FDD115 /* inline_exhaustive_pass.cpp */; };
+		A9765FD92485758600FDD115 /* loop_fission.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C9D2485758400FDD115 /* loop_fission.h */; };
+		A9765FDA2485758600FDD115 /* loop_fission.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C9D2485758400FDD115 /* loop_fission.h */; };
+		A9765FDB2485758600FDD115 /* workaround1209.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C9E2485758400FDD115 /* workaround1209.h */; };
+		A9765FDC2485758600FDD115 /* workaround1209.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765C9E2485758400FDD115 /* workaround1209.h */; };
+		A9765FDD2485758600FDD115 /* loop_fusion_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9F2485758400FDD115 /* loop_fusion_pass.cpp */; };
+		A9765FDE2485758600FDD115 /* loop_fusion_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765C9F2485758400FDD115 /* loop_fusion_pass.cpp */; };
+		A9765FDF2485758600FDD115 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA02485758400FDD115 /* log.h */; };
+		A9765FE02485758600FDD115 /* log.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA02485758400FDD115 /* log.h */; };
+		A9765FE12485758600FDD115 /* split_invalid_unreachable_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA12485758400FDD115 /* split_invalid_unreachable_pass.h */; };
+		A9765FE22485758600FDD115 /* split_invalid_unreachable_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA12485758400FDD115 /* split_invalid_unreachable_pass.h */; };
+		A9765FE32485758600FDD115 /* copy_prop_arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA22485758400FDD115 /* copy_prop_arrays.h */; };
+		A9765FE42485758600FDD115 /* copy_prop_arrays.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA22485758400FDD115 /* copy_prop_arrays.h */; };
+		A9765FE52485758600FDD115 /* eliminate_dead_constant_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA32485758400FDD115 /* eliminate_dead_constant_pass.h */; };
+		A9765FE62485758600FDD115 /* eliminate_dead_constant_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA32485758400FDD115 /* eliminate_dead_constant_pass.h */; };
+		A9765FE72485758600FDD115 /* dead_insert_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA42485758400FDD115 /* dead_insert_elim_pass.cpp */; };
+		A9765FE82485758600FDD115 /* dead_insert_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA42485758400FDD115 /* dead_insert_elim_pass.cpp */; };
+		A9765FE92485758600FDD115 /* ssa_rewrite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA52485758400FDD115 /* ssa_rewrite_pass.h */; };
+		A9765FEA2485758600FDD115 /* ssa_rewrite_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA52485758400FDD115 /* ssa_rewrite_pass.h */; };
+		A9765FEB2485758600FDD115 /* scalar_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA62485758400FDD115 /* scalar_analysis.cpp */; };
+		A9765FEC2485758600FDD115 /* scalar_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA62485758400FDD115 /* scalar_analysis.cpp */; };
+		A9765FED2485758600FDD115 /* dead_variable_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA72485758400FDD115 /* dead_variable_elimination.h */; };
+		A9765FEE2485758600FDD115 /* dead_variable_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA72485758400FDD115 /* dead_variable_elimination.h */; };
+		A9765FEF2485758600FDD115 /* block_merge_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA82485758400FDD115 /* block_merge_pass.cpp */; };
+		A9765FF02485758600FDD115 /* block_merge_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CA82485758400FDD115 /* block_merge_pass.cpp */; };
+		A9765FF12485758600FDD115 /* dominator_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA92485758400FDD115 /* dominator_analysis.h */; };
+		A9765FF22485758600FDD115 /* dominator_analysis.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CA92485758400FDD115 /* dominator_analysis.h */; };
+		A9765FF32485758600FDD115 /* pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAA2485758400FDD115 /* pass.h */; };
+		A9765FF42485758600FDD115 /* pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAA2485758400FDD115 /* pass.h */; };
+		A9765FF52485758600FDD115 /* folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAB2485758400FDD115 /* folding_rules.h */; };
+		A9765FF62485758600FDD115 /* folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAB2485758400FDD115 /* folding_rules.h */; };
+		A9765FF72485758600FDD115 /* eliminate_dead_functions_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAC2485758400FDD115 /* eliminate_dead_functions_pass.h */; };
+		A9765FF82485758600FDD115 /* eliminate_dead_functions_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAC2485758400FDD115 /* eliminate_dead_functions_pass.h */; };
+		A9765FF92485758600FDD115 /* eliminate_dead_functions_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAD2485758400FDD115 /* eliminate_dead_functions_util.h */; };
+		A9765FFA2485758600FDD115 /* eliminate_dead_functions_util.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAD2485758400FDD115 /* eliminate_dead_functions_util.h */; };
+		A9765FFB2485758600FDD115 /* fold.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAE2485758400FDD115 /* fold.h */; };
+		A9765FFC2485758600FDD115 /* fold.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CAE2485758400FDD115 /* fold.h */; };
+		A9765FFD2485758600FDD115 /* local_single_store_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CAF2485758400FDD115 /* local_single_store_elim_pass.cpp */; };
+		A9765FFE2485758600FDD115 /* local_single_store_elim_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CAF2485758400FDD115 /* local_single_store_elim_pass.cpp */; };
+		A9765FFF2485758600FDD115 /* dead_branch_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB02485758400FDD115 /* dead_branch_elim_pass.h */; };
+		A97660002485758600FDD115 /* dead_branch_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB02485758400FDD115 /* dead_branch_elim_pass.h */; };
+		A97660012485758600FDD115 /* private_to_local_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB12485758400FDD115 /* private_to_local_pass.cpp */; };
+		A97660022485758600FDD115 /* private_to_local_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB12485758400FDD115 /* private_to_local_pass.cpp */; };
+		A97660032485758600FDD115 /* scalar_analysis_nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB22485758400FDD115 /* scalar_analysis_nodes.h */; };
+		A97660042485758600FDD115 /* scalar_analysis_nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB22485758400FDD115 /* scalar_analysis_nodes.h */; };
+		A97660052485758600FDD115 /* propagator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB32485758400FDD115 /* propagator.cpp */; };
+		A97660062485758600FDD115 /* propagator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB32485758400FDD115 /* propagator.cpp */; };
+		A97660072485758600FDD115 /* fix_storage_class.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB42485758400FDD115 /* fix_storage_class.h */; };
+		A97660082485758600FDD115 /* fix_storage_class.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB42485758400FDD115 /* fix_storage_class.h */; };
+		A97660092485758600FDD115 /* loop_dependence_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB52485758400FDD115 /* loop_dependence_helpers.cpp */; };
+		A976600A2485758600FDD115 /* loop_dependence_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB52485758400FDD115 /* loop_dependence_helpers.cpp */; };
+		A976600B2485758600FDD115 /* set_spec_constant_default_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB62485758400FDD115 /* set_spec_constant_default_value_pass.cpp */; };
+		A976600C2485758600FDD115 /* set_spec_constant_default_value_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB62485758400FDD115 /* set_spec_constant_default_value_pass.cpp */; };
+		A976600D2485758600FDD115 /* passes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB72485758400FDD115 /* passes.h */; };
+		A976600E2485758600FDD115 /* passes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CB72485758400FDD115 /* passes.h */; };
+		A976600F2485758600FDD115 /* fold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB82485758400FDD115 /* fold.cpp */; };
+		A97660102485758600FDD115 /* fold.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB82485758400FDD115 /* fold.cpp */; };
+		A97660112485758600FDD115 /* amd_ext_to_khr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB92485758400FDD115 /* amd_ext_to_khr.cpp */; };
+		A97660122485758600FDD115 /* amd_ext_to_khr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CB92485758400FDD115 /* amd_ext_to_khr.cpp */; };
+		A97660132485758600FDD115 /* strip_reflect_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBA2485758400FDD115 /* strip_reflect_info_pass.h */; };
+		A97660142485758600FDD115 /* strip_reflect_info_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBA2485758400FDD115 /* strip_reflect_info_pass.h */; };
+		A97660152485758600FDD115 /* scalar_replacement_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CBB2485758400FDD115 /* scalar_replacement_pass.cpp */; };
+		A97660162485758600FDD115 /* scalar_replacement_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CBB2485758400FDD115 /* scalar_replacement_pass.cpp */; };
+		A97660172485758600FDD115 /* simplification_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBC2485758400FDD115 /* simplification_pass.h */; };
+		A97660182485758600FDD115 /* simplification_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBC2485758400FDD115 /* simplification_pass.h */; };
+		A97660192485758600FDD115 /* remove_duplicates_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBD2485758400FDD115 /* remove_duplicates_pass.h */; };
+		A976601A2485758600FDD115 /* remove_duplicates_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBD2485758400FDD115 /* remove_duplicates_pass.h */; };
+		A976601B2485758600FDD115 /* redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CBE2485758400FDD115 /* redundancy_elimination.cpp */; };
+		A976601C2485758600FDD115 /* redundancy_elimination.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CBE2485758400FDD115 /* redundancy_elimination.cpp */; };
+		A976601D2485758600FDD115 /* reflect.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBF2485758400FDD115 /* reflect.h */; };
+		A976601E2485758600FDD115 /* reflect.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CBF2485758400FDD115 /* reflect.h */; };
+		A976601F2485758600FDD115 /* workaround1209.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC02485758400FDD115 /* workaround1209.cpp */; };
+		A97660202485758600FDD115 /* workaround1209.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC02485758400FDD115 /* workaround1209.cpp */; };
+		A97660212485758600FDD115 /* null_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC12485758400FDD115 /* null_pass.h */; };
+		A97660222485758600FDD115 /* null_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC12485758400FDD115 /* null_pass.h */; };
+		A97660232485758600FDD115 /* relax_float_ops_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC22485758400FDD115 /* relax_float_ops_pass.cpp */; };
+		A97660242485758600FDD115 /* relax_float_ops_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC22485758400FDD115 /* relax_float_ops_pass.cpp */; };
+		A97660252485758600FDD115 /* const_folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC32485758400FDD115 /* const_folding_rules.h */; };
+		A97660262485758600FDD115 /* const_folding_rules.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC32485758400FDD115 /* const_folding_rules.h */; };
+		A97660272485758600FDD115 /* scalar_replacement_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC42485758400FDD115 /* scalar_replacement_pass.h */; };
+		A97660282485758600FDD115 /* scalar_replacement_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC42485758400FDD115 /* scalar_replacement_pass.h */; };
+		A97660292485758600FDD115 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC52485758400FDD115 /* instruction.cpp */; };
+		A976602A2485758600FDD115 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC52485758400FDD115 /* instruction.cpp */; };
+		A976602B2485758600FDD115 /* pch_source_opt.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC62485758400FDD115 /* pch_source_opt.h */; };
+		A976602C2485758600FDD115 /* pch_source_opt.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC62485758400FDD115 /* pch_source_opt.h */; };
+		A976602D2485758600FDD115 /* reduce_load_size.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC72485758400FDD115 /* reduce_load_size.cpp */; };
+		A976602E2485758600FDD115 /* reduce_load_size.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC72485758400FDD115 /* reduce_load_size.cpp */; };
+		A976602F2485758600FDD115 /* redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC82485758400FDD115 /* redundancy_elimination.h */; };
+		A97660302485758600FDD115 /* redundancy_elimination.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CC82485758400FDD115 /* redundancy_elimination.h */; };
+		A97660312485758600FDD115 /* fix_storage_class.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC92485758400FDD115 /* fix_storage_class.cpp */; };
+		A97660322485758600FDD115 /* fix_storage_class.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CC92485758400FDD115 /* fix_storage_class.cpp */; };
+		A97660332485758600FDD115 /* value_number_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCA2485758400FDD115 /* value_number_table.cpp */; };
+		A97660342485758600FDD115 /* value_number_table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCA2485758400FDD115 /* value_number_table.cpp */; };
+		A97660352485758600FDD115 /* inline_opaque_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCB2485758400FDD115 /* inline_opaque_pass.cpp */; };
+		A97660362485758600FDD115 /* inline_opaque_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCB2485758400FDD115 /* inline_opaque_pass.cpp */; };
+		A97660372485758600FDD115 /* replace_invalid_opc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCC2485758400FDD115 /* replace_invalid_opc.cpp */; };
+		A97660382485758600FDD115 /* replace_invalid_opc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCC2485758400FDD115 /* replace_invalid_opc.cpp */; };
+		A97660392485758600FDD115 /* loop_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CCD2485758400FDD115 /* loop_utils.h */; };
+		A976603A2485758600FDD115 /* loop_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CCD2485758400FDD115 /* loop_utils.h */; };
+		A976603B2485758600FDD115 /* module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CCE2485758400FDD115 /* module.h */; };
+		A976603C2485758600FDD115 /* module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CCE2485758400FDD115 /* module.h */; };
+		A976603D2485758600FDD115 /* dominator_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCF2485758400FDD115 /* dominator_analysis.cpp */; };
+		A976603E2485758600FDD115 /* dominator_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CCF2485758400FDD115 /* dominator_analysis.cpp */; };
+		A976603F2485758600FDD115 /* decompose_initialized_variables_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CD02485758400FDD115 /* decompose_initialized_variables_pass.cpp */; };
+		A97660402485758600FDD115 /* decompose_initialized_variables_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CD02485758400FDD115 /* decompose_initialized_variables_pass.cpp */; };
+		A97660412485758600FDD115 /* ir_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD12485758400FDD115 /* ir_builder.h */; };
+		A97660422485758600FDD115 /* ir_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD12485758400FDD115 /* ir_builder.h */; };
+		A97660432485758600FDD115 /* loop_unswitch_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD22485758400FDD115 /* loop_unswitch_pass.h */; };
+		A97660442485758600FDD115 /* loop_unswitch_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD22485758400FDD115 /* loop_unswitch_pass.h */; };
+		A97660452485758600FDD115 /* cfg.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD32485758400FDD115 /* cfg.h */; };
+		A97660462485758600FDD115 /* cfg.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD32485758400FDD115 /* cfg.h */; };
+		A97660472485758600FDD115 /* code_sink.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD42485758400FDD115 /* code_sink.h */; };
+		A97660482485758600FDD115 /* code_sink.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD42485758400FDD115 /* code_sink.h */; };
+		A97660492485758600FDD115 /* loop_descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD52485758400FDD115 /* loop_descriptor.h */; };
+		A976604A2485758600FDD115 /* loop_descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD52485758400FDD115 /* loop_descriptor.h */; };
+		A976604B2485758600FDD115 /* generate_webgpu_initializers_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD62485758400FDD115 /* generate_webgpu_initializers_pass.h */; };
+		A976604C2485758600FDD115 /* generate_webgpu_initializers_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD62485758400FDD115 /* generate_webgpu_initializers_pass.h */; };
+		A976604D2485758600FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD72485758400FDD115 /* instruction.h */; };
+		A976604E2485758600FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD72485758400FDD115 /* instruction.h */; };
+		A976604F2485758600FDD115 /* aggressive_dead_code_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD82485758400FDD115 /* aggressive_dead_code_elim_pass.h */; };
+		A97660502485758600FDD115 /* aggressive_dead_code_elim_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CD82485758400FDD115 /* aggressive_dead_code_elim_pass.h */; };
+		A97660512485758600FDD115 /* struct_cfg_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CD92485758400FDD115 /* struct_cfg_analysis.cpp */; };
+		A97660522485758600FDD115 /* struct_cfg_analysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CD92485758400FDD115 /* struct_cfg_analysis.cpp */; };
+		A97660532485758600FDD115 /* vector_dce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDA2485758400FDD115 /* vector_dce.h */; };
+		A97660542485758600FDD115 /* vector_dce.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDA2485758400FDD115 /* vector_dce.h */; };
+		A97660552485758600FDD115 /* combine_access_chains.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDB2485758400FDD115 /* combine_access_chains.h */; };
+		A97660562485758600FDD115 /* combine_access_chains.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDB2485758400FDD115 /* combine_access_chains.h */; };
+		A97660572485758600FDD115 /* pass_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDC2485758400FDD115 /* pass_manager.h */; };
+		A97660582485758600FDD115 /* pass_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDC2485758400FDD115 /* pass_manager.h */; };
+		A97660592485758600FDD115 /* local_access_chain_convert_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CDD2485758400FDD115 /* local_access_chain_convert_pass.cpp */; };
+		A976605A2485758600FDD115 /* local_access_chain_convert_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CDD2485758400FDD115 /* local_access_chain_convert_pass.cpp */; };
+		A976605B2485758600FDD115 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CDE2485758400FDD115 /* basic_block.cpp */; };
+		A976605C2485758600FDD115 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CDE2485758400FDD115 /* basic_block.cpp */; };
+		A976605D2485758600FDD115 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDF2485758400FDD115 /* iterator.h */; };
+		A976605E2485758600FDD115 /* iterator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CDF2485758400FDD115 /* iterator.h */; };
+		A976605F2485758600FDD115 /* licm_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE02485758400FDD115 /* licm_pass.h */; };
+		A97660602485758600FDD115 /* licm_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE02485758400FDD115 /* licm_pass.h */; };
+		A97660612485758600FDD115 /* build_module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE12485758400FDD115 /* build_module.h */; };
+		A97660622485758600FDD115 /* build_module.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE12485758400FDD115 /* build_module.h */; };
+		A97660632485758600FDD115 /* ccp_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE22485758400FDD115 /* ccp_pass.h */; };
+		A97660642485758600FDD115 /* ccp_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE22485758400FDD115 /* ccp_pass.h */; };
+		A97660652485758600FDD115 /* graphics_robust_access_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE32485758400FDD115 /* graphics_robust_access_pass.cpp */; };
+		A97660662485758600FDD115 /* graphics_robust_access_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE32485758400FDD115 /* graphics_robust_access_pass.cpp */; };
+		A97660672485758600FDD115 /* decompose_initialized_variables_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE42485758400FDD115 /* decompose_initialized_variables_pass.h */; };
+		A97660682485758600FDD115 /* decompose_initialized_variables_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE42485758400FDD115 /* decompose_initialized_variables_pass.h */; };
+		A97660692485758600FDD115 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE52485758400FDD115 /* function.h */; };
+		A976606A2485758600FDD115 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE52485758400FDD115 /* function.h */; };
+		A976606B2485758600FDD115 /* loop_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE62485758400FDD115 /* loop_fusion.cpp */; };
+		A976606C2485758600FDD115 /* loop_fusion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE62485758400FDD115 /* loop_fusion.cpp */; };
+		A976606D2485758600FDD115 /* upgrade_memory_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE72485758400FDD115 /* upgrade_memory_model.cpp */; };
+		A976606E2485758600FDD115 /* upgrade_memory_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CE72485758400FDD115 /* upgrade_memory_model.cpp */; };
+		A976606F2485758600FDD115 /* feature_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE82485758400FDD115 /* feature_manager.h */; };
+		A97660702485758600FDD115 /* feature_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE82485758400FDD115 /* feature_manager.h */; };
+		A97660712485758600FDD115 /* inst_bindless_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE92485758400FDD115 /* inst_bindless_check_pass.h */; };
+		A97660722485758600FDD115 /* inst_bindless_check_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CE92485758400FDD115 /* inst_bindless_check_pass.h */; };
+		A97660732485758600FDD115 /* scalar_analysis_simplification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CEA2485758400FDD115 /* scalar_analysis_simplification.cpp */; };
+		A97660742485758600FDD115 /* scalar_analysis_simplification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CEA2485758400FDD115 /* scalar_analysis_simplification.cpp */; };
+		A97660752485758600FDD115 /* set_spec_constant_default_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEB2485758400FDD115 /* set_spec_constant_default_value_pass.h */; };
+		A97660762485758600FDD115 /* set_spec_constant_default_value_pass.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEB2485758400FDD115 /* set_spec_constant_default_value_pass.h */; };
+		A97660772485758600FDD115 /* dominator_tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEC2485758400FDD115 /* dominator_tree.h */; };
+		A97660782485758600FDD115 /* dominator_tree.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEC2485758400FDD115 /* dominator_tree.h */; };
+		A97660792485758600FDD115 /* legalize_vector_shuffle_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CED2485758400FDD115 /* legalize_vector_shuffle_pass.cpp */; };
+		A976607A2485758600FDD115 /* legalize_vector_shuffle_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CED2485758400FDD115 /* legalize_vector_shuffle_pass.cpp */; };
+		A976607B2485758600FDD115 /* type_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEE2485758400FDD115 /* type_manager.h */; };
+		A976607C2485758600FDD115 /* type_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CEE2485758400FDD115 /* type_manager.h */; };
+		A976607D2485758600FDD115 /* compact_ids_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CEF2485758400FDD115 /* compact_ids_pass.cpp */; };
+		A976607E2485758600FDD115 /* compact_ids_pass.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CEF2485758400FDD115 /* compact_ids_pass.cpp */; };
+		A976607F2485758600FDD115 /* loop_peeling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CF02485758400FDD115 /* loop_peeling.cpp */; };
+		A97660802485758600FDD115 /* loop_peeling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765CF02485758400FDD115 /* loop_peeling.cpp */; };
+		A97660812485758600FDD115 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CF12485758400FDD115 /* table.h */; };
+		A97660822485758600FDD115 /* table.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765CF12485758400FDD115 /* table.h */; };
+		A97661FD2485758700FDD115 /* ext_inst.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB22485758500FDD115 /* ext_inst.h */; };
+		A97661FE2485758700FDD115 /* ext_inst.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB22485758500FDD115 /* ext_inst.h */; };
+		A97661FF2485758700FDD115 /* diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB32485758500FDD115 /* diagnostic.cpp */; };
+		A97662002485758700FDD115 /* diagnostic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB32485758500FDD115 /* diagnostic.cpp */; };
+		A97662012485758700FDD115 /* latest_version_spirv_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB42485758500FDD115 /* latest_version_spirv_header.h */; };
+		A97662022485758700FDD115 /* latest_version_spirv_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB42485758500FDD115 /* latest_version_spirv_header.h */; };
+		A97662032485758700FDD115 /* libspirv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB52485758500FDD115 /* libspirv.cpp */; };
+		A97662042485758700FDD115 /* libspirv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB52485758500FDD115 /* libspirv.cpp */; };
+		A97662052485758700FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB62485758500FDD115 /* instruction.h */; };
+		A97662062485758700FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB62485758500FDD115 /* instruction.h */; };
+		A97662072485758700FDD115 /* spirv_optimizer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB72485758500FDD115 /* spirv_optimizer_options.h */; };
+		A97662082485758700FDD115 /* spirv_optimizer_options.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB72485758500FDD115 /* spirv_optimizer_options.h */; };
+		A97662092485758700FDD115 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB82485758500FDD115 /* opcode.h */; };
+		A976620A2485758700FDD115 /* opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DB82485758500FDD115 /* opcode.h */; };
+		A976620B2485758700FDD115 /* operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB92485758500FDD115 /* operand.cpp */; };
+		A976620C2485758700FDD115 /* operand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DB92485758500FDD115 /* operand.cpp */; };
+		A976620D2485758700FDD115 /* latest_version_glsl_std_450_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBA2485758500FDD115 /* latest_version_glsl_std_450_header.h */; };
+		A976620E2485758700FDD115 /* latest_version_glsl_std_450_header.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBA2485758500FDD115 /* latest_version_glsl_std_450_header.h */; };
+		A976620F2485758700FDD115 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBB2485758500FDD115 /* extensions.h */; };
+		A97662102485758700FDD115 /* extensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBB2485758500FDD115 /* extensions.h */; };
+		A97662112485758700FDD115 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DBC2485758500FDD115 /* disassemble.cpp */; };
+		A97662122485758700FDD115 /* disassemble.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DBC2485758500FDD115 /* disassemble.cpp */; };
+		A97662132485758700FDD115 /* binary.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBD2485758500FDD115 /* binary.h */; };
+		A97662142485758700FDD115 /* binary.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DBD2485758500FDD115 /* binary.h */; };
+		A97662152485758700FDD115 /* text_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DBE2485758500FDD115 /* text_handler.cpp */; };
+		A97662162485758700FDD115 /* text_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DBE2485758500FDD115 /* text_handler.cpp */; };
+		A97662172485758700FDD115 /* validate_annotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC02485758500FDD115 /* validate_annotation.cpp */; };
+		A97662182485758700FDD115 /* validate_annotation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC02485758500FDD115 /* validate_annotation.cpp */; };
+		A97662192485758700FDD115 /* validate_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC12485758500FDD115 /* validate_misc.cpp */; };
+		A976621A2485758700FDD115 /* validate_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC12485758500FDD115 /* validate_misc.cpp */; };
+		A976621B2485758700FDD115 /* validate_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC22485758500FDD115 /* validate_cfg.cpp */; };
+		A976621C2485758700FDD115 /* validate_cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC22485758500FDD115 /* validate_cfg.cpp */; };
+		A976621D2485758700FDD115 /* validate_capability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC32485758500FDD115 /* validate_capability.cpp */; };
+		A976621E2485758700FDD115 /* validate_capability.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC32485758500FDD115 /* validate_capability.cpp */; };
+		A976621F2485758700FDD115 /* construct.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DC42485758500FDD115 /* construct.h */; };
+		A97662202485758700FDD115 /* construct.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DC42485758500FDD115 /* construct.h */; };
+		A97662212485758700FDD115 /* validate_barriers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC52485758500FDD115 /* validate_barriers.cpp */; };
+		A97662222485758700FDD115 /* validate_barriers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC52485758500FDD115 /* validate_barriers.cpp */; };
+		A97662232485758700FDD115 /* validate_non_uniform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC62485758500FDD115 /* validate_non_uniform.cpp */; };
+		A97662242485758700FDD115 /* validate_non_uniform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC62485758500FDD115 /* validate_non_uniform.cpp */; };
+		A97662252485758700FDD115 /* validate_scopes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC72485758500FDD115 /* validate_scopes.cpp */; };
+		A97662262485758700FDD115 /* validate_scopes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC72485758500FDD115 /* validate_scopes.cpp */; };
+		A97662272485758700FDD115 /* validate_atomics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC82485758500FDD115 /* validate_atomics.cpp */; };
+		A97662282485758700FDD115 /* validate_atomics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DC82485758500FDD115 /* validate_atomics.cpp */; };
+		A97662292485758700FDD115 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DC92485758500FDD115 /* basic_block.h */; };
+		A976622A2485758700FDD115 /* basic_block.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DC92485758500FDD115 /* basic_block.h */; };
+		A976622B2485758700FDD115 /* validate_instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCA2485758500FDD115 /* validate_instruction.cpp */; };
+		A976622C2485758700FDD115 /* validate_instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCA2485758500FDD115 /* validate_instruction.cpp */; };
+		A976622D2485758700FDD115 /* validate_decorations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCB2485758500FDD115 /* validate_decorations.cpp */; };
+		A976622E2485758700FDD115 /* validate_decorations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCB2485758500FDD115 /* validate_decorations.cpp */; };
+		A976622F2485758700FDD115 /* validate_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCC2485758500FDD115 /* validate_debug.cpp */; };
+		A97662302485758700FDD115 /* validate_debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCC2485758500FDD115 /* validate_debug.cpp */; };
+		A97662312485758700FDD115 /* validate_builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCD2485758500FDD115 /* validate_builtins.cpp */; };
+		A97662322485758700FDD115 /* validate_builtins.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCD2485758500FDD115 /* validate_builtins.cpp */; };
+		A97662332485758700FDD115 /* validate_interfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCE2485758500FDD115 /* validate_interfaces.cpp */; };
+		A97662342485758700FDD115 /* validate_interfaces.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCE2485758500FDD115 /* validate_interfaces.cpp */; };
+		A97662352485758700FDD115 /* validate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCF2485758500FDD115 /* validate.cpp */; };
+		A97662362485758700FDD115 /* validate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DCF2485758500FDD115 /* validate.cpp */; };
+		A97662372485758700FDD115 /* validation_state.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DD02485758500FDD115 /* validation_state.h */; };
+		A97662382485758700FDD115 /* validation_state.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DD02485758500FDD115 /* validation_state.h */; };
+		A97662392485758700FDD115 /* validate_constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD12485758500FDD115 /* validate_constants.cpp */; };
+		A976623A2485758700FDD115 /* validate_constants.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD12485758500FDD115 /* validate_constants.cpp */; };
+		A976623B2485758700FDD115 /* validate_bitwise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD22485758500FDD115 /* validate_bitwise.cpp */; };
+		A976623C2485758700FDD115 /* validate_bitwise.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD22485758500FDD115 /* validate_bitwise.cpp */; };
+		A976623D2485758700FDD115 /* validate_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD32485758500FDD115 /* validate_extensions.cpp */; };
+		A976623E2485758700FDD115 /* validate_extensions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD32485758500FDD115 /* validate_extensions.cpp */; };
+		A976623F2485758700FDD115 /* construct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD42485758500FDD115 /* construct.cpp */; };
+		A97662402485758700FDD115 /* construct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD42485758500FDD115 /* construct.cpp */; };
+		A97662412485758700FDD115 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD52485758500FDD115 /* function.cpp */; };
+		A97662422485758700FDD115 /* function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD52485758500FDD115 /* function.cpp */; };
+		A97662432485758700FDD115 /* validate.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DD62485758500FDD115 /* validate.h */; };
+		A97662442485758700FDD115 /* validate.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DD62485758500FDD115 /* validate.h */; };
+		A97662452485758700FDD115 /* validate_adjacency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD72485758500FDD115 /* validate_adjacency.cpp */; };
+		A97662462485758700FDD115 /* validate_adjacency.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD72485758500FDD115 /* validate_adjacency.cpp */; };
+		A97662472485758700FDD115 /* validate_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD82485758500FDD115 /* validate_conversion.cpp */; };
+		A97662482485758700FDD115 /* validate_conversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD82485758500FDD115 /* validate_conversion.cpp */; };
+		A97662492485758700FDD115 /* validate_small_type_uses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD92485758500FDD115 /* validate_small_type_uses.cpp */; };
+		A976624A2485758700FDD115 /* validate_small_type_uses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DD92485758500FDD115 /* validate_small_type_uses.cpp */; };
+		A976624B2485758700FDD115 /* validate_scopes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DDA2485758500FDD115 /* validate_scopes.h */; };
+		A976624C2485758700FDD115 /* validate_scopes.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DDA2485758500FDD115 /* validate_scopes.h */; };
+		A976624D2485758700FDD115 /* validate_id.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDB2485758500FDD115 /* validate_id.cpp */; };
+		A976624E2485758700FDD115 /* validate_id.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDB2485758500FDD115 /* validate_id.cpp */; };
+		A976624F2485758700FDD115 /* validate_memory_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DDC2485758500FDD115 /* validate_memory_semantics.h */; };
+		A97662502485758700FDD115 /* validate_memory_semantics.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DDC2485758500FDD115 /* validate_memory_semantics.h */; };
+		A97662512485758700FDD115 /* validate_arithmetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDD2485758500FDD115 /* validate_arithmetics.cpp */; };
+		A97662522485758700FDD115 /* validate_arithmetics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDD2485758500FDD115 /* validate_arithmetics.cpp */; };
+		A97662532485758700FDD115 /* validate_mode_setting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDE2485758500FDD115 /* validate_mode_setting.cpp */; };
+		A97662542485758700FDD115 /* validate_mode_setting.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDE2485758500FDD115 /* validate_mode_setting.cpp */; };
+		A97662552485758700FDD115 /* validate_memory_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDF2485758500FDD115 /* validate_memory_semantics.cpp */; };
+		A97662562485758700FDD115 /* validate_memory_semantics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DDF2485758500FDD115 /* validate_memory_semantics.cpp */; };
+		A97662572485758700FDD115 /* validate_logicals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE02485758500FDD115 /* validate_logicals.cpp */; };
+		A97662582485758700FDD115 /* validate_logicals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE02485758500FDD115 /* validate_logicals.cpp */; };
+		A97662592485758700FDD115 /* validate_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE12485758500FDD115 /* validate_derivatives.cpp */; };
+		A976625A2485758700FDD115 /* validate_derivatives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE12485758500FDD115 /* validate_derivatives.cpp */; };
+		A976625B2485758700FDD115 /* validate_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE22485758500FDD115 /* validate_memory.cpp */; };
+		A976625C2485758700FDD115 /* validate_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE22485758500FDD115 /* validate_memory.cpp */; };
+		A976625D2485758700FDD115 /* validate_image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE32485758500FDD115 /* validate_image.cpp */; };
+		A976625E2485758700FDD115 /* validate_image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE32485758500FDD115 /* validate_image.cpp */; };
+		A976625F2485758700FDD115 /* validate_literals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE42485758500FDD115 /* validate_literals.cpp */; };
+		A97662602485758700FDD115 /* validate_literals.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE42485758500FDD115 /* validate_literals.cpp */; };
+		A97662612485758700FDD115 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE52485758500FDD115 /* instruction.cpp */; };
+		A97662622485758700FDD115 /* instruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE52485758500FDD115 /* instruction.cpp */; };
+		A97662632485758700FDD115 /* validate_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE62485758500FDD115 /* validate_type.cpp */; };
+		A97662642485758700FDD115 /* validate_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE62485758500FDD115 /* validate_type.cpp */; };
+		A97662652485758700FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DE72485758500FDD115 /* instruction.h */; };
+		A97662662485758700FDD115 /* instruction.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DE72485758500FDD115 /* instruction.h */; };
+		A97662672485758700FDD115 /* validate_execution_limitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE82485758500FDD115 /* validate_execution_limitations.cpp */; };
+		A97662682485758700FDD115 /* validate_execution_limitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE82485758500FDD115 /* validate_execution_limitations.cpp */; };
+		A97662692485758700FDD115 /* validate_layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE92485758500FDD115 /* validate_layout.cpp */; };
+		A976626A2485758700FDD115 /* validate_layout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DE92485758500FDD115 /* validate_layout.cpp */; };
+		A976626B2485758700FDD115 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEA2485758500FDD115 /* basic_block.cpp */; };
+		A976626C2485758700FDD115 /* basic_block.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEA2485758500FDD115 /* basic_block.cpp */; };
+		A976626D2485758700FDD115 /* validate_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEB2485758500FDD115 /* validate_function.cpp */; };
+		A976626E2485758700FDD115 /* validate_function.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEB2485758500FDD115 /* validate_function.cpp */; };
+		A976626F2485758700FDD115 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DEC2485758500FDD115 /* function.h */; };
+		A97662702485758700FDD115 /* function.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DEC2485758500FDD115 /* function.h */; };
+		A97662712485758700FDD115 /* validate_composites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DED2485758500FDD115 /* validate_composites.cpp */; };
+		A97662722485758700FDD115 /* validate_composites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DED2485758500FDD115 /* validate_composites.cpp */; };
+		A97662732485758700FDD115 /* validation_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEE2485758500FDD115 /* validation_state.cpp */; };
+		A97662742485758700FDD115 /* validation_state.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEE2485758500FDD115 /* validation_state.cpp */; };
+		A97662752485758700FDD115 /* validate_primitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEF2485758500FDD115 /* validate_primitives.cpp */; };
+		A97662762485758700FDD115 /* validate_primitives.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9765DEF2485758500FDD115 /* validate_primitives.cpp */; };
+		A97662772485758700FDD115 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DF02485758500FDD115 /* decoration.h */; };
+		A97662782485758700FDD115 /* decoration.h in Headers */ = {isa = PBXBuildFile; fileRef = A9765DF02485758500FDD115 /* decoration.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -1101,401 +1113,6 @@
 		A90FD89F21CC4EAB00B92BB2 /* libSPIRVCross.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVCross.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		A90FD9E421CC4EB900B92BB2 /* libSPIRVCross.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSPIRVCross.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		A91BF011235F9C510039B7DE /* gen_spirv_cross_rev_hdr.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = gen_spirv_cross_rev_hdr.sh; sourceTree = "<group>"; };
-		A941583F243667F600566F16 /* spirv_target_env.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_target_env.cpp; sourceTree = "<group>"; };
-		A9415840243667F600566F16 /* extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json"; sourceTree = "<group>"; };
-		A9415841243667F600566F16 /* spirv_fuzzer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_fuzzer_options.h; sourceTree = "<group>"; };
-		A9415842243667F600566F16 /* assembly_grammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assembly_grammar.h; sourceTree = "<group>"; };
-		A9415843243667F600566F16 /* enum_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enum_set.h; sourceTree = "<group>"; };
-		A9415844243667F600566F16 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
-		A9415845243667F600566F16 /* extinst.spv-amd-shader-ballot.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-ballot.grammar.json"; sourceTree = "<group>"; };
-		A9415846243667F600566F16 /* text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text.cpp; sourceTree = "<group>"; };
-		A9415847243667F600566F16 /* assembly_grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assembly_grammar.cpp; sourceTree = "<group>"; };
-		A9415848243667F600566F16 /* text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text.h; sourceTree = "<group>"; };
-		A9415849243667F600566F16 /* extensions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extensions.cpp; sourceTree = "<group>"; };
-		A941584A243667F600566F16 /* pch_source.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source.cpp; sourceTree = "<group>"; };
-		A941584C243667F600566F16 /* parse_number.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse_number.h; sourceTree = "<group>"; };
-		A941584D243667F600566F16 /* ilist_node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilist_node.h; sourceTree = "<group>"; };
-		A941584E243667F600566F16 /* make_unique.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = make_unique.h; sourceTree = "<group>"; };
-		A941584F243667F600566F16 /* string_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_utils.h; sourceTree = "<group>"; };
-		A9415850243667F600566F16 /* small_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = small_vector.h; sourceTree = "<group>"; };
-		A9415851243667F600566F16 /* timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timer.cpp; sourceTree = "<group>"; };
-		A9415852243667F600566F16 /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
-		A9415853243667F600566F16 /* string_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_utils.cpp; sourceTree = "<group>"; };
-		A9415854243667F600566F16 /* bit_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_vector.h; sourceTree = "<group>"; };
-		A9415855243667F600566F16 /* bitutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitutils.h; sourceTree = "<group>"; };
-		A9415856243667F600566F16 /* hex_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hex_float.h; sourceTree = "<group>"; };
-		A9415857243667F600566F16 /* parse_number.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parse_number.cpp; sourceTree = "<group>"; };
-		A9415858243667F600566F16 /* bit_vector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bit_vector.cpp; sourceTree = "<group>"; };
-		A9415859243667F600566F16 /* ilist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilist.h; sourceTree = "<group>"; };
-		A941585A243667F600566F16 /* spirv_target_env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_target_env.h; sourceTree = "<group>"; };
-		A941585B243667F600566F16 /* table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = table.cpp; sourceTree = "<group>"; };
-		A941585C243667F600566F16 /* extinst.opencl.debuginfo.100.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = extinst.opencl.debuginfo.100.grammar.json; sourceTree = "<group>"; };
-		A941585E243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_undef_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A941585F243667F600566F16 /* remove_selection_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_selection_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415860243667F600566F16 /* remove_block_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_block_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415861243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_dominating_id_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415862243667F600566F16 /* reduction_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_pass.cpp; sourceTree = "<group>"; };
-		A9415863243667F600566F16 /* operand_to_const_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_const_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415864243667F600566F16 /* operand_to_const_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_const_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415865243667F600566F16 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
-		A9415866243667F600566F16 /* reduction_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_util.cpp; sourceTree = "<group>"; };
-		A9415867243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = structured_loop_to_selection_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415868243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_conditional_branch_to_branch_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415869243667F600566F16 /* remove_function_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_function_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A941586A243667F600566F16 /* remove_instruction_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_instruction_reduction_opportunity.h; sourceTree = "<group>"; };
-		A941586B243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conditional_branch_to_simple_conditional_branch_reduction_opportunity.h; sourceTree = "<group>"; };
-		A941586C243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_conditional_branch_to_branch_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A941586D243667F600566F16 /* remove_function_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_function_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A941586E243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_conditional_branch_to_branch_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A941586F243667F600566F16 /* remove_selection_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_selection_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415870243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415871243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_conditional_branch_to_branch_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415872243667F600566F16 /* merge_blocks_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_blocks_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415873243667F600566F16 /* change_operand_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = change_operand_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415874243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structured_loop_to_selection_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415875243667F600566F16 /* remove_function_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_function_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415876243667F600566F16 /* change_operand_to_undef_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = change_operand_to_undef_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415877243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_unreferenced_instruction_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415878243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structured_loop_to_selection_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415879243667F600566F16 /* remove_selection_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_selection_reduction_opportunity.h; sourceTree = "<group>"; };
-		A941587A243667F600566F16 /* remove_instruction_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_instruction_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A941587B243667F600566F16 /* remove_selection_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_selection_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A941587C243667F600566F16 /* merge_blocks_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_blocks_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A941587D243667F600566F16 /* pch_source_reduce.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source_reduce.cpp; sourceTree = "<group>"; };
-		A941587E243667F600566F16 /* reducer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reducer.cpp; sourceTree = "<group>"; };
-		A941587F243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_undef_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415880243667F600566F16 /* remove_function_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_function_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415881243667F600566F16 /* pch_source_reduce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source_reduce.h; sourceTree = "<group>"; };
-		A9415882243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_unreferenced_instruction_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415883243667F600566F16 /* merge_blocks_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_blocks_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415884243667F600566F16 /* reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415885243667F600566F16 /* reducer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reducer.h; sourceTree = "<group>"; };
-		A9415886243667F600566F16 /* change_operand_to_undef_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = change_operand_to_undef_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415887243667F600566F16 /* reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415888243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conditional_branch_to_simple_conditional_branch_opportunity_finder.h; sourceTree = "<group>"; };
-		A9415889243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_dominating_id_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A941588A243667F600566F16 /* reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A941588B243667F600566F16 /* change_operand_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = change_operand_reduction_opportunity.h; sourceTree = "<group>"; };
-		A941588C243667F600566F16 /* remove_block_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_block_reduction_opportunity_finder.h; sourceTree = "<group>"; };
-		A941588D243667F600566F16 /* remove_block_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_block_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A941588E243667F600566F16 /* reduction_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_util.h; sourceTree = "<group>"; };
-		A941588F243667F600566F16 /* merge_blocks_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_blocks_reduction_opportunity.h; sourceTree = "<group>"; };
-		A9415890243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp; sourceTree = "<group>"; };
-		A9415891243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = structured_loop_to_selection_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415892243667F600566F16 /* remove_block_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_block_reduction_opportunity.cpp; sourceTree = "<group>"; };
-		A9415893243667F600566F16 /* reduction_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_pass.h; sourceTree = "<group>"; };
-		A9415894243667F600566F16 /* latest_version_opencl_std_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_opencl_std_header.h; sourceTree = "<group>"; };
-		A9415895243667F600566F16 /* spirv_optimizer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_optimizer_options.cpp; sourceTree = "<group>"; };
-		A9415896243667F600566F16 /* cfa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfa.h; sourceTree = "<group>"; };
-		A9415897243667F600566F16 /* pch_source.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source.h; sourceTree = "<group>"; };
-		A9415898243667F600566F16 /* enum_string_mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enum_string_mapping.h; sourceTree = "<group>"; };
-		A9415899243667F600566F16 /* spirv_fuzzer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_fuzzer_options.cpp; sourceTree = "<group>"; };
-		A941589A243667F600566F16 /* spirv_reducer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_reducer_options.h; sourceTree = "<group>"; };
-		A941589B243667F600566F16 /* spirv_validator_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_validator_options.cpp; sourceTree = "<group>"; };
-		A941589C243667F600566F16 /* extinst.spv-amd-shader-trinary-minmax.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-trinary-minmax.grammar.json"; sourceTree = "<group>"; };
-		A941589D243667F600566F16 /* print.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = print.cpp; sourceTree = "<group>"; };
-		A941589E243667F600566F16 /* spirv_definition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_definition.h; sourceTree = "<group>"; };
-		A941589F243667F600566F16 /* operand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand.h; sourceTree = "<group>"; };
-		A94158A0243667F600566F16 /* spirv_endian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_endian.cpp; sourceTree = "<group>"; };
-		A94158A1243667F600566F16 /* macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macro.h; sourceTree = "<group>"; };
-		A94158A2243667F600566F16 /* spirv_constant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_constant.h; sourceTree = "<group>"; };
-		A94158A3243667F600566F16 /* extinst.spv-amd-gcn-shader.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-gcn-shader.grammar.json"; sourceTree = "<group>"; };
-		A94158A4243667F600566F16 /* binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = binary.cpp; sourceTree = "<group>"; };
-		A94158A5243667F600566F16 /* spirv_validator_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_validator_options.h; sourceTree = "<group>"; };
-		A94158A6243667F600566F16 /* enum_string_mapping.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = enum_string_mapping.cpp; sourceTree = "<group>"; };
-		A94158A7243667F600566F16 /* text_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text_handler.h; sourceTree = "<group>"; };
-		A94158A8243667F600566F16 /* parsed_operand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parsed_operand.h; sourceTree = "<group>"; };
-		A94158A9243667F600566F16 /* name_mapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = name_mapper.h; sourceTree = "<group>"; };
-		A94158AA243667F600566F16 /* spirv_reducer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_reducer_options.cpp; sourceTree = "<group>"; };
-		A94158AB243667F600566F16 /* parsed_operand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parsed_operand.cpp; sourceTree = "<group>"; };
-		A94158AC243667F600566F16 /* diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = diagnostic.h; sourceTree = "<group>"; };
-		A94158AD243667F600566F16 /* spirv_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_endian.h; sourceTree = "<group>"; };
-		A94158AE243667F600566F16 /* name_mapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = name_mapper.cpp; sourceTree = "<group>"; };
-		A94158AF243667F600566F16 /* extinst.debuginfo.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = extinst.debuginfo.grammar.json; sourceTree = "<group>"; };
-		A94158B1243667F600566F16 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
-		A94158B2243667F600566F16 /* linker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = linker.cpp; sourceTree = "<group>"; };
-		A94158B3243667F600566F16 /* software_version.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = software_version.cpp; sourceTree = "<group>"; };
-		A94158B4243667F600566F16 /* opcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opcode.cpp; sourceTree = "<group>"; };
-		A94158B5243667F600566F16 /* print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = print.h; sourceTree = "<group>"; };
-		A94158B6243667F600566F16 /* ext_inst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ext_inst.cpp; sourceTree = "<group>"; };
-		A94158B7243667F600566F16 /* disassemble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disassemble.h; sourceTree = "<group>"; };
-		A94158B9243667F600566F16 /* optimizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optimizer.cpp; sourceTree = "<group>"; };
-		A94158BA243667F600566F16 /* if_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_conversion.h; sourceTree = "<group>"; };
-		A94158BB243667F600566F16 /* register_pressure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = register_pressure.cpp; sourceTree = "<group>"; };
-		A94158BC243667F600566F16 /* loop_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_utils.cpp; sourceTree = "<group>"; };
-		A94158BD243667F600566F16 /* merge_return_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_return_pass.h; sourceTree = "<group>"; };
-		A94158BE243667F600566F16 /* inline_opaque_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_opaque_pass.h; sourceTree = "<group>"; };
-		A94158BF243667F600566F16 /* loop_fusion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fusion.h; sourceTree = "<group>"; };
-		A94158C0243667F600566F16 /* combine_access_chains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = combine_access_chains.cpp; sourceTree = "<group>"; };
-		A94158C1243667F600566F16 /* build_module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = build_module.cpp; sourceTree = "<group>"; };
-		A94158C2243667F600566F16 /* composite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = composite.h; sourceTree = "<group>"; };
-		A94158C3243667F600566F16 /* compact_ids_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compact_ids_pass.h; sourceTree = "<group>"; };
-		A94158C4243667F600566F16 /* register_pressure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = register_pressure.h; sourceTree = "<group>"; };
-		A94158C5243667F600566F16 /* tree_iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tree_iterator.h; sourceTree = "<group>"; };
-		A94158C6243667F600566F16 /* graphics_robust_access_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphics_robust_access_pass.h; sourceTree = "<group>"; };
-		A94158C7243667F600566F16 /* strip_atomic_counter_memory_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_atomic_counter_memory_pass.h; sourceTree = "<group>"; };
-		A94158C8243667F600566F16 /* legalize_vector_shuffle_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = legalize_vector_shuffle_pass.h; sourceTree = "<group>"; };
-		A94158C9243667F600566F16 /* local_single_store_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_single_store_elim_pass.h; sourceTree = "<group>"; };
-		A94158CA243667F600566F16 /* reduce_load_size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduce_load_size.h; sourceTree = "<group>"; };
-		A94158CB243667F600566F16 /* code_sink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = code_sink.cpp; sourceTree = "<group>"; };
-		A94158CC243667F600566F16 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
-		A94158CD243667F600566F16 /* scalar_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_analysis.h; sourceTree = "<group>"; };
-		A94158CE243667F600566F16 /* strip_debug_info_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_debug_info_pass.h; sourceTree = "<group>"; };
-		A94158CF243667F600566F16 /* cfg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg.cpp; sourceTree = "<group>"; };
-		A94158D0243667F600566F16 /* strip_atomic_counter_memory_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_atomic_counter_memory_pass.cpp; sourceTree = "<group>"; };
-		A94158D1243667F600566F16 /* decoration_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = decoration_manager.cpp; sourceTree = "<group>"; };
-		A94158D2243667F600566F16 /* local_single_block_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_single_block_elim_pass.cpp; sourceTree = "<group>"; };
-		A94158D3243667F600566F16 /* freeze_spec_constant_value_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = freeze_spec_constant_value_pass.cpp; sourceTree = "<group>"; };
-		A94158D4243667F600566F16 /* replace_invalid_opc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = replace_invalid_opc.h; sourceTree = "<group>"; };
-		A94158D5243667F600566F16 /* local_access_chain_convert_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_access_chain_convert_pass.h; sourceTree = "<group>"; };
-		A94158D6243667F600566F16 /* inst_bindless_check_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_bindless_check_pass.cpp; sourceTree = "<group>"; };
-		A94158D7243667F600566F16 /* local_redundancy_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_redundancy_elimination.cpp; sourceTree = "<group>"; };
-		A94158D8243667F600566F16 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
-		A94158D9243667F600566F16 /* instrument_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instrument_pass.cpp; sourceTree = "<group>"; };
-		A94158DA243667F600566F16 /* propagator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = propagator.h; sourceTree = "<group>"; };
-		A94158DB243667F600566F16 /* instruction_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction_list.h; sourceTree = "<group>"; };
-		A94158DC243667F600566F16 /* feature_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = feature_manager.cpp; sourceTree = "<group>"; };
-		A94158DD243667F600566F16 /* pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pass.cpp; sourceTree = "<group>"; };
-		A94158DE243667F600566F16 /* loop_fission.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fission.cpp; sourceTree = "<group>"; };
-		A94158DF243667F600566F16 /* dominator_tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dominator_tree.cpp; sourceTree = "<group>"; };
-		A94158E0243667F600566F16 /* amd_ext_to_khr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amd_ext_to_khr.h; sourceTree = "<group>"; };
-		A94158E1243667F600566F16 /* merge_return_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_return_pass.cpp; sourceTree = "<group>"; };
-		A94158E2243667F600566F16 /* ir_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_context.h; sourceTree = "<group>"; };
-		A94158E3243667F600566F16 /* eliminate_dead_constant_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_constant_pass.cpp; sourceTree = "<group>"; };
-		A94158E4243667F600566F16 /* cfg_cleanup_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_cleanup_pass.cpp; sourceTree = "<group>"; };
-		A94158E5243667F600566F16 /* wrap_opkill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_opkill.cpp; sourceTree = "<group>"; };
-		A94158E6243667F600566F16 /* const_folding_rules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = const_folding_rules.cpp; sourceTree = "<group>"; };
-		A94158E7243667F600566F16 /* loop_unroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_unroller.h; sourceTree = "<group>"; };
-		A94158E8243667F600566F16 /* strip_debug_info_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_debug_info_pass.cpp; sourceTree = "<group>"; };
-		A94158E9243667F600566F16 /* ssa_rewrite_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssa_rewrite_pass.cpp; sourceTree = "<group>"; };
-		A94158EA243667F600566F16 /* loop_dependence.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_dependence.cpp; sourceTree = "<group>"; };
-		A94158EB243667F600566F16 /* unify_const_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unify_const_pass.h; sourceTree = "<group>"; };
-		A94158EC243667F600566F16 /* ir_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_loader.h; sourceTree = "<group>"; };
-		A94158ED243667F600566F16 /* inst_debug_printf_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_debug_printf_pass.cpp; sourceTree = "<group>"; };
-		A94158EE243667F600566F16 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
-		A94158EF243667F600566F16 /* fold_spec_constant_op_and_composite_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fold_spec_constant_op_and_composite_pass.h; sourceTree = "<group>"; };
-		A94158F0243667F600566F16 /* mem_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mem_pass.cpp; sourceTree = "<group>"; };
-		A94158F1243667F600566F16 /* basic_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basic_block.h; sourceTree = "<group>"; };
-		A94158F2243667F600566F16 /* remove_duplicates_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_duplicates_pass.cpp; sourceTree = "<group>"; };
-		A94158F3243667F600566F16 /* dead_variable_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_variable_elimination.cpp; sourceTree = "<group>"; };
-		A94158F4243667F600566F16 /* block_merge_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block_merge_pass.h; sourceTree = "<group>"; };
-		A94158F5243667F600566F16 /* module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = module.cpp; sourceTree = "<group>"; };
-		A94158F6243667F600566F16 /* fold_spec_constant_op_and_composite_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fold_spec_constant_op_and_composite_pass.cpp; sourceTree = "<group>"; };
-		A94158F7243667F600566F16 /* loop_unswitch_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_unswitch_pass.cpp; sourceTree = "<group>"; };
-		A94158F8243667F600566F16 /* unify_const_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unify_const_pass.cpp; sourceTree = "<group>"; };
-		A94158F9243667F600566F16 /* type_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = type_manager.cpp; sourceTree = "<group>"; };
-		A94158FA243667F600566F16 /* generate_webgpu_initializers_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generate_webgpu_initializers_pass.cpp; sourceTree = "<group>"; };
-		A94158FB243667F600566F16 /* private_to_local_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = private_to_local_pass.h; sourceTree = "<group>"; };
-		A94158FC243667F600566F16 /* convert_to_half_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convert_to_half_pass.h; sourceTree = "<group>"; };
-		A94158FD243667F600566F16 /* relax_float_ops_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = relax_float_ops_pass.h; sourceTree = "<group>"; };
-		A94158FE243667F600566F16 /* inline_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_pass.cpp; sourceTree = "<group>"; };
-		A94158FF243667F600566F16 /* def_use_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = def_use_manager.h; sourceTree = "<group>"; };
-		A9415900243667F600566F16 /* ir_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ir_loader.cpp; sourceTree = "<group>"; };
-		A9415901243667F600566F16 /* cfg_cleanup_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_cleanup_pass.h; sourceTree = "<group>"; };
-		A9415902243667F600566F16 /* licm_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = licm_pass.cpp; sourceTree = "<group>"; };
-		A9415903243667F600566F16 /* eliminate_dead_functions_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_functions_pass.cpp; sourceTree = "<group>"; };
-		A9415904243667F600566F16 /* local_redundancy_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_redundancy_elimination.h; sourceTree = "<group>"; };
-		A9415905243667F600566F16 /* split_invalid_unreachable_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = split_invalid_unreachable_pass.cpp; sourceTree = "<group>"; };
-		A9415906243667F600566F16 /* loop_peeling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_peeling.h; sourceTree = "<group>"; };
-		A9415907243667F600566F16 /* vector_dce.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vector_dce.cpp; sourceTree = "<group>"; };
-		A9415908243667F600566F16 /* block_merge_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block_merge_util.h; sourceTree = "<group>"; };
-		A9415909243667F600566F16 /* loop_unroller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_unroller.cpp; sourceTree = "<group>"; };
-		A941590A243667F600566F16 /* desc_sroa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = desc_sroa.h; sourceTree = "<group>"; };
-		A941590B243667F600566F16 /* constants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = constants.cpp; sourceTree = "<group>"; };
-		A941590C243667F600566F16 /* loop_fusion_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fusion_pass.h; sourceTree = "<group>"; };
-		A941590D243667F600566F16 /* struct_cfg_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = struct_cfg_analysis.h; sourceTree = "<group>"; };
-		A941590E243667F600566F16 /* inst_buff_addr_check_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_buff_addr_check_pass.cpp; sourceTree = "<group>"; };
-		A941590F243667F600566F16 /* def_use_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = def_use_manager.cpp; sourceTree = "<group>"; };
-		A9415910243667F600566F16 /* wrap_opkill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_opkill.h; sourceTree = "<group>"; };
-		A9415911243667F600566F16 /* strip_reflect_info_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_reflect_info_pass.cpp; sourceTree = "<group>"; };
-		A9415912243667F600566F16 /* decoration_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoration_manager.h; sourceTree = "<group>"; };
-		A9415913243667F600566F16 /* ccp_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ccp_pass.cpp; sourceTree = "<group>"; };
-		A9415914243667F600566F16 /* process_lines_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = process_lines_pass.h; sourceTree = "<group>"; };
-		A9415915243667F600566F16 /* local_single_block_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_single_block_elim_pass.h; sourceTree = "<group>"; };
-		A9415916243667F600566F16 /* pch_source_opt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source_opt.cpp; sourceTree = "<group>"; };
-		A9415917243667F600566F16 /* inst_buff_addr_check_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_buff_addr_check_pass.h; sourceTree = "<group>"; };
-		A9415918243667F600566F16 /* strength_reduction_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strength_reduction_pass.h; sourceTree = "<group>"; };
-		A9415919243667F600566F16 /* aggressive_dead_code_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = aggressive_dead_code_elim_pass.cpp; sourceTree = "<group>"; };
-		A941591A243667F600566F16 /* eliminate_dead_functions_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_functions_util.cpp; sourceTree = "<group>"; };
-		A941591B243667F600566F16 /* inst_debug_printf_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_debug_printf_pass.h; sourceTree = "<group>"; };
-		A941591C243667F600566F16 /* simplification_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simplification_pass.cpp; sourceTree = "<group>"; };
-		A941591D243667F600566F16 /* dead_branch_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_branch_elim_pass.cpp; sourceTree = "<group>"; };
-		A941591E243667F600566F16 /* flatten_decoration_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flatten_decoration_pass.cpp; sourceTree = "<group>"; };
-		A941591F243667F600566F16 /* dead_insert_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_insert_elim_pass.h; sourceTree = "<group>"; };
-		A9415920243667F600566F16 /* folding_rules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = folding_rules.cpp; sourceTree = "<group>"; };
-		A9415921243667F600566F16 /* freeze_spec_constant_value_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = freeze_spec_constant_value_pass.h; sourceTree = "<group>"; };
-		A9415922243667F600566F16 /* ir_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ir_context.cpp; sourceTree = "<group>"; };
-		A9415923243667F600566F16 /* instrument_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instrument_pass.h; sourceTree = "<group>"; };
-		A9415924243667F600566F16 /* mem_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mem_pass.h; sourceTree = "<group>"; };
-		A9415925243667F600566F16 /* loop_descriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_descriptor.cpp; sourceTree = "<group>"; };
-		A9415926243667F600566F16 /* eliminate_dead_members_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_members_pass.h; sourceTree = "<group>"; };
-		A9415927243667F600566F16 /* function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function.cpp; sourceTree = "<group>"; };
-		A9415928243667F600566F16 /* instruction_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction_list.cpp; sourceTree = "<group>"; };
-		A9415929243667F600566F16 /* composite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = composite.cpp; sourceTree = "<group>"; };
-		A941592A243667F600566F16 /* convert_to_half_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = convert_to_half_pass.cpp; sourceTree = "<group>"; };
-		A941592B243667F600566F16 /* process_lines_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = process_lines_pass.cpp; sourceTree = "<group>"; };
-		A941592C243667F600566F16 /* inline_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_pass.h; sourceTree = "<group>"; };
-		A941592D243667F600566F16 /* loop_dependence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_dependence.h; sourceTree = "<group>"; };
-		A941592E243667F600566F16 /* value_number_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = value_number_table.h; sourceTree = "<group>"; };
-		A941592F243667F600566F16 /* flatten_decoration_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flatten_decoration_pass.h; sourceTree = "<group>"; };
-		A9415930243667F600566F16 /* if_conversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = if_conversion.cpp; sourceTree = "<group>"; };
-		A9415931243667F600566F16 /* inline_exhaustive_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_exhaustive_pass.h; sourceTree = "<group>"; };
-		A9415932243667F600566F16 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = constants.h; sourceTree = "<group>"; };
-		A9415933243667F600566F16 /* eliminate_dead_members_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_members_pass.cpp; sourceTree = "<group>"; };
-		A9415934243667F600566F16 /* strength_reduction_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strength_reduction_pass.cpp; sourceTree = "<group>"; };
-		A9415935243667F600566F16 /* desc_sroa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = desc_sroa.cpp; sourceTree = "<group>"; };
-		A9415936243667F600566F16 /* block_merge_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = block_merge_util.cpp; sourceTree = "<group>"; };
-		A9415937243667F600566F16 /* upgrade_memory_model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upgrade_memory_model.h; sourceTree = "<group>"; };
-		A9415938243667F600566F16 /* copy_prop_arrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = copy_prop_arrays.cpp; sourceTree = "<group>"; };
-		A9415939243667F600566F16 /* pass_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pass_manager.cpp; sourceTree = "<group>"; };
-		A941593A243667F600566F16 /* inline_exhaustive_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_exhaustive_pass.cpp; sourceTree = "<group>"; };
-		A941593B243667F600566F16 /* loop_fission.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fission.h; sourceTree = "<group>"; };
-		A941593C243667F600566F16 /* workaround1209.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = workaround1209.h; sourceTree = "<group>"; };
-		A941593D243667F600566F16 /* loop_fusion_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fusion_pass.cpp; sourceTree = "<group>"; };
-		A941593E243667F600566F16 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
-		A941593F243667F600566F16 /* split_invalid_unreachable_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = split_invalid_unreachable_pass.h; sourceTree = "<group>"; };
-		A9415940243667F600566F16 /* copy_prop_arrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copy_prop_arrays.h; sourceTree = "<group>"; };
-		A9415941243667F600566F16 /* eliminate_dead_constant_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_constant_pass.h; sourceTree = "<group>"; };
-		A9415942243667F600566F16 /* dead_insert_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_insert_elim_pass.cpp; sourceTree = "<group>"; };
-		A9415943243667F600566F16 /* ssa_rewrite_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssa_rewrite_pass.h; sourceTree = "<group>"; };
-		A9415944243667F600566F16 /* scalar_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_analysis.cpp; sourceTree = "<group>"; };
-		A9415945243667F600566F16 /* dead_variable_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_variable_elimination.h; sourceTree = "<group>"; };
-		A9415946243667F600566F16 /* block_merge_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = block_merge_pass.cpp; sourceTree = "<group>"; };
-		A9415947243667F600566F16 /* dominator_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dominator_analysis.h; sourceTree = "<group>"; };
-		A9415948243667F600566F16 /* pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pass.h; sourceTree = "<group>"; };
-		A9415949243667F600566F16 /* folding_rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = folding_rules.h; sourceTree = "<group>"; };
-		A941594A243667F600566F16 /* eliminate_dead_functions_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_functions_pass.h; sourceTree = "<group>"; };
-		A941594B243667F600566F16 /* eliminate_dead_functions_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_functions_util.h; sourceTree = "<group>"; };
-		A941594C243667F600566F16 /* fold.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fold.h; sourceTree = "<group>"; };
-		A941594D243667F600566F16 /* local_single_store_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_single_store_elim_pass.cpp; sourceTree = "<group>"; };
-		A941594E243667F600566F16 /* dead_branch_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_branch_elim_pass.h; sourceTree = "<group>"; };
-		A941594F243667F600566F16 /* private_to_local_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = private_to_local_pass.cpp; sourceTree = "<group>"; };
-		A9415950243667F600566F16 /* scalar_analysis_nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_analysis_nodes.h; sourceTree = "<group>"; };
-		A9415951243667F600566F16 /* propagator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = propagator.cpp; sourceTree = "<group>"; };
-		A9415952243667F600566F16 /* fix_storage_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fix_storage_class.h; sourceTree = "<group>"; };
-		A9415953243667F600566F16 /* loop_dependence_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_dependence_helpers.cpp; sourceTree = "<group>"; };
-		A9415954243667F600566F16 /* set_spec_constant_default_value_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = set_spec_constant_default_value_pass.cpp; sourceTree = "<group>"; };
-		A9415955243667F600566F16 /* passes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = passes.h; sourceTree = "<group>"; };
-		A9415956243667F600566F16 /* fold.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fold.cpp; sourceTree = "<group>"; };
-		A9415957243667F600566F16 /* amd_ext_to_khr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = amd_ext_to_khr.cpp; sourceTree = "<group>"; };
-		A9415958243667F600566F16 /* strip_reflect_info_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_reflect_info_pass.h; sourceTree = "<group>"; };
-		A9415959243667F600566F16 /* scalar_replacement_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_replacement_pass.cpp; sourceTree = "<group>"; };
-		A941595A243667F600566F16 /* simplification_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simplification_pass.h; sourceTree = "<group>"; };
-		A941595B243667F600566F16 /* remove_duplicates_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_duplicates_pass.h; sourceTree = "<group>"; };
-		A941595C243667F600566F16 /* redundancy_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = redundancy_elimination.cpp; sourceTree = "<group>"; };
-		A941595D243667F600566F16 /* reflect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflect.h; sourceTree = "<group>"; };
-		A941595E243667F600566F16 /* workaround1209.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = workaround1209.cpp; sourceTree = "<group>"; };
-		A941595F243667F600566F16 /* null_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = null_pass.h; sourceTree = "<group>"; };
-		A9415960243667F600566F16 /* relax_float_ops_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = relax_float_ops_pass.cpp; sourceTree = "<group>"; };
-		A9415961243667F600566F16 /* const_folding_rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = const_folding_rules.h; sourceTree = "<group>"; };
-		A9415962243667F600566F16 /* scalar_replacement_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_replacement_pass.h; sourceTree = "<group>"; };
-		A9415963243667F600566F16 /* instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction.cpp; sourceTree = "<group>"; };
-		A9415964243667F600566F16 /* pch_source_opt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source_opt.h; sourceTree = "<group>"; };
-		A9415965243667F600566F16 /* reduce_load_size.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduce_load_size.cpp; sourceTree = "<group>"; };
-		A9415966243667F600566F16 /* redundancy_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = redundancy_elimination.h; sourceTree = "<group>"; };
-		A9415967243667F600566F16 /* fix_storage_class.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fix_storage_class.cpp; sourceTree = "<group>"; };
-		A9415968243667F600566F16 /* value_number_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = value_number_table.cpp; sourceTree = "<group>"; };
-		A9415969243667F600566F16 /* inline_opaque_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_opaque_pass.cpp; sourceTree = "<group>"; };
-		A941596A243667F600566F16 /* replace_invalid_opc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = replace_invalid_opc.cpp; sourceTree = "<group>"; };
-		A941596B243667F600566F16 /* loop_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_utils.h; sourceTree = "<group>"; };
-		A941596C243667F700566F16 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = module.h; sourceTree = "<group>"; };
-		A941596D243667F700566F16 /* dominator_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dominator_analysis.cpp; sourceTree = "<group>"; };
-		A941596E243667F700566F16 /* decompose_initialized_variables_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = decompose_initialized_variables_pass.cpp; sourceTree = "<group>"; };
-		A941596F243667F700566F16 /* ir_builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_builder.h; sourceTree = "<group>"; };
-		A9415970243667F700566F16 /* loop_unswitch_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_unswitch_pass.h; sourceTree = "<group>"; };
-		A9415971243667F700566F16 /* cfg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg.h; sourceTree = "<group>"; };
-		A9415972243667F700566F16 /* code_sink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = code_sink.h; sourceTree = "<group>"; };
-		A9415973243667F700566F16 /* loop_descriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_descriptor.h; sourceTree = "<group>"; };
-		A9415974243667F700566F16 /* generate_webgpu_initializers_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = generate_webgpu_initializers_pass.h; sourceTree = "<group>"; };
-		A9415975243667F700566F16 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
-		A9415976243667F700566F16 /* aggressive_dead_code_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aggressive_dead_code_elim_pass.h; sourceTree = "<group>"; };
-		A9415977243667F700566F16 /* struct_cfg_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = struct_cfg_analysis.cpp; sourceTree = "<group>"; };
-		A9415978243667F700566F16 /* vector_dce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_dce.h; sourceTree = "<group>"; };
-		A9415979243667F700566F16 /* combine_access_chains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = combine_access_chains.h; sourceTree = "<group>"; };
-		A941597A243667F700566F16 /* pass_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pass_manager.h; sourceTree = "<group>"; };
-		A941597B243667F700566F16 /* local_access_chain_convert_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_access_chain_convert_pass.cpp; sourceTree = "<group>"; };
-		A941597C243667F700566F16 /* basic_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basic_block.cpp; sourceTree = "<group>"; };
-		A941597D243667F700566F16 /* iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterator.h; sourceTree = "<group>"; };
-		A941597E243667F700566F16 /* licm_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = licm_pass.h; sourceTree = "<group>"; };
-		A941597F243667F700566F16 /* build_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = build_module.h; sourceTree = "<group>"; };
-		A9415980243667F700566F16 /* ccp_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccp_pass.h; sourceTree = "<group>"; };
-		A9415981243667F700566F16 /* graphics_robust_access_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphics_robust_access_pass.cpp; sourceTree = "<group>"; };
-		A9415982243667F700566F16 /* decompose_initialized_variables_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decompose_initialized_variables_pass.h; sourceTree = "<group>"; };
-		A9415983243667F700566F16 /* function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function.h; sourceTree = "<group>"; };
-		A9415984243667F700566F16 /* loop_fusion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fusion.cpp; sourceTree = "<group>"; };
-		A9415985243667F700566F16 /* upgrade_memory_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = upgrade_memory_model.cpp; sourceTree = "<group>"; };
-		A9415986243667F700566F16 /* feature_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = feature_manager.h; sourceTree = "<group>"; };
-		A9415987243667F700566F16 /* inst_bindless_check_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_bindless_check_pass.h; sourceTree = "<group>"; };
-		A9415988243667F700566F16 /* scalar_analysis_simplification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_analysis_simplification.cpp; sourceTree = "<group>"; };
-		A9415989243667F700566F16 /* set_spec_constant_default_value_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = set_spec_constant_default_value_pass.h; sourceTree = "<group>"; };
-		A941598A243667F700566F16 /* dominator_tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dominator_tree.h; sourceTree = "<group>"; };
-		A941598B243667F700566F16 /* legalize_vector_shuffle_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = legalize_vector_shuffle_pass.cpp; sourceTree = "<group>"; };
-		A941598C243667F700566F16 /* type_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type_manager.h; sourceTree = "<group>"; };
-		A941598D243667F700566F16 /* compact_ids_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_ids_pass.cpp; sourceTree = "<group>"; };
-		A941598E243667F700566F16 /* loop_peeling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_peeling.cpp; sourceTree = "<group>"; };
-		A941598F243667F700566F16 /* table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = table.h; sourceTree = "<group>"; };
-		A9415A48243667F700566F16 /* ext_inst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ext_inst.h; sourceTree = "<group>"; };
-		A9415A49243667F700566F16 /* diagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = diagnostic.cpp; sourceTree = "<group>"; };
-		A9415A4A243667F700566F16 /* latest_version_spirv_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_spirv_header.h; sourceTree = "<group>"; };
-		A9415A4B243667F700566F16 /* libspirv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libspirv.cpp; sourceTree = "<group>"; };
-		A9415A4C243667F700566F16 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
-		A9415A4D243667F700566F16 /* spirv_optimizer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_optimizer_options.h; sourceTree = "<group>"; };
-		A9415A4E243667F700566F16 /* opcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcode.h; sourceTree = "<group>"; };
-		A9415A4F243667F700566F16 /* operand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand.cpp; sourceTree = "<group>"; };
-		A9415A50243667F700566F16 /* latest_version_glsl_std_450_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_glsl_std_450_header.h; sourceTree = "<group>"; };
-		A9415A51243667F700566F16 /* extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extensions.h; sourceTree = "<group>"; };
-		A9415A52243667F700566F16 /* disassemble.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = disassemble.cpp; sourceTree = "<group>"; };
-		A9415A53243667F700566F16 /* binary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = binary.h; sourceTree = "<group>"; };
-		A9415A54243667F700566F16 /* text_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_handler.cpp; sourceTree = "<group>"; };
-		A9415A56243667F700566F16 /* validate_annotation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_annotation.cpp; sourceTree = "<group>"; };
-		A9415A57243667F700566F16 /* validate_misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_misc.cpp; sourceTree = "<group>"; };
-		A9415A58243667F700566F16 /* validate_cfg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_cfg.cpp; sourceTree = "<group>"; };
-		A9415A59243667F700566F16 /* validate_capability.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_capability.cpp; sourceTree = "<group>"; };
-		A9415A5A243667F700566F16 /* construct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = construct.h; sourceTree = "<group>"; };
-		A9415A5B243667F700566F16 /* validate_barriers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_barriers.cpp; sourceTree = "<group>"; };
-		A9415A5C243667F700566F16 /* validate_non_uniform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_non_uniform.cpp; sourceTree = "<group>"; };
-		A9415A5D243667F700566F16 /* validate_scopes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_scopes.cpp; sourceTree = "<group>"; };
-		A9415A5E243667F700566F16 /* validate_atomics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_atomics.cpp; sourceTree = "<group>"; };
-		A9415A5F243667F700566F16 /* basic_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basic_block.h; sourceTree = "<group>"; };
-		A9415A60243667F700566F16 /* validate_instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_instruction.cpp; sourceTree = "<group>"; };
-		A9415A61243667F700566F16 /* validate_decorations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_decorations.cpp; sourceTree = "<group>"; };
-		A9415A62243667F700566F16 /* validate_debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_debug.cpp; sourceTree = "<group>"; };
-		A9415A63243667F700566F16 /* validate_builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_builtins.cpp; sourceTree = "<group>"; };
-		A9415A64243667F700566F16 /* validate_interfaces.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_interfaces.cpp; sourceTree = "<group>"; };
-		A9415A65243667F700566F16 /* validate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate.cpp; sourceTree = "<group>"; };
-		A9415A66243667F700566F16 /* validation_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validation_state.h; sourceTree = "<group>"; };
-		A9415A67243667F700566F16 /* validate_constants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_constants.cpp; sourceTree = "<group>"; };
-		A9415A68243667F700566F16 /* validate_bitwise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_bitwise.cpp; sourceTree = "<group>"; };
-		A9415A69243667F700566F16 /* validate_extensions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_extensions.cpp; sourceTree = "<group>"; };
-		A9415A6A243667F700566F16 /* construct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = construct.cpp; sourceTree = "<group>"; };
-		A9415A6B243667F700566F16 /* function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function.cpp; sourceTree = "<group>"; };
-		A9415A6C243667F700566F16 /* validate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate.h; sourceTree = "<group>"; };
-		A9415A6D243667F700566F16 /* validate_adjacency.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_adjacency.cpp; sourceTree = "<group>"; };
-		A9415A6E243667F700566F16 /* validate_conversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_conversion.cpp; sourceTree = "<group>"; };
-		A9415A6F243667F700566F16 /* validate_small_type_uses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_small_type_uses.cpp; sourceTree = "<group>"; };
-		A9415A70243667F700566F16 /* validate_scopes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate_scopes.h; sourceTree = "<group>"; };
-		A9415A71243667F700566F16 /* validate_id.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_id.cpp; sourceTree = "<group>"; };
-		A9415A72243667F700566F16 /* validate_memory_semantics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate_memory_semantics.h; sourceTree = "<group>"; };
-		A9415A73243667F700566F16 /* validate_arithmetics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_arithmetics.cpp; sourceTree = "<group>"; };
-		A9415A74243667F700566F16 /* validate_mode_setting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_mode_setting.cpp; sourceTree = "<group>"; };
-		A9415A75243667F700566F16 /* validate_memory_semantics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_memory_semantics.cpp; sourceTree = "<group>"; };
-		A9415A76243667F700566F16 /* validate_logicals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_logicals.cpp; sourceTree = "<group>"; };
-		A9415A77243667F700566F16 /* validate_derivatives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_derivatives.cpp; sourceTree = "<group>"; };
-		A9415A78243667F700566F16 /* validate_memory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_memory.cpp; sourceTree = "<group>"; };
-		A9415A79243667F700566F16 /* validate_image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_image.cpp; sourceTree = "<group>"; };
-		A9415A7A243667F700566F16 /* validate_literals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_literals.cpp; sourceTree = "<group>"; };
-		A9415A7B243667F700566F16 /* instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction.cpp; sourceTree = "<group>"; };
-		A9415A7C243667F700566F16 /* validate_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_type.cpp; sourceTree = "<group>"; };
-		A9415A7D243667F700566F16 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
-		A9415A7E243667F700566F16 /* validate_execution_limitations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_execution_limitations.cpp; sourceTree = "<group>"; };
-		A9415A7F243667F700566F16 /* validate_layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_layout.cpp; sourceTree = "<group>"; };
-		A9415A80243667F700566F16 /* basic_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basic_block.cpp; sourceTree = "<group>"; };
-		A9415A81243667F700566F16 /* validate_function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_function.cpp; sourceTree = "<group>"; };
-		A9415A82243667F700566F16 /* function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function.h; sourceTree = "<group>"; };
-		A9415A83243667F700566F16 /* validate_composites.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_composites.cpp; sourceTree = "<group>"; };
-		A9415A84243667F700566F16 /* validation_state.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validation_state.cpp; sourceTree = "<group>"; };
-		A9415A85243667F700566F16 /* validate_primitives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_primitives.cpp; sourceTree = "<group>"; };
-		A9415A86243667F700566F16 /* decoration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoration.h; sourceTree = "<group>"; };
 		A9415EF624366B0E00566F16 /* packagePregenSpirvToolsHeaders */ = {isa = PBXFileReference; lastKnownFileType = text; path = packagePregenSpirvToolsHeaders; sourceTree = "<group>"; };
 		A95D90A723A7F1E500CBCC60 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
 		A95D90AA23A7F1E500CBCC60 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
@@ -1619,6 +1236,407 @@
 		A976290C21CC60BC00B52A68 /* spirv_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_parser.hpp; sourceTree = "<group>"; };
 		A976290D21CC60BC00B52A68 /* spirv_msl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_msl.cpp; sourceTree = "<group>"; };
 		A976290E21CC60BC00B52A68 /* spirv_cross_parsed_ir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cross_parsed_ir.cpp; sourceTree = "<group>"; };
+		A9765B9B2485758300FDD115 /* spirv_target_env.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_target_env.cpp; sourceTree = "<group>"; };
+		A9765B9C2485758300FDD115 /* extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json"; sourceTree = "<group>"; };
+		A9765B9D2485758300FDD115 /* spirv_fuzzer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_fuzzer_options.h; sourceTree = "<group>"; };
+		A9765B9E2485758300FDD115 /* assembly_grammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assembly_grammar.h; sourceTree = "<group>"; };
+		A9765B9F2485758300FDD115 /* enum_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enum_set.h; sourceTree = "<group>"; };
+		A9765BA02485758300FDD115 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		A9765BA12485758300FDD115 /* extinst.spv-amd-shader-ballot.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-ballot.grammar.json"; sourceTree = "<group>"; };
+		A9765BA22485758300FDD115 /* text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text.cpp; sourceTree = "<group>"; };
+		A9765BA32485758300FDD115 /* assembly_grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = assembly_grammar.cpp; sourceTree = "<group>"; };
+		A9765BA42485758300FDD115 /* text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text.h; sourceTree = "<group>"; };
+		A9765BA52485758300FDD115 /* extensions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = extensions.cpp; sourceTree = "<group>"; };
+		A9765BA62485758300FDD115 /* pch_source.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source.cpp; sourceTree = "<group>"; };
+		A9765BA82485758300FDD115 /* parse_number.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parse_number.h; sourceTree = "<group>"; };
+		A9765BA92485758300FDD115 /* ilist_node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilist_node.h; sourceTree = "<group>"; };
+		A9765BAA2485758300FDD115 /* make_unique.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = make_unique.h; sourceTree = "<group>"; };
+		A9765BAB2485758300FDD115 /* string_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_utils.h; sourceTree = "<group>"; };
+		A9765BAC2485758300FDD115 /* small_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = small_vector.h; sourceTree = "<group>"; };
+		A9765BAD2485758300FDD115 /* timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timer.cpp; sourceTree = "<group>"; };
+		A9765BAE2485758300FDD115 /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
+		A9765BAF2485758300FDD115 /* string_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_utils.cpp; sourceTree = "<group>"; };
+		A9765BB02485758300FDD115 /* bit_vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_vector.h; sourceTree = "<group>"; };
+		A9765BB12485758300FDD115 /* bitutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitutils.h; sourceTree = "<group>"; };
+		A9765BB22485758300FDD115 /* hex_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hex_float.h; sourceTree = "<group>"; };
+		A9765BB32485758300FDD115 /* parse_number.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parse_number.cpp; sourceTree = "<group>"; };
+		A9765BB42485758300FDD115 /* bit_vector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bit_vector.cpp; sourceTree = "<group>"; };
+		A9765BB52485758300FDD115 /* ilist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ilist.h; sourceTree = "<group>"; };
+		A9765BB62485758300FDD115 /* spirv_target_env.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_target_env.h; sourceTree = "<group>"; };
+		A9765BB72485758300FDD115 /* table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = table.cpp; sourceTree = "<group>"; };
+		A9765BB82485758300FDD115 /* extinst.opencl.debuginfo.100.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = extinst.opencl.debuginfo.100.grammar.json; sourceTree = "<group>"; };
+		A9765BBA2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_undef_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BBB2485758300FDD115 /* remove_selection_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_selection_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BBC2485758300FDD115 /* remove_block_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_block_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BBD2485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_dominating_id_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BBE2485758300FDD115 /* reduction_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_pass.cpp; sourceTree = "<group>"; };
+		A9765BBF2485758300FDD115 /* operand_to_const_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_const_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BC02485758300FDD115 /* operand_to_const_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand_to_const_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BC12485758300FDD115 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		A9765BC22485758300FDD115 /* reduction_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_util.cpp; sourceTree = "<group>"; };
+		A9765BC32485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = structured_loop_to_selection_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BC42485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_conditional_branch_to_branch_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BC52485758300FDD115 /* remove_function_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_function_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BC62485758300FDD115 /* remove_instruction_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_instruction_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BC72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conditional_branch_to_simple_conditional_branch_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BC82485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_conditional_branch_to_branch_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BC92485758300FDD115 /* remove_function_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_function_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BCA2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_conditional_branch_to_branch_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BCB2485758300FDD115 /* remove_selection_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_selection_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BCC2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BCD2485758300FDD115 /* remove_struct_member_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_struct_member_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BCE2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_conditional_branch_to_branch_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BCF2485758300FDD115 /* merge_blocks_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_blocks_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BD02485758300FDD115 /* change_operand_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = change_operand_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BD12485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structured_loop_to_selection_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BD22485758300FDD115 /* remove_function_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_function_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BD32485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_unused_instruction_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BD42485758300FDD115 /* change_operand_to_undef_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = change_operand_to_undef_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BD52485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = structured_loop_to_selection_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BD62485758300FDD115 /* remove_selection_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_selection_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BD72485758300FDD115 /* remove_instruction_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_instruction_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BD82485758300FDD115 /* remove_selection_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_selection_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BD92485758300FDD115 /* merge_blocks_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_blocks_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BDA2485758300FDD115 /* pch_source_reduce.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source_reduce.cpp; sourceTree = "<group>"; };
+		A9765BDB2485758300FDD115 /* remove_struct_member_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_struct_member_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BDC2485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_unused_struct_member_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BDD2485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_unused_instruction_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BDE2485758300FDD115 /* reducer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reducer.cpp; sourceTree = "<group>"; };
+		A9765BDF2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_undef_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BE02485758300FDD115 /* remove_function_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_function_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BE12485758300FDD115 /* pch_source_reduce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source_reduce.h; sourceTree = "<group>"; };
+		A9765BE22485758300FDD115 /* merge_blocks_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_blocks_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BE32485758300FDD115 /* reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BE42485758300FDD115 /* reducer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reducer.h; sourceTree = "<group>"; };
+		A9765BE52485758300FDD115 /* change_operand_to_undef_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = change_operand_to_undef_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BE62485758300FDD115 /* reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BE72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conditional_branch_to_simple_conditional_branch_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BE82485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand_to_dominating_id_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BE92485758300FDD115 /* reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BEA2485758300FDD115 /* change_operand_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = change_operand_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BEB2485758300FDD115 /* remove_block_reduction_opportunity_finder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_block_reduction_opportunity_finder.h; sourceTree = "<group>"; };
+		A9765BEC2485758300FDD115 /* remove_block_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_block_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BED2485758300FDD115 /* reduction_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_util.h; sourceTree = "<group>"; };
+		A9765BEE2485758300FDD115 /* merge_blocks_reduction_opportunity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_blocks_reduction_opportunity.h; sourceTree = "<group>"; };
+		A9765BEF2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BF02485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = structured_loop_to_selection_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BF12485758300FDD115 /* remove_block_reduction_opportunity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_block_reduction_opportunity.cpp; sourceTree = "<group>"; };
+		A9765BF22485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_unused_struct_member_reduction_opportunity_finder.cpp; sourceTree = "<group>"; };
+		A9765BF32485758300FDD115 /* reduction_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduction_pass.h; sourceTree = "<group>"; };
+		A9765BF42485758300FDD115 /* latest_version_opencl_std_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_opencl_std_header.h; sourceTree = "<group>"; };
+		A9765BF52485758300FDD115 /* spirv_optimizer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_optimizer_options.cpp; sourceTree = "<group>"; };
+		A9765BF62485758300FDD115 /* cfa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfa.h; sourceTree = "<group>"; };
+		A9765BF72485758300FDD115 /* pch_source.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source.h; sourceTree = "<group>"; };
+		A9765BF82485758300FDD115 /* enum_string_mapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = enum_string_mapping.h; sourceTree = "<group>"; };
+		A9765BF92485758300FDD115 /* spirv_fuzzer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_fuzzer_options.cpp; sourceTree = "<group>"; };
+		A9765BFA2485758300FDD115 /* spirv_reducer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_reducer_options.h; sourceTree = "<group>"; };
+		A9765BFB2485758300FDD115 /* spirv_validator_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_validator_options.cpp; sourceTree = "<group>"; };
+		A9765BFC2485758300FDD115 /* extinst.spv-amd-shader-trinary-minmax.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-shader-trinary-minmax.grammar.json"; sourceTree = "<group>"; };
+		A9765BFD2485758300FDD115 /* print.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = print.cpp; sourceTree = "<group>"; };
+		A9765BFE2485758300FDD115 /* spirv_definition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_definition.h; sourceTree = "<group>"; };
+		A9765BFF2485758300FDD115 /* operand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = operand.h; sourceTree = "<group>"; };
+		A9765C002485758300FDD115 /* spirv_endian.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_endian.cpp; sourceTree = "<group>"; };
+		A9765C012485758300FDD115 /* macro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macro.h; sourceTree = "<group>"; };
+		A9765C022485758300FDD115 /* spirv_constant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_constant.h; sourceTree = "<group>"; };
+		A9765C032485758300FDD115 /* extinst.spv-amd-gcn-shader.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "extinst.spv-amd-gcn-shader.grammar.json"; sourceTree = "<group>"; };
+		A9765C042485758300FDD115 /* binary.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = binary.cpp; sourceTree = "<group>"; };
+		A9765C052485758300FDD115 /* spirv_validator_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_validator_options.h; sourceTree = "<group>"; };
+		A9765C062485758300FDD115 /* enum_string_mapping.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = enum_string_mapping.cpp; sourceTree = "<group>"; };
+		A9765C072485758300FDD115 /* text_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text_handler.h; sourceTree = "<group>"; };
+		A9765C082485758300FDD115 /* parsed_operand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parsed_operand.h; sourceTree = "<group>"; };
+		A9765C092485758300FDD115 /* name_mapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = name_mapper.h; sourceTree = "<group>"; };
+		A9765C0A2485758300FDD115 /* spirv_reducer_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_reducer_options.cpp; sourceTree = "<group>"; };
+		A9765C0B2485758300FDD115 /* parsed_operand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parsed_operand.cpp; sourceTree = "<group>"; };
+		A9765C0C2485758300FDD115 /* diagnostic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = diagnostic.h; sourceTree = "<group>"; };
+		A9765C0D2485758300FDD115 /* spirv_endian.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_endian.h; sourceTree = "<group>"; };
+		A9765C0E2485758300FDD115 /* name_mapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = name_mapper.cpp; sourceTree = "<group>"; };
+		A9765C0F2485758300FDD115 /* extinst.debuginfo.grammar.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = extinst.debuginfo.grammar.json; sourceTree = "<group>"; };
+		A9765C112485758300FDD115 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		A9765C122485758300FDD115 /* linker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = linker.cpp; sourceTree = "<group>"; };
+		A9765C132485758300FDD115 /* software_version.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = software_version.cpp; sourceTree = "<group>"; };
+		A9765C142485758300FDD115 /* opcode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opcode.cpp; sourceTree = "<group>"; };
+		A9765C152485758300FDD115 /* print.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = print.h; sourceTree = "<group>"; };
+		A9765C162485758300FDD115 /* ext_inst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ext_inst.cpp; sourceTree = "<group>"; };
+		A9765C172485758300FDD115 /* disassemble.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = disassemble.h; sourceTree = "<group>"; };
+		A9765C192485758300FDD115 /* optimizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = optimizer.cpp; sourceTree = "<group>"; };
+		A9765C1A2485758300FDD115 /* if_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if_conversion.h; sourceTree = "<group>"; };
+		A9765C1B2485758300FDD115 /* register_pressure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = register_pressure.cpp; sourceTree = "<group>"; };
+		A9765C1C2485758300FDD115 /* loop_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_utils.cpp; sourceTree = "<group>"; };
+		A9765C1D2485758300FDD115 /* merge_return_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = merge_return_pass.h; sourceTree = "<group>"; };
+		A9765C1E2485758300FDD115 /* inline_opaque_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_opaque_pass.h; sourceTree = "<group>"; };
+		A9765C1F2485758300FDD115 /* loop_fusion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fusion.h; sourceTree = "<group>"; };
+		A9765C202485758300FDD115 /* combine_access_chains.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = combine_access_chains.cpp; sourceTree = "<group>"; };
+		A9765C212485758300FDD115 /* build_module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = build_module.cpp; sourceTree = "<group>"; };
+		A9765C222485758300FDD115 /* composite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = composite.h; sourceTree = "<group>"; };
+		A9765C232485758300FDD115 /* compact_ids_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compact_ids_pass.h; sourceTree = "<group>"; };
+		A9765C242485758300FDD115 /* register_pressure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = register_pressure.h; sourceTree = "<group>"; };
+		A9765C252485758300FDD115 /* tree_iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tree_iterator.h; sourceTree = "<group>"; };
+		A9765C262485758300FDD115 /* graphics_robust_access_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = graphics_robust_access_pass.h; sourceTree = "<group>"; };
+		A9765C272485758300FDD115 /* strip_atomic_counter_memory_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_atomic_counter_memory_pass.h; sourceTree = "<group>"; };
+		A9765C282485758300FDD115 /* legalize_vector_shuffle_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = legalize_vector_shuffle_pass.h; sourceTree = "<group>"; };
+		A9765C292485758300FDD115 /* local_single_store_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_single_store_elim_pass.h; sourceTree = "<group>"; };
+		A9765C2A2485758300FDD115 /* reduce_load_size.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reduce_load_size.h; sourceTree = "<group>"; };
+		A9765C2B2485758300FDD115 /* code_sink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = code_sink.cpp; sourceTree = "<group>"; };
+		A9765C2C2485758300FDD115 /* types.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = types.cpp; sourceTree = "<group>"; };
+		A9765C2D2485758300FDD115 /* scalar_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_analysis.h; sourceTree = "<group>"; };
+		A9765C2E2485758300FDD115 /* strip_debug_info_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_debug_info_pass.h; sourceTree = "<group>"; };
+		A9765C2F2485758300FDD115 /* cfg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg.cpp; sourceTree = "<group>"; };
+		A9765C302485758300FDD115 /* strip_atomic_counter_memory_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_atomic_counter_memory_pass.cpp; sourceTree = "<group>"; };
+		A9765C312485758300FDD115 /* decoration_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = decoration_manager.cpp; sourceTree = "<group>"; };
+		A9765C322485758300FDD115 /* local_single_block_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_single_block_elim_pass.cpp; sourceTree = "<group>"; };
+		A9765C332485758300FDD115 /* freeze_spec_constant_value_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = freeze_spec_constant_value_pass.cpp; sourceTree = "<group>"; };
+		A9765C342485758300FDD115 /* replace_invalid_opc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = replace_invalid_opc.h; sourceTree = "<group>"; };
+		A9765C352485758300FDD115 /* local_access_chain_convert_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_access_chain_convert_pass.h; sourceTree = "<group>"; };
+		A9765C362485758300FDD115 /* inst_bindless_check_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_bindless_check_pass.cpp; sourceTree = "<group>"; };
+		A9765C372485758300FDD115 /* local_redundancy_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_redundancy_elimination.cpp; sourceTree = "<group>"; };
+		A9765C382485758300FDD115 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+		A9765C392485758300FDD115 /* instrument_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instrument_pass.cpp; sourceTree = "<group>"; };
+		A9765C3A2485758300FDD115 /* propagator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = propagator.h; sourceTree = "<group>"; };
+		A9765C3B2485758300FDD115 /* instruction_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction_list.h; sourceTree = "<group>"; };
+		A9765C3C2485758300FDD115 /* feature_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = feature_manager.cpp; sourceTree = "<group>"; };
+		A9765C3D2485758300FDD115 /* pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pass.cpp; sourceTree = "<group>"; };
+		A9765C3E2485758300FDD115 /* loop_fission.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fission.cpp; sourceTree = "<group>"; };
+		A9765C3F2485758300FDD115 /* dominator_tree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dominator_tree.cpp; sourceTree = "<group>"; };
+		A9765C402485758300FDD115 /* amd_ext_to_khr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amd_ext_to_khr.h; sourceTree = "<group>"; };
+		A9765C412485758300FDD115 /* merge_return_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = merge_return_pass.cpp; sourceTree = "<group>"; };
+		A9765C422485758300FDD115 /* ir_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_context.h; sourceTree = "<group>"; };
+		A9765C432485758300FDD115 /* eliminate_dead_constant_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_constant_pass.cpp; sourceTree = "<group>"; };
+		A9765C442485758300FDD115 /* cfg_cleanup_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_cleanup_pass.cpp; sourceTree = "<group>"; };
+		A9765C452485758300FDD115 /* wrap_opkill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_opkill.cpp; sourceTree = "<group>"; };
+		A9765C462485758300FDD115 /* const_folding_rules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = const_folding_rules.cpp; sourceTree = "<group>"; };
+		A9765C472485758300FDD115 /* loop_unroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_unroller.h; sourceTree = "<group>"; };
+		A9765C482485758300FDD115 /* strip_debug_info_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_debug_info_pass.cpp; sourceTree = "<group>"; };
+		A9765C492485758300FDD115 /* ssa_rewrite_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ssa_rewrite_pass.cpp; sourceTree = "<group>"; };
+		A9765C4A2485758300FDD115 /* loop_dependence.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_dependence.cpp; sourceTree = "<group>"; };
+		A9765C4B2485758300FDD115 /* unify_const_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unify_const_pass.h; sourceTree = "<group>"; };
+		A9765C4C2485758300FDD115 /* ir_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_loader.h; sourceTree = "<group>"; };
+		A9765C4D2485758300FDD115 /* inst_debug_printf_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_debug_printf_pass.cpp; sourceTree = "<group>"; };
+		A9765C4E2485758300FDD115 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = "<group>"; };
+		A9765C4F2485758300FDD115 /* fold_spec_constant_op_and_composite_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fold_spec_constant_op_and_composite_pass.h; sourceTree = "<group>"; };
+		A9765C502485758300FDD115 /* mem_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mem_pass.cpp; sourceTree = "<group>"; };
+		A9765C512485758300FDD115 /* basic_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basic_block.h; sourceTree = "<group>"; };
+		A9765C522485758300FDD115 /* remove_duplicates_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = remove_duplicates_pass.cpp; sourceTree = "<group>"; };
+		A9765C532485758300FDD115 /* dead_variable_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_variable_elimination.cpp; sourceTree = "<group>"; };
+		A9765C542485758300FDD115 /* block_merge_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block_merge_pass.h; sourceTree = "<group>"; };
+		A9765C552485758400FDD115 /* module.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = module.cpp; sourceTree = "<group>"; };
+		A9765C562485758400FDD115 /* debug_info_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug_info_manager.h; sourceTree = "<group>"; };
+		A9765C572485758400FDD115 /* fold_spec_constant_op_and_composite_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fold_spec_constant_op_and_composite_pass.cpp; sourceTree = "<group>"; };
+		A9765C582485758400FDD115 /* loop_unswitch_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_unswitch_pass.cpp; sourceTree = "<group>"; };
+		A9765C592485758400FDD115 /* unify_const_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unify_const_pass.cpp; sourceTree = "<group>"; };
+		A9765C5A2485758400FDD115 /* type_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = type_manager.cpp; sourceTree = "<group>"; };
+		A9765C5B2485758400FDD115 /* generate_webgpu_initializers_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generate_webgpu_initializers_pass.cpp; sourceTree = "<group>"; };
+		A9765C5C2485758400FDD115 /* private_to_local_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = private_to_local_pass.h; sourceTree = "<group>"; };
+		A9765C5D2485758400FDD115 /* convert_to_half_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convert_to_half_pass.h; sourceTree = "<group>"; };
+		A9765C5E2485758400FDD115 /* relax_float_ops_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = relax_float_ops_pass.h; sourceTree = "<group>"; };
+		A9765C5F2485758400FDD115 /* inline_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_pass.cpp; sourceTree = "<group>"; };
+		A9765C602485758400FDD115 /* def_use_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = def_use_manager.h; sourceTree = "<group>"; };
+		A9765C612485758400FDD115 /* ir_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ir_loader.cpp; sourceTree = "<group>"; };
+		A9765C622485758400FDD115 /* cfg_cleanup_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_cleanup_pass.h; sourceTree = "<group>"; };
+		A9765C632485758400FDD115 /* licm_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = licm_pass.cpp; sourceTree = "<group>"; };
+		A9765C642485758400FDD115 /* eliminate_dead_functions_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_functions_pass.cpp; sourceTree = "<group>"; };
+		A9765C652485758400FDD115 /* local_redundancy_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_redundancy_elimination.h; sourceTree = "<group>"; };
+		A9765C662485758400FDD115 /* split_invalid_unreachable_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = split_invalid_unreachable_pass.cpp; sourceTree = "<group>"; };
+		A9765C672485758400FDD115 /* loop_peeling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_peeling.h; sourceTree = "<group>"; };
+		A9765C682485758400FDD115 /* vector_dce.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vector_dce.cpp; sourceTree = "<group>"; };
+		A9765C692485758400FDD115 /* block_merge_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = block_merge_util.h; sourceTree = "<group>"; };
+		A9765C6A2485758400FDD115 /* loop_unroller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_unroller.cpp; sourceTree = "<group>"; };
+		A9765C6B2485758400FDD115 /* desc_sroa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = desc_sroa.h; sourceTree = "<group>"; };
+		A9765C6C2485758400FDD115 /* constants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = constants.cpp; sourceTree = "<group>"; };
+		A9765C6D2485758400FDD115 /* loop_fusion_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fusion_pass.h; sourceTree = "<group>"; };
+		A9765C6E2485758400FDD115 /* struct_cfg_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = struct_cfg_analysis.h; sourceTree = "<group>"; };
+		A9765C6F2485758400FDD115 /* inst_buff_addr_check_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inst_buff_addr_check_pass.cpp; sourceTree = "<group>"; };
+		A9765C702485758400FDD115 /* def_use_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = def_use_manager.cpp; sourceTree = "<group>"; };
+		A9765C712485758400FDD115 /* wrap_opkill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_opkill.h; sourceTree = "<group>"; };
+		A9765C722485758400FDD115 /* strip_reflect_info_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strip_reflect_info_pass.cpp; sourceTree = "<group>"; };
+		A9765C732485758400FDD115 /* decoration_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoration_manager.h; sourceTree = "<group>"; };
+		A9765C742485758400FDD115 /* ccp_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ccp_pass.cpp; sourceTree = "<group>"; };
+		A9765C752485758400FDD115 /* process_lines_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = process_lines_pass.h; sourceTree = "<group>"; };
+		A9765C762485758400FDD115 /* local_single_block_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = local_single_block_elim_pass.h; sourceTree = "<group>"; };
+		A9765C772485758400FDD115 /* pch_source_opt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch_source_opt.cpp; sourceTree = "<group>"; };
+		A9765C782485758400FDD115 /* inst_buff_addr_check_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_buff_addr_check_pass.h; sourceTree = "<group>"; };
+		A9765C792485758400FDD115 /* strength_reduction_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strength_reduction_pass.h; sourceTree = "<group>"; };
+		A9765C7A2485758400FDD115 /* aggressive_dead_code_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = aggressive_dead_code_elim_pass.cpp; sourceTree = "<group>"; };
+		A9765C7B2485758400FDD115 /* eliminate_dead_functions_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_functions_util.cpp; sourceTree = "<group>"; };
+		A9765C7C2485758400FDD115 /* inst_debug_printf_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_debug_printf_pass.h; sourceTree = "<group>"; };
+		A9765C7D2485758400FDD115 /* simplification_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simplification_pass.cpp; sourceTree = "<group>"; };
+		A9765C7E2485758400FDD115 /* dead_branch_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_branch_elim_pass.cpp; sourceTree = "<group>"; };
+		A9765C7F2485758400FDD115 /* flatten_decoration_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = flatten_decoration_pass.cpp; sourceTree = "<group>"; };
+		A9765C802485758400FDD115 /* dead_insert_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_insert_elim_pass.h; sourceTree = "<group>"; };
+		A9765C812485758400FDD115 /* folding_rules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = folding_rules.cpp; sourceTree = "<group>"; };
+		A9765C822485758400FDD115 /* freeze_spec_constant_value_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = freeze_spec_constant_value_pass.h; sourceTree = "<group>"; };
+		A9765C832485758400FDD115 /* ir_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ir_context.cpp; sourceTree = "<group>"; };
+		A9765C842485758400FDD115 /* instrument_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instrument_pass.h; sourceTree = "<group>"; };
+		A9765C852485758400FDD115 /* mem_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mem_pass.h; sourceTree = "<group>"; };
+		A9765C862485758400FDD115 /* loop_descriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_descriptor.cpp; sourceTree = "<group>"; };
+		A9765C872485758400FDD115 /* eliminate_dead_members_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_members_pass.h; sourceTree = "<group>"; };
+		A9765C882485758400FDD115 /* function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function.cpp; sourceTree = "<group>"; };
+		A9765C892485758400FDD115 /* instruction_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction_list.cpp; sourceTree = "<group>"; };
+		A9765C8A2485758400FDD115 /* composite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = composite.cpp; sourceTree = "<group>"; };
+		A9765C8B2485758400FDD115 /* convert_to_half_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = convert_to_half_pass.cpp; sourceTree = "<group>"; };
+		A9765C8C2485758400FDD115 /* process_lines_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = process_lines_pass.cpp; sourceTree = "<group>"; };
+		A9765C8D2485758400FDD115 /* inline_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_pass.h; sourceTree = "<group>"; };
+		A9765C8E2485758400FDD115 /* loop_dependence.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_dependence.h; sourceTree = "<group>"; };
+		A9765C8F2485758400FDD115 /* value_number_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = value_number_table.h; sourceTree = "<group>"; };
+		A9765C902485758400FDD115 /* flatten_decoration_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = flatten_decoration_pass.h; sourceTree = "<group>"; };
+		A9765C912485758400FDD115 /* if_conversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = if_conversion.cpp; sourceTree = "<group>"; };
+		A9765C922485758400FDD115 /* debug_info_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debug_info_manager.cpp; sourceTree = "<group>"; };
+		A9765C932485758400FDD115 /* inline_exhaustive_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inline_exhaustive_pass.h; sourceTree = "<group>"; };
+		A9765C942485758400FDD115 /* constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = constants.h; sourceTree = "<group>"; };
+		A9765C952485758400FDD115 /* eliminate_dead_members_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = eliminate_dead_members_pass.cpp; sourceTree = "<group>"; };
+		A9765C962485758400FDD115 /* strength_reduction_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = strength_reduction_pass.cpp; sourceTree = "<group>"; };
+		A9765C972485758400FDD115 /* desc_sroa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = desc_sroa.cpp; sourceTree = "<group>"; };
+		A9765C982485758400FDD115 /* block_merge_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = block_merge_util.cpp; sourceTree = "<group>"; };
+		A9765C992485758400FDD115 /* upgrade_memory_model.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = upgrade_memory_model.h; sourceTree = "<group>"; };
+		A9765C9A2485758400FDD115 /* copy_prop_arrays.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = copy_prop_arrays.cpp; sourceTree = "<group>"; };
+		A9765C9B2485758400FDD115 /* pass_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pass_manager.cpp; sourceTree = "<group>"; };
+		A9765C9C2485758400FDD115 /* inline_exhaustive_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_exhaustive_pass.cpp; sourceTree = "<group>"; };
+		A9765C9D2485758400FDD115 /* loop_fission.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_fission.h; sourceTree = "<group>"; };
+		A9765C9E2485758400FDD115 /* workaround1209.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = workaround1209.h; sourceTree = "<group>"; };
+		A9765C9F2485758400FDD115 /* loop_fusion_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fusion_pass.cpp; sourceTree = "<group>"; };
+		A9765CA02485758400FDD115 /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log.h; sourceTree = "<group>"; };
+		A9765CA12485758400FDD115 /* split_invalid_unreachable_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = split_invalid_unreachable_pass.h; sourceTree = "<group>"; };
+		A9765CA22485758400FDD115 /* copy_prop_arrays.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copy_prop_arrays.h; sourceTree = "<group>"; };
+		A9765CA32485758400FDD115 /* eliminate_dead_constant_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_constant_pass.h; sourceTree = "<group>"; };
+		A9765CA42485758400FDD115 /* dead_insert_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dead_insert_elim_pass.cpp; sourceTree = "<group>"; };
+		A9765CA52485758400FDD115 /* ssa_rewrite_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ssa_rewrite_pass.h; sourceTree = "<group>"; };
+		A9765CA62485758400FDD115 /* scalar_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_analysis.cpp; sourceTree = "<group>"; };
+		A9765CA72485758400FDD115 /* dead_variable_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_variable_elimination.h; sourceTree = "<group>"; };
+		A9765CA82485758400FDD115 /* block_merge_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = block_merge_pass.cpp; sourceTree = "<group>"; };
+		A9765CA92485758400FDD115 /* dominator_analysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dominator_analysis.h; sourceTree = "<group>"; };
+		A9765CAA2485758400FDD115 /* pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pass.h; sourceTree = "<group>"; };
+		A9765CAB2485758400FDD115 /* folding_rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = folding_rules.h; sourceTree = "<group>"; };
+		A9765CAC2485758400FDD115 /* eliminate_dead_functions_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_functions_pass.h; sourceTree = "<group>"; };
+		A9765CAD2485758400FDD115 /* eliminate_dead_functions_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eliminate_dead_functions_util.h; sourceTree = "<group>"; };
+		A9765CAE2485758400FDD115 /* fold.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fold.h; sourceTree = "<group>"; };
+		A9765CAF2485758400FDD115 /* local_single_store_elim_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_single_store_elim_pass.cpp; sourceTree = "<group>"; };
+		A9765CB02485758400FDD115 /* dead_branch_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dead_branch_elim_pass.h; sourceTree = "<group>"; };
+		A9765CB12485758400FDD115 /* private_to_local_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = private_to_local_pass.cpp; sourceTree = "<group>"; };
+		A9765CB22485758400FDD115 /* scalar_analysis_nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_analysis_nodes.h; sourceTree = "<group>"; };
+		A9765CB32485758400FDD115 /* propagator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = propagator.cpp; sourceTree = "<group>"; };
+		A9765CB42485758400FDD115 /* fix_storage_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fix_storage_class.h; sourceTree = "<group>"; };
+		A9765CB52485758400FDD115 /* loop_dependence_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_dependence_helpers.cpp; sourceTree = "<group>"; };
+		A9765CB62485758400FDD115 /* set_spec_constant_default_value_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = set_spec_constant_default_value_pass.cpp; sourceTree = "<group>"; };
+		A9765CB72485758400FDD115 /* passes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = passes.h; sourceTree = "<group>"; };
+		A9765CB82485758400FDD115 /* fold.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fold.cpp; sourceTree = "<group>"; };
+		A9765CB92485758400FDD115 /* amd_ext_to_khr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = amd_ext_to_khr.cpp; sourceTree = "<group>"; };
+		A9765CBA2485758400FDD115 /* strip_reflect_info_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strip_reflect_info_pass.h; sourceTree = "<group>"; };
+		A9765CBB2485758400FDD115 /* scalar_replacement_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_replacement_pass.cpp; sourceTree = "<group>"; };
+		A9765CBC2485758400FDD115 /* simplification_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simplification_pass.h; sourceTree = "<group>"; };
+		A9765CBD2485758400FDD115 /* remove_duplicates_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = remove_duplicates_pass.h; sourceTree = "<group>"; };
+		A9765CBE2485758400FDD115 /* redundancy_elimination.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = redundancy_elimination.cpp; sourceTree = "<group>"; };
+		A9765CBF2485758400FDD115 /* reflect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reflect.h; sourceTree = "<group>"; };
+		A9765CC02485758400FDD115 /* workaround1209.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = workaround1209.cpp; sourceTree = "<group>"; };
+		A9765CC12485758400FDD115 /* null_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = null_pass.h; sourceTree = "<group>"; };
+		A9765CC22485758400FDD115 /* relax_float_ops_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = relax_float_ops_pass.cpp; sourceTree = "<group>"; };
+		A9765CC32485758400FDD115 /* const_folding_rules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = const_folding_rules.h; sourceTree = "<group>"; };
+		A9765CC42485758400FDD115 /* scalar_replacement_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scalar_replacement_pass.h; sourceTree = "<group>"; };
+		A9765CC52485758400FDD115 /* instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction.cpp; sourceTree = "<group>"; };
+		A9765CC62485758400FDD115 /* pch_source_opt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch_source_opt.h; sourceTree = "<group>"; };
+		A9765CC72485758400FDD115 /* reduce_load_size.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = reduce_load_size.cpp; sourceTree = "<group>"; };
+		A9765CC82485758400FDD115 /* redundancy_elimination.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = redundancy_elimination.h; sourceTree = "<group>"; };
+		A9765CC92485758400FDD115 /* fix_storage_class.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fix_storage_class.cpp; sourceTree = "<group>"; };
+		A9765CCA2485758400FDD115 /* value_number_table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = value_number_table.cpp; sourceTree = "<group>"; };
+		A9765CCB2485758400FDD115 /* inline_opaque_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inline_opaque_pass.cpp; sourceTree = "<group>"; };
+		A9765CCC2485758400FDD115 /* replace_invalid_opc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = replace_invalid_opc.cpp; sourceTree = "<group>"; };
+		A9765CCD2485758400FDD115 /* loop_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_utils.h; sourceTree = "<group>"; };
+		A9765CCE2485758400FDD115 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = module.h; sourceTree = "<group>"; };
+		A9765CCF2485758400FDD115 /* dominator_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dominator_analysis.cpp; sourceTree = "<group>"; };
+		A9765CD02485758400FDD115 /* decompose_initialized_variables_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = decompose_initialized_variables_pass.cpp; sourceTree = "<group>"; };
+		A9765CD12485758400FDD115 /* ir_builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ir_builder.h; sourceTree = "<group>"; };
+		A9765CD22485758400FDD115 /* loop_unswitch_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_unswitch_pass.h; sourceTree = "<group>"; };
+		A9765CD32485758400FDD115 /* cfg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg.h; sourceTree = "<group>"; };
+		A9765CD42485758400FDD115 /* code_sink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = code_sink.h; sourceTree = "<group>"; };
+		A9765CD52485758400FDD115 /* loop_descriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = loop_descriptor.h; sourceTree = "<group>"; };
+		A9765CD62485758400FDD115 /* generate_webgpu_initializers_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = generate_webgpu_initializers_pass.h; sourceTree = "<group>"; };
+		A9765CD72485758400FDD115 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
+		A9765CD82485758400FDD115 /* aggressive_dead_code_elim_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aggressive_dead_code_elim_pass.h; sourceTree = "<group>"; };
+		A9765CD92485758400FDD115 /* struct_cfg_analysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = struct_cfg_analysis.cpp; sourceTree = "<group>"; };
+		A9765CDA2485758400FDD115 /* vector_dce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_dce.h; sourceTree = "<group>"; };
+		A9765CDB2485758400FDD115 /* combine_access_chains.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = combine_access_chains.h; sourceTree = "<group>"; };
+		A9765CDC2485758400FDD115 /* pass_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pass_manager.h; sourceTree = "<group>"; };
+		A9765CDD2485758400FDD115 /* local_access_chain_convert_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = local_access_chain_convert_pass.cpp; sourceTree = "<group>"; };
+		A9765CDE2485758400FDD115 /* basic_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basic_block.cpp; sourceTree = "<group>"; };
+		A9765CDF2485758400FDD115 /* iterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterator.h; sourceTree = "<group>"; };
+		A9765CE02485758400FDD115 /* licm_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = licm_pass.h; sourceTree = "<group>"; };
+		A9765CE12485758400FDD115 /* build_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = build_module.h; sourceTree = "<group>"; };
+		A9765CE22485758400FDD115 /* ccp_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ccp_pass.h; sourceTree = "<group>"; };
+		A9765CE32485758400FDD115 /* graphics_robust_access_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = graphics_robust_access_pass.cpp; sourceTree = "<group>"; };
+		A9765CE42485758400FDD115 /* decompose_initialized_variables_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decompose_initialized_variables_pass.h; sourceTree = "<group>"; };
+		A9765CE52485758400FDD115 /* function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function.h; sourceTree = "<group>"; };
+		A9765CE62485758400FDD115 /* loop_fusion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_fusion.cpp; sourceTree = "<group>"; };
+		A9765CE72485758400FDD115 /* upgrade_memory_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = upgrade_memory_model.cpp; sourceTree = "<group>"; };
+		A9765CE82485758400FDD115 /* feature_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = feature_manager.h; sourceTree = "<group>"; };
+		A9765CE92485758400FDD115 /* inst_bindless_check_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inst_bindless_check_pass.h; sourceTree = "<group>"; };
+		A9765CEA2485758400FDD115 /* scalar_analysis_simplification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = scalar_analysis_simplification.cpp; sourceTree = "<group>"; };
+		A9765CEB2485758400FDD115 /* set_spec_constant_default_value_pass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = set_spec_constant_default_value_pass.h; sourceTree = "<group>"; };
+		A9765CEC2485758400FDD115 /* dominator_tree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dominator_tree.h; sourceTree = "<group>"; };
+		A9765CED2485758400FDD115 /* legalize_vector_shuffle_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = legalize_vector_shuffle_pass.cpp; sourceTree = "<group>"; };
+		A9765CEE2485758400FDD115 /* type_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type_manager.h; sourceTree = "<group>"; };
+		A9765CEF2485758400FDD115 /* compact_ids_pass.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = compact_ids_pass.cpp; sourceTree = "<group>"; };
+		A9765CF02485758400FDD115 /* loop_peeling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = loop_peeling.cpp; sourceTree = "<group>"; };
+		A9765CF12485758400FDD115 /* table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = table.h; sourceTree = "<group>"; };
+		A9765DB22485758500FDD115 /* ext_inst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ext_inst.h; sourceTree = "<group>"; };
+		A9765DB32485758500FDD115 /* diagnostic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = diagnostic.cpp; sourceTree = "<group>"; };
+		A9765DB42485758500FDD115 /* latest_version_spirv_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_spirv_header.h; sourceTree = "<group>"; };
+		A9765DB52485758500FDD115 /* libspirv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libspirv.cpp; sourceTree = "<group>"; };
+		A9765DB62485758500FDD115 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
+		A9765DB72485758500FDD115 /* spirv_optimizer_options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_optimizer_options.h; sourceTree = "<group>"; };
+		A9765DB82485758500FDD115 /* opcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opcode.h; sourceTree = "<group>"; };
+		A9765DB92485758500FDD115 /* operand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = operand.cpp; sourceTree = "<group>"; };
+		A9765DBA2485758500FDD115 /* latest_version_glsl_std_450_header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = latest_version_glsl_std_450_header.h; sourceTree = "<group>"; };
+		A9765DBB2485758500FDD115 /* extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extensions.h; sourceTree = "<group>"; };
+		A9765DBC2485758500FDD115 /* disassemble.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = disassemble.cpp; sourceTree = "<group>"; };
+		A9765DBD2485758500FDD115 /* binary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = binary.h; sourceTree = "<group>"; };
+		A9765DBE2485758500FDD115 /* text_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_handler.cpp; sourceTree = "<group>"; };
+		A9765DC02485758500FDD115 /* validate_annotation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_annotation.cpp; sourceTree = "<group>"; };
+		A9765DC12485758500FDD115 /* validate_misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_misc.cpp; sourceTree = "<group>"; };
+		A9765DC22485758500FDD115 /* validate_cfg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_cfg.cpp; sourceTree = "<group>"; };
+		A9765DC32485758500FDD115 /* validate_capability.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_capability.cpp; sourceTree = "<group>"; };
+		A9765DC42485758500FDD115 /* construct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = construct.h; sourceTree = "<group>"; };
+		A9765DC52485758500FDD115 /* validate_barriers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_barriers.cpp; sourceTree = "<group>"; };
+		A9765DC62485758500FDD115 /* validate_non_uniform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_non_uniform.cpp; sourceTree = "<group>"; };
+		A9765DC72485758500FDD115 /* validate_scopes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_scopes.cpp; sourceTree = "<group>"; };
+		A9765DC82485758500FDD115 /* validate_atomics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_atomics.cpp; sourceTree = "<group>"; };
+		A9765DC92485758500FDD115 /* basic_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basic_block.h; sourceTree = "<group>"; };
+		A9765DCA2485758500FDD115 /* validate_instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_instruction.cpp; sourceTree = "<group>"; };
+		A9765DCB2485758500FDD115 /* validate_decorations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_decorations.cpp; sourceTree = "<group>"; };
+		A9765DCC2485758500FDD115 /* validate_debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_debug.cpp; sourceTree = "<group>"; };
+		A9765DCD2485758500FDD115 /* validate_builtins.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_builtins.cpp; sourceTree = "<group>"; };
+		A9765DCE2485758500FDD115 /* validate_interfaces.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_interfaces.cpp; sourceTree = "<group>"; };
+		A9765DCF2485758500FDD115 /* validate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate.cpp; sourceTree = "<group>"; };
+		A9765DD02485758500FDD115 /* validation_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validation_state.h; sourceTree = "<group>"; };
+		A9765DD12485758500FDD115 /* validate_constants.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_constants.cpp; sourceTree = "<group>"; };
+		A9765DD22485758500FDD115 /* validate_bitwise.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_bitwise.cpp; sourceTree = "<group>"; };
+		A9765DD32485758500FDD115 /* validate_extensions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_extensions.cpp; sourceTree = "<group>"; };
+		A9765DD42485758500FDD115 /* construct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = construct.cpp; sourceTree = "<group>"; };
+		A9765DD52485758500FDD115 /* function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = function.cpp; sourceTree = "<group>"; };
+		A9765DD62485758500FDD115 /* validate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate.h; sourceTree = "<group>"; };
+		A9765DD72485758500FDD115 /* validate_adjacency.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_adjacency.cpp; sourceTree = "<group>"; };
+		A9765DD82485758500FDD115 /* validate_conversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_conversion.cpp; sourceTree = "<group>"; };
+		A9765DD92485758500FDD115 /* validate_small_type_uses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_small_type_uses.cpp; sourceTree = "<group>"; };
+		A9765DDA2485758500FDD115 /* validate_scopes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate_scopes.h; sourceTree = "<group>"; };
+		A9765DDB2485758500FDD115 /* validate_id.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_id.cpp; sourceTree = "<group>"; };
+		A9765DDC2485758500FDD115 /* validate_memory_semantics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = validate_memory_semantics.h; sourceTree = "<group>"; };
+		A9765DDD2485758500FDD115 /* validate_arithmetics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_arithmetics.cpp; sourceTree = "<group>"; };
+		A9765DDE2485758500FDD115 /* validate_mode_setting.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_mode_setting.cpp; sourceTree = "<group>"; };
+		A9765DDF2485758500FDD115 /* validate_memory_semantics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_memory_semantics.cpp; sourceTree = "<group>"; };
+		A9765DE02485758500FDD115 /* validate_logicals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_logicals.cpp; sourceTree = "<group>"; };
+		A9765DE12485758500FDD115 /* validate_derivatives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_derivatives.cpp; sourceTree = "<group>"; };
+		A9765DE22485758500FDD115 /* validate_memory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_memory.cpp; sourceTree = "<group>"; };
+		A9765DE32485758500FDD115 /* validate_image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_image.cpp; sourceTree = "<group>"; };
+		A9765DE42485758500FDD115 /* validate_literals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_literals.cpp; sourceTree = "<group>"; };
+		A9765DE52485758500FDD115 /* instruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = instruction.cpp; sourceTree = "<group>"; };
+		A9765DE62485758500FDD115 /* validate_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_type.cpp; sourceTree = "<group>"; };
+		A9765DE72485758500FDD115 /* instruction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = instruction.h; sourceTree = "<group>"; };
+		A9765DE82485758500FDD115 /* validate_execution_limitations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_execution_limitations.cpp; sourceTree = "<group>"; };
+		A9765DE92485758500FDD115 /* validate_layout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_layout.cpp; sourceTree = "<group>"; };
+		A9765DEA2485758500FDD115 /* basic_block.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = basic_block.cpp; sourceTree = "<group>"; };
+		A9765DEB2485758500FDD115 /* validate_function.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_function.cpp; sourceTree = "<group>"; };
+		A9765DEC2485758500FDD115 /* function.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = function.h; sourceTree = "<group>"; };
+		A9765DED2485758500FDD115 /* validate_composites.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_composites.cpp; sourceTree = "<group>"; };
+		A9765DEE2485758500FDD115 /* validation_state.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validation_state.cpp; sourceTree = "<group>"; };
+		A9765DEF2485758500FDD115 /* validate_primitives.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = validate_primitives.cpp; sourceTree = "<group>"; };
+		A9765DF02485758500FDD115 /* decoration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decoration.h; sourceTree = "<group>"; };
 		A9C2104521D14FD7006BA2D3 /* fetchDependencies */ = {isa = PBXFileReference; lastKnownFileType = text; path = fetchDependencies; sourceTree = "<group>"; };
 		A9C2104721D15843006BA2D3 /* ExternalRevisions */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ExternalRevisions; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -1634,448 +1652,6 @@
 			path = External;
 			sourceTree = "<group>";
 		};
-		A941583E243667F600566F16 /* source */ = {
-			isa = PBXGroup;
-			children = (
-				A941583F243667F600566F16 /* spirv_target_env.cpp */,
-				A9415840243667F600566F16 /* extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json */,
-				A9415841243667F600566F16 /* spirv_fuzzer_options.h */,
-				A9415842243667F600566F16 /* assembly_grammar.h */,
-				A9415843243667F600566F16 /* enum_set.h */,
-				A9415844243667F600566F16 /* CMakeLists.txt */,
-				A9415845243667F600566F16 /* extinst.spv-amd-shader-ballot.grammar.json */,
-				A9415846243667F600566F16 /* text.cpp */,
-				A9415847243667F600566F16 /* assembly_grammar.cpp */,
-				A9415848243667F600566F16 /* text.h */,
-				A9415849243667F600566F16 /* extensions.cpp */,
-				A941584A243667F600566F16 /* pch_source.cpp */,
-				A941584B243667F600566F16 /* util */,
-				A941585A243667F600566F16 /* spirv_target_env.h */,
-				A941585B243667F600566F16 /* table.cpp */,
-				A941585C243667F600566F16 /* extinst.opencl.debuginfo.100.grammar.json */,
-				A941585D243667F600566F16 /* reduce */,
-				A9415894243667F600566F16 /* latest_version_opencl_std_header.h */,
-				A9415895243667F600566F16 /* spirv_optimizer_options.cpp */,
-				A9415896243667F600566F16 /* cfa.h */,
-				A9415897243667F600566F16 /* pch_source.h */,
-				A9415898243667F600566F16 /* enum_string_mapping.h */,
-				A9415899243667F600566F16 /* spirv_fuzzer_options.cpp */,
-				A941589A243667F600566F16 /* spirv_reducer_options.h */,
-				A941589B243667F600566F16 /* spirv_validator_options.cpp */,
-				A941589C243667F600566F16 /* extinst.spv-amd-shader-trinary-minmax.grammar.json */,
-				A941589D243667F600566F16 /* print.cpp */,
-				A941589E243667F600566F16 /* spirv_definition.h */,
-				A941589F243667F600566F16 /* operand.h */,
-				A94158A0243667F600566F16 /* spirv_endian.cpp */,
-				A94158A1243667F600566F16 /* macro.h */,
-				A94158A2243667F600566F16 /* spirv_constant.h */,
-				A94158A3243667F600566F16 /* extinst.spv-amd-gcn-shader.grammar.json */,
-				A94158A4243667F600566F16 /* binary.cpp */,
-				A94158A5243667F600566F16 /* spirv_validator_options.h */,
-				A94158A6243667F600566F16 /* enum_string_mapping.cpp */,
-				A94158A7243667F600566F16 /* text_handler.h */,
-				A94158A8243667F600566F16 /* parsed_operand.h */,
-				A94158A9243667F600566F16 /* name_mapper.h */,
-				A94158AA243667F600566F16 /* spirv_reducer_options.cpp */,
-				A94158AB243667F600566F16 /* parsed_operand.cpp */,
-				A94158AC243667F600566F16 /* diagnostic.h */,
-				A94158AD243667F600566F16 /* spirv_endian.h */,
-				A94158AE243667F600566F16 /* name_mapper.cpp */,
-				A94158AF243667F600566F16 /* extinst.debuginfo.grammar.json */,
-				A94158B0243667F600566F16 /* link */,
-				A94158B3243667F600566F16 /* software_version.cpp */,
-				A94158B4243667F600566F16 /* opcode.cpp */,
-				A94158B5243667F600566F16 /* print.h */,
-				A94158B6243667F600566F16 /* ext_inst.cpp */,
-				A94158B7243667F600566F16 /* disassemble.h */,
-				A94158B8243667F600566F16 /* opt */,
-				A941598F243667F700566F16 /* table.h */,
-				A9415A48243667F700566F16 /* ext_inst.h */,
-				A9415A49243667F700566F16 /* diagnostic.cpp */,
-				A9415A4A243667F700566F16 /* latest_version_spirv_header.h */,
-				A9415A4B243667F700566F16 /* libspirv.cpp */,
-				A9415A4C243667F700566F16 /* instruction.h */,
-				A9415A4D243667F700566F16 /* spirv_optimizer_options.h */,
-				A9415A4E243667F700566F16 /* opcode.h */,
-				A9415A4F243667F700566F16 /* operand.cpp */,
-				A9415A50243667F700566F16 /* latest_version_glsl_std_450_header.h */,
-				A9415A51243667F700566F16 /* extensions.h */,
-				A9415A52243667F700566F16 /* disassemble.cpp */,
-				A9415A53243667F700566F16 /* binary.h */,
-				A9415A54243667F700566F16 /* text_handler.cpp */,
-				A9415A55243667F700566F16 /* val */,
-			);
-			path = source;
-			sourceTree = "<group>";
-		};
-		A941584B243667F600566F16 /* util */ = {
-			isa = PBXGroup;
-			children = (
-				A941584C243667F600566F16 /* parse_number.h */,
-				A941584D243667F600566F16 /* ilist_node.h */,
-				A941584E243667F600566F16 /* make_unique.h */,
-				A941584F243667F600566F16 /* string_utils.h */,
-				A9415850243667F600566F16 /* small_vector.h */,
-				A9415851243667F600566F16 /* timer.cpp */,
-				A9415852243667F600566F16 /* timer.h */,
-				A9415853243667F600566F16 /* string_utils.cpp */,
-				A9415854243667F600566F16 /* bit_vector.h */,
-				A9415855243667F600566F16 /* bitutils.h */,
-				A9415856243667F600566F16 /* hex_float.h */,
-				A9415857243667F600566F16 /* parse_number.cpp */,
-				A9415858243667F600566F16 /* bit_vector.cpp */,
-				A9415859243667F600566F16 /* ilist.h */,
-			);
-			path = util;
-			sourceTree = "<group>";
-		};
-		A941585D243667F600566F16 /* reduce */ = {
-			isa = PBXGroup;
-			children = (
-				A941585E243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.h */,
-				A941585F243667F600566F16 /* remove_selection_reduction_opportunity.cpp */,
-				A9415860243667F600566F16 /* remove_block_reduction_opportunity.h */,
-				A9415861243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h */,
-				A9415862243667F600566F16 /* reduction_pass.cpp */,
-				A9415863243667F600566F16 /* operand_to_const_reduction_opportunity_finder.cpp */,
-				A9415864243667F600566F16 /* operand_to_const_reduction_opportunity_finder.h */,
-				A9415865243667F600566F16 /* CMakeLists.txt */,
-				A9415866243667F600566F16 /* reduction_util.cpp */,
-				A9415867243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */,
-				A9415868243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h */,
-				A9415869243667F600566F16 /* remove_function_reduction_opportunity_finder.cpp */,
-				A941586A243667F600566F16 /* remove_instruction_reduction_opportunity.h */,
-				A941586B243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */,
-				A941586C243667F600566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */,
-				A941586D243667F600566F16 /* remove_function_reduction_opportunity.cpp */,
-				A941586E243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */,
-				A941586F243667F600566F16 /* remove_selection_reduction_opportunity_finder.cpp */,
-				A9415870243667F600566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */,
-				A9415871243667F600566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h */,
-				A9415872243667F600566F16 /* merge_blocks_reduction_opportunity.cpp */,
-				A9415873243667F600566F16 /* change_operand_reduction_opportunity.cpp */,
-				A9415874243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.h */,
-				A9415875243667F600566F16 /* remove_function_reduction_opportunity.h */,
-				A9415876243667F600566F16 /* change_operand_to_undef_reduction_opportunity.h */,
-				A9415877243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp */,
-				A9415878243667F600566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h */,
-				A9415879243667F600566F16 /* remove_selection_reduction_opportunity.h */,
-				A941587A243667F600566F16 /* remove_instruction_reduction_opportunity.cpp */,
-				A941587B243667F600566F16 /* remove_selection_reduction_opportunity_finder.h */,
-				A941587C243667F600566F16 /* merge_blocks_reduction_opportunity_finder.h */,
-				A941587D243667F600566F16 /* pch_source_reduce.cpp */,
-				A941587E243667F600566F16 /* reducer.cpp */,
-				A941587F243667F600566F16 /* operand_to_undef_reduction_opportunity_finder.cpp */,
-				A9415880243667F600566F16 /* remove_function_reduction_opportunity_finder.h */,
-				A9415881243667F600566F16 /* pch_source_reduce.h */,
-				A9415882243667F600566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h */,
-				A9415883243667F600566F16 /* merge_blocks_reduction_opportunity_finder.cpp */,
-				A9415884243667F600566F16 /* reduction_opportunity.cpp */,
-				A9415885243667F600566F16 /* reducer.h */,
-				A9415886243667F600566F16 /* change_operand_to_undef_reduction_opportunity.cpp */,
-				A9415887243667F600566F16 /* reduction_opportunity.h */,
-				A9415888243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */,
-				A9415889243667F600566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */,
-				A941588A243667F600566F16 /* reduction_opportunity_finder.h */,
-				A941588B243667F600566F16 /* change_operand_reduction_opportunity.h */,
-				A941588C243667F600566F16 /* remove_block_reduction_opportunity_finder.h */,
-				A941588D243667F600566F16 /* remove_block_reduction_opportunity_finder.cpp */,
-				A941588E243667F600566F16 /* reduction_util.h */,
-				A941588F243667F600566F16 /* merge_blocks_reduction_opportunity.h */,
-				A9415890243667F600566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */,
-				A9415891243667F600566F16 /* structured_loop_to_selection_reduction_opportunity.cpp */,
-				A9415892243667F600566F16 /* remove_block_reduction_opportunity.cpp */,
-				A9415893243667F600566F16 /* reduction_pass.h */,
-			);
-			path = reduce;
-			sourceTree = "<group>";
-		};
-		A94158B0243667F600566F16 /* link */ = {
-			isa = PBXGroup;
-			children = (
-				A94158B1243667F600566F16 /* CMakeLists.txt */,
-				A94158B2243667F600566F16 /* linker.cpp */,
-			);
-			path = link;
-			sourceTree = "<group>";
-		};
-		A94158B8243667F600566F16 /* opt */ = {
-			isa = PBXGroup;
-			children = (
-				A94158B9243667F600566F16 /* optimizer.cpp */,
-				A94158BA243667F600566F16 /* if_conversion.h */,
-				A94158BB243667F600566F16 /* register_pressure.cpp */,
-				A94158BC243667F600566F16 /* loop_utils.cpp */,
-				A94158BD243667F600566F16 /* merge_return_pass.h */,
-				A94158BE243667F600566F16 /* inline_opaque_pass.h */,
-				A94158BF243667F600566F16 /* loop_fusion.h */,
-				A94158C0243667F600566F16 /* combine_access_chains.cpp */,
-				A94158C1243667F600566F16 /* build_module.cpp */,
-				A94158C2243667F600566F16 /* composite.h */,
-				A94158C3243667F600566F16 /* compact_ids_pass.h */,
-				A94158C4243667F600566F16 /* register_pressure.h */,
-				A94158C5243667F600566F16 /* tree_iterator.h */,
-				A94158C6243667F600566F16 /* graphics_robust_access_pass.h */,
-				A94158C7243667F600566F16 /* strip_atomic_counter_memory_pass.h */,
-				A94158C8243667F600566F16 /* legalize_vector_shuffle_pass.h */,
-				A94158C9243667F600566F16 /* local_single_store_elim_pass.h */,
-				A94158CA243667F600566F16 /* reduce_load_size.h */,
-				A94158CB243667F600566F16 /* code_sink.cpp */,
-				A94158CC243667F600566F16 /* types.cpp */,
-				A94158CD243667F600566F16 /* scalar_analysis.h */,
-				A94158CE243667F600566F16 /* strip_debug_info_pass.h */,
-				A94158CF243667F600566F16 /* cfg.cpp */,
-				A94158D0243667F600566F16 /* strip_atomic_counter_memory_pass.cpp */,
-				A94158D1243667F600566F16 /* decoration_manager.cpp */,
-				A94158D2243667F600566F16 /* local_single_block_elim_pass.cpp */,
-				A94158D3243667F600566F16 /* freeze_spec_constant_value_pass.cpp */,
-				A94158D4243667F600566F16 /* replace_invalid_opc.h */,
-				A94158D5243667F600566F16 /* local_access_chain_convert_pass.h */,
-				A94158D6243667F600566F16 /* inst_bindless_check_pass.cpp */,
-				A94158D7243667F600566F16 /* local_redundancy_elimination.cpp */,
-				A94158D8243667F600566F16 /* CMakeLists.txt */,
-				A94158D9243667F600566F16 /* instrument_pass.cpp */,
-				A94158DA243667F600566F16 /* propagator.h */,
-				A94158DB243667F600566F16 /* instruction_list.h */,
-				A94158DC243667F600566F16 /* feature_manager.cpp */,
-				A94158DD243667F600566F16 /* pass.cpp */,
-				A94158DE243667F600566F16 /* loop_fission.cpp */,
-				A94158DF243667F600566F16 /* dominator_tree.cpp */,
-				A94158E0243667F600566F16 /* amd_ext_to_khr.h */,
-				A94158E1243667F600566F16 /* merge_return_pass.cpp */,
-				A94158E2243667F600566F16 /* ir_context.h */,
-				A94158E3243667F600566F16 /* eliminate_dead_constant_pass.cpp */,
-				A94158E4243667F600566F16 /* cfg_cleanup_pass.cpp */,
-				A94158E5243667F600566F16 /* wrap_opkill.cpp */,
-				A94158E6243667F600566F16 /* const_folding_rules.cpp */,
-				A94158E7243667F600566F16 /* loop_unroller.h */,
-				A94158E8243667F600566F16 /* strip_debug_info_pass.cpp */,
-				A94158E9243667F600566F16 /* ssa_rewrite_pass.cpp */,
-				A94158EA243667F600566F16 /* loop_dependence.cpp */,
-				A94158EB243667F600566F16 /* unify_const_pass.h */,
-				A94158EC243667F600566F16 /* ir_loader.h */,
-				A94158ED243667F600566F16 /* inst_debug_printf_pass.cpp */,
-				A94158EE243667F600566F16 /* types.h */,
-				A94158EF243667F600566F16 /* fold_spec_constant_op_and_composite_pass.h */,
-				A94158F0243667F600566F16 /* mem_pass.cpp */,
-				A94158F1243667F600566F16 /* basic_block.h */,
-				A94158F2243667F600566F16 /* remove_duplicates_pass.cpp */,
-				A94158F3243667F600566F16 /* dead_variable_elimination.cpp */,
-				A94158F4243667F600566F16 /* block_merge_pass.h */,
-				A94158F5243667F600566F16 /* module.cpp */,
-				A94158F6243667F600566F16 /* fold_spec_constant_op_and_composite_pass.cpp */,
-				A94158F7243667F600566F16 /* loop_unswitch_pass.cpp */,
-				A94158F8243667F600566F16 /* unify_const_pass.cpp */,
-				A94158F9243667F600566F16 /* type_manager.cpp */,
-				A94158FA243667F600566F16 /* generate_webgpu_initializers_pass.cpp */,
-				A94158FB243667F600566F16 /* private_to_local_pass.h */,
-				A94158FC243667F600566F16 /* convert_to_half_pass.h */,
-				A94158FD243667F600566F16 /* relax_float_ops_pass.h */,
-				A94158FE243667F600566F16 /* inline_pass.cpp */,
-				A94158FF243667F600566F16 /* def_use_manager.h */,
-				A9415900243667F600566F16 /* ir_loader.cpp */,
-				A9415901243667F600566F16 /* cfg_cleanup_pass.h */,
-				A9415902243667F600566F16 /* licm_pass.cpp */,
-				A9415903243667F600566F16 /* eliminate_dead_functions_pass.cpp */,
-				A9415904243667F600566F16 /* local_redundancy_elimination.h */,
-				A9415905243667F600566F16 /* split_invalid_unreachable_pass.cpp */,
-				A9415906243667F600566F16 /* loop_peeling.h */,
-				A9415907243667F600566F16 /* vector_dce.cpp */,
-				A9415908243667F600566F16 /* block_merge_util.h */,
-				A9415909243667F600566F16 /* loop_unroller.cpp */,
-				A941590A243667F600566F16 /* desc_sroa.h */,
-				A941590B243667F600566F16 /* constants.cpp */,
-				A941590C243667F600566F16 /* loop_fusion_pass.h */,
-				A941590D243667F600566F16 /* struct_cfg_analysis.h */,
-				A941590E243667F600566F16 /* inst_buff_addr_check_pass.cpp */,
-				A941590F243667F600566F16 /* def_use_manager.cpp */,
-				A9415910243667F600566F16 /* wrap_opkill.h */,
-				A9415911243667F600566F16 /* strip_reflect_info_pass.cpp */,
-				A9415912243667F600566F16 /* decoration_manager.h */,
-				A9415913243667F600566F16 /* ccp_pass.cpp */,
-				A9415914243667F600566F16 /* process_lines_pass.h */,
-				A9415915243667F600566F16 /* local_single_block_elim_pass.h */,
-				A9415916243667F600566F16 /* pch_source_opt.cpp */,
-				A9415917243667F600566F16 /* inst_buff_addr_check_pass.h */,
-				A9415918243667F600566F16 /* strength_reduction_pass.h */,
-				A9415919243667F600566F16 /* aggressive_dead_code_elim_pass.cpp */,
-				A941591A243667F600566F16 /* eliminate_dead_functions_util.cpp */,
-				A941591B243667F600566F16 /* inst_debug_printf_pass.h */,
-				A941591C243667F600566F16 /* simplification_pass.cpp */,
-				A941591D243667F600566F16 /* dead_branch_elim_pass.cpp */,
-				A941591E243667F600566F16 /* flatten_decoration_pass.cpp */,
-				A941591F243667F600566F16 /* dead_insert_elim_pass.h */,
-				A9415920243667F600566F16 /* folding_rules.cpp */,
-				A9415921243667F600566F16 /* freeze_spec_constant_value_pass.h */,
-				A9415922243667F600566F16 /* ir_context.cpp */,
-				A9415923243667F600566F16 /* instrument_pass.h */,
-				A9415924243667F600566F16 /* mem_pass.h */,
-				A9415925243667F600566F16 /* loop_descriptor.cpp */,
-				A9415926243667F600566F16 /* eliminate_dead_members_pass.h */,
-				A9415927243667F600566F16 /* function.cpp */,
-				A9415928243667F600566F16 /* instruction_list.cpp */,
-				A9415929243667F600566F16 /* composite.cpp */,
-				A941592A243667F600566F16 /* convert_to_half_pass.cpp */,
-				A941592B243667F600566F16 /* process_lines_pass.cpp */,
-				A941592C243667F600566F16 /* inline_pass.h */,
-				A941592D243667F600566F16 /* loop_dependence.h */,
-				A941592E243667F600566F16 /* value_number_table.h */,
-				A941592F243667F600566F16 /* flatten_decoration_pass.h */,
-				A9415930243667F600566F16 /* if_conversion.cpp */,
-				A9415931243667F600566F16 /* inline_exhaustive_pass.h */,
-				A9415932243667F600566F16 /* constants.h */,
-				A9415933243667F600566F16 /* eliminate_dead_members_pass.cpp */,
-				A9415934243667F600566F16 /* strength_reduction_pass.cpp */,
-				A9415935243667F600566F16 /* desc_sroa.cpp */,
-				A9415936243667F600566F16 /* block_merge_util.cpp */,
-				A9415937243667F600566F16 /* upgrade_memory_model.h */,
-				A9415938243667F600566F16 /* copy_prop_arrays.cpp */,
-				A9415939243667F600566F16 /* pass_manager.cpp */,
-				A941593A243667F600566F16 /* inline_exhaustive_pass.cpp */,
-				A941593B243667F600566F16 /* loop_fission.h */,
-				A941593C243667F600566F16 /* workaround1209.h */,
-				A941593D243667F600566F16 /* loop_fusion_pass.cpp */,
-				A941593E243667F600566F16 /* log.h */,
-				A941593F243667F600566F16 /* split_invalid_unreachable_pass.h */,
-				A9415940243667F600566F16 /* copy_prop_arrays.h */,
-				A9415941243667F600566F16 /* eliminate_dead_constant_pass.h */,
-				A9415942243667F600566F16 /* dead_insert_elim_pass.cpp */,
-				A9415943243667F600566F16 /* ssa_rewrite_pass.h */,
-				A9415944243667F600566F16 /* scalar_analysis.cpp */,
-				A9415945243667F600566F16 /* dead_variable_elimination.h */,
-				A9415946243667F600566F16 /* block_merge_pass.cpp */,
-				A9415947243667F600566F16 /* dominator_analysis.h */,
-				A9415948243667F600566F16 /* pass.h */,
-				A9415949243667F600566F16 /* folding_rules.h */,
-				A941594A243667F600566F16 /* eliminate_dead_functions_pass.h */,
-				A941594B243667F600566F16 /* eliminate_dead_functions_util.h */,
-				A941594C243667F600566F16 /* fold.h */,
-				A941594D243667F600566F16 /* local_single_store_elim_pass.cpp */,
-				A941594E243667F600566F16 /* dead_branch_elim_pass.h */,
-				A941594F243667F600566F16 /* private_to_local_pass.cpp */,
-				A9415950243667F600566F16 /* scalar_analysis_nodes.h */,
-				A9415951243667F600566F16 /* propagator.cpp */,
-				A9415952243667F600566F16 /* fix_storage_class.h */,
-				A9415953243667F600566F16 /* loop_dependence_helpers.cpp */,
-				A9415954243667F600566F16 /* set_spec_constant_default_value_pass.cpp */,
-				A9415955243667F600566F16 /* passes.h */,
-				A9415956243667F600566F16 /* fold.cpp */,
-				A9415957243667F600566F16 /* amd_ext_to_khr.cpp */,
-				A9415958243667F600566F16 /* strip_reflect_info_pass.h */,
-				A9415959243667F600566F16 /* scalar_replacement_pass.cpp */,
-				A941595A243667F600566F16 /* simplification_pass.h */,
-				A941595B243667F600566F16 /* remove_duplicates_pass.h */,
-				A941595C243667F600566F16 /* redundancy_elimination.cpp */,
-				A941595D243667F600566F16 /* reflect.h */,
-				A941595E243667F600566F16 /* workaround1209.cpp */,
-				A941595F243667F600566F16 /* null_pass.h */,
-				A9415960243667F600566F16 /* relax_float_ops_pass.cpp */,
-				A9415961243667F600566F16 /* const_folding_rules.h */,
-				A9415962243667F600566F16 /* scalar_replacement_pass.h */,
-				A9415963243667F600566F16 /* instruction.cpp */,
-				A9415964243667F600566F16 /* pch_source_opt.h */,
-				A9415965243667F600566F16 /* reduce_load_size.cpp */,
-				A9415966243667F600566F16 /* redundancy_elimination.h */,
-				A9415967243667F600566F16 /* fix_storage_class.cpp */,
-				A9415968243667F600566F16 /* value_number_table.cpp */,
-				A9415969243667F600566F16 /* inline_opaque_pass.cpp */,
-				A941596A243667F600566F16 /* replace_invalid_opc.cpp */,
-				A941596B243667F600566F16 /* loop_utils.h */,
-				A941596C243667F700566F16 /* module.h */,
-				A941596D243667F700566F16 /* dominator_analysis.cpp */,
-				A941596E243667F700566F16 /* decompose_initialized_variables_pass.cpp */,
-				A941596F243667F700566F16 /* ir_builder.h */,
-				A9415970243667F700566F16 /* loop_unswitch_pass.h */,
-				A9415971243667F700566F16 /* cfg.h */,
-				A9415972243667F700566F16 /* code_sink.h */,
-				A9415973243667F700566F16 /* loop_descriptor.h */,
-				A9415974243667F700566F16 /* generate_webgpu_initializers_pass.h */,
-				A9415975243667F700566F16 /* instruction.h */,
-				A9415976243667F700566F16 /* aggressive_dead_code_elim_pass.h */,
-				A9415977243667F700566F16 /* struct_cfg_analysis.cpp */,
-				A9415978243667F700566F16 /* vector_dce.h */,
-				A9415979243667F700566F16 /* combine_access_chains.h */,
-				A941597A243667F700566F16 /* pass_manager.h */,
-				A941597B243667F700566F16 /* local_access_chain_convert_pass.cpp */,
-				A941597C243667F700566F16 /* basic_block.cpp */,
-				A941597D243667F700566F16 /* iterator.h */,
-				A941597E243667F700566F16 /* licm_pass.h */,
-				A941597F243667F700566F16 /* build_module.h */,
-				A9415980243667F700566F16 /* ccp_pass.h */,
-				A9415981243667F700566F16 /* graphics_robust_access_pass.cpp */,
-				A9415982243667F700566F16 /* decompose_initialized_variables_pass.h */,
-				A9415983243667F700566F16 /* function.h */,
-				A9415984243667F700566F16 /* loop_fusion.cpp */,
-				A9415985243667F700566F16 /* upgrade_memory_model.cpp */,
-				A9415986243667F700566F16 /* feature_manager.h */,
-				A9415987243667F700566F16 /* inst_bindless_check_pass.h */,
-				A9415988243667F700566F16 /* scalar_analysis_simplification.cpp */,
-				A9415989243667F700566F16 /* set_spec_constant_default_value_pass.h */,
-				A941598A243667F700566F16 /* dominator_tree.h */,
-				A941598B243667F700566F16 /* legalize_vector_shuffle_pass.cpp */,
-				A941598C243667F700566F16 /* type_manager.h */,
-				A941598D243667F700566F16 /* compact_ids_pass.cpp */,
-				A941598E243667F700566F16 /* loop_peeling.cpp */,
-			);
-			path = opt;
-			sourceTree = "<group>";
-		};
-		A9415A55243667F700566F16 /* val */ = {
-			isa = PBXGroup;
-			children = (
-				A9415A56243667F700566F16 /* validate_annotation.cpp */,
-				A9415A57243667F700566F16 /* validate_misc.cpp */,
-				A9415A58243667F700566F16 /* validate_cfg.cpp */,
-				A9415A59243667F700566F16 /* validate_capability.cpp */,
-				A9415A5A243667F700566F16 /* construct.h */,
-				A9415A5B243667F700566F16 /* validate_barriers.cpp */,
-				A9415A5C243667F700566F16 /* validate_non_uniform.cpp */,
-				A9415A5D243667F700566F16 /* validate_scopes.cpp */,
-				A9415A5E243667F700566F16 /* validate_atomics.cpp */,
-				A9415A5F243667F700566F16 /* basic_block.h */,
-				A9415A60243667F700566F16 /* validate_instruction.cpp */,
-				A9415A61243667F700566F16 /* validate_decorations.cpp */,
-				A9415A62243667F700566F16 /* validate_debug.cpp */,
-				A9415A63243667F700566F16 /* validate_builtins.cpp */,
-				A9415A64243667F700566F16 /* validate_interfaces.cpp */,
-				A9415A65243667F700566F16 /* validate.cpp */,
-				A9415A66243667F700566F16 /* validation_state.h */,
-				A9415A67243667F700566F16 /* validate_constants.cpp */,
-				A9415A68243667F700566F16 /* validate_bitwise.cpp */,
-				A9415A69243667F700566F16 /* validate_extensions.cpp */,
-				A9415A6A243667F700566F16 /* construct.cpp */,
-				A9415A6B243667F700566F16 /* function.cpp */,
-				A9415A6C243667F700566F16 /* validate.h */,
-				A9415A6D243667F700566F16 /* validate_adjacency.cpp */,
-				A9415A6E243667F700566F16 /* validate_conversion.cpp */,
-				A9415A6F243667F700566F16 /* validate_small_type_uses.cpp */,
-				A9415A70243667F700566F16 /* validate_scopes.h */,
-				A9415A71243667F700566F16 /* validate_id.cpp */,
-				A9415A72243667F700566F16 /* validate_memory_semantics.h */,
-				A9415A73243667F700566F16 /* validate_arithmetics.cpp */,
-				A9415A74243667F700566F16 /* validate_mode_setting.cpp */,
-				A9415A75243667F700566F16 /* validate_memory_semantics.cpp */,
-				A9415A76243667F700566F16 /* validate_logicals.cpp */,
-				A9415A77243667F700566F16 /* validate_derivatives.cpp */,
-				A9415A78243667F700566F16 /* validate_memory.cpp */,
-				A9415A79243667F700566F16 /* validate_image.cpp */,
-				A9415A7A243667F700566F16 /* validate_literals.cpp */,
-				A9415A7B243667F700566F16 /* instruction.cpp */,
-				A9415A7C243667F700566F16 /* validate_type.cpp */,
-				A9415A7D243667F700566F16 /* instruction.h */,
-				A9415A7E243667F700566F16 /* validate_execution_limitations.cpp */,
-				A9415A7F243667F700566F16 /* validate_layout.cpp */,
-				A9415A80243667F700566F16 /* basic_block.cpp */,
-				A9415A81243667F700566F16 /* validate_function.cpp */,
-				A9415A82243667F700566F16 /* function.h */,
-				A9415A83243667F700566F16 /* validate_composites.cpp */,
-				A9415A84243667F700566F16 /* validation_state.cpp */,
-				A9415A85243667F700566F16 /* validate_primitives.cpp */,
-				A9415A86243667F700566F16 /* decoration.h */,
-			);
-			path = val;
-			sourceTree = "<group>";
-		};
 		A95D90A623A7F1E500CBCC60 /* glslang */ = {
 			isa = PBXGroup;
 			children = (
@@ -2278,7 +1854,7 @@
 		A972A82421CECC410013AB25 /* SPIRV-Tools */ = {
 			isa = PBXGroup;
 			children = (
-				A941583E243667F600566F16 /* source */,
+				A9765B9A2485758300FDD115 /* source */,
 			);
 			name = "SPIRV-Tools";
 			path = "glslang/External/spirv-tools";
@@ -2329,6 +1905,454 @@
 			path = "SPIRV-Cross";
 			sourceTree = "<group>";
 		};
+		A9765B9A2485758300FDD115 /* source */ = {
+			isa = PBXGroup;
+			children = (
+				A9765B9B2485758300FDD115 /* spirv_target_env.cpp */,
+				A9765B9C2485758300FDD115 /* extinst.spv-amd-shader-explicit-vertex-parameter.grammar.json */,
+				A9765B9D2485758300FDD115 /* spirv_fuzzer_options.h */,
+				A9765B9E2485758300FDD115 /* assembly_grammar.h */,
+				A9765B9F2485758300FDD115 /* enum_set.h */,
+				A9765BA02485758300FDD115 /* CMakeLists.txt */,
+				A9765BA12485758300FDD115 /* extinst.spv-amd-shader-ballot.grammar.json */,
+				A9765BA22485758300FDD115 /* text.cpp */,
+				A9765BA32485758300FDD115 /* assembly_grammar.cpp */,
+				A9765BA42485758300FDD115 /* text.h */,
+				A9765BA52485758300FDD115 /* extensions.cpp */,
+				A9765BA62485758300FDD115 /* pch_source.cpp */,
+				A9765BA72485758300FDD115 /* util */,
+				A9765BB62485758300FDD115 /* spirv_target_env.h */,
+				A9765BB72485758300FDD115 /* table.cpp */,
+				A9765BB82485758300FDD115 /* extinst.opencl.debuginfo.100.grammar.json */,
+				A9765BB92485758300FDD115 /* reduce */,
+				A9765BF42485758300FDD115 /* latest_version_opencl_std_header.h */,
+				A9765BF52485758300FDD115 /* spirv_optimizer_options.cpp */,
+				A9765BF62485758300FDD115 /* cfa.h */,
+				A9765BF72485758300FDD115 /* pch_source.h */,
+				A9765BF82485758300FDD115 /* enum_string_mapping.h */,
+				A9765BF92485758300FDD115 /* spirv_fuzzer_options.cpp */,
+				A9765BFA2485758300FDD115 /* spirv_reducer_options.h */,
+				A9765BFB2485758300FDD115 /* spirv_validator_options.cpp */,
+				A9765BFC2485758300FDD115 /* extinst.spv-amd-shader-trinary-minmax.grammar.json */,
+				A9765BFD2485758300FDD115 /* print.cpp */,
+				A9765BFE2485758300FDD115 /* spirv_definition.h */,
+				A9765BFF2485758300FDD115 /* operand.h */,
+				A9765C002485758300FDD115 /* spirv_endian.cpp */,
+				A9765C012485758300FDD115 /* macro.h */,
+				A9765C022485758300FDD115 /* spirv_constant.h */,
+				A9765C032485758300FDD115 /* extinst.spv-amd-gcn-shader.grammar.json */,
+				A9765C042485758300FDD115 /* binary.cpp */,
+				A9765C052485758300FDD115 /* spirv_validator_options.h */,
+				A9765C062485758300FDD115 /* enum_string_mapping.cpp */,
+				A9765C072485758300FDD115 /* text_handler.h */,
+				A9765C082485758300FDD115 /* parsed_operand.h */,
+				A9765C092485758300FDD115 /* name_mapper.h */,
+				A9765C0A2485758300FDD115 /* spirv_reducer_options.cpp */,
+				A9765C0B2485758300FDD115 /* parsed_operand.cpp */,
+				A9765C0C2485758300FDD115 /* diagnostic.h */,
+				A9765C0D2485758300FDD115 /* spirv_endian.h */,
+				A9765C0E2485758300FDD115 /* name_mapper.cpp */,
+				A9765C0F2485758300FDD115 /* extinst.debuginfo.grammar.json */,
+				A9765C102485758300FDD115 /* link */,
+				A9765C132485758300FDD115 /* software_version.cpp */,
+				A9765C142485758300FDD115 /* opcode.cpp */,
+				A9765C152485758300FDD115 /* print.h */,
+				A9765C162485758300FDD115 /* ext_inst.cpp */,
+				A9765C172485758300FDD115 /* disassemble.h */,
+				A9765C182485758300FDD115 /* opt */,
+				A9765CF12485758400FDD115 /* table.h */,
+				A9765DB22485758500FDD115 /* ext_inst.h */,
+				A9765DB32485758500FDD115 /* diagnostic.cpp */,
+				A9765DB42485758500FDD115 /* latest_version_spirv_header.h */,
+				A9765DB52485758500FDD115 /* libspirv.cpp */,
+				A9765DB62485758500FDD115 /* instruction.h */,
+				A9765DB72485758500FDD115 /* spirv_optimizer_options.h */,
+				A9765DB82485758500FDD115 /* opcode.h */,
+				A9765DB92485758500FDD115 /* operand.cpp */,
+				A9765DBA2485758500FDD115 /* latest_version_glsl_std_450_header.h */,
+				A9765DBB2485758500FDD115 /* extensions.h */,
+				A9765DBC2485758500FDD115 /* disassemble.cpp */,
+				A9765DBD2485758500FDD115 /* binary.h */,
+				A9765DBE2485758500FDD115 /* text_handler.cpp */,
+				A9765DBF2485758500FDD115 /* val */,
+			);
+			path = source;
+			sourceTree = "<group>";
+		};
+		A9765BA72485758300FDD115 /* util */ = {
+			isa = PBXGroup;
+			children = (
+				A9765BA82485758300FDD115 /* parse_number.h */,
+				A9765BA92485758300FDD115 /* ilist_node.h */,
+				A9765BAA2485758300FDD115 /* make_unique.h */,
+				A9765BAB2485758300FDD115 /* string_utils.h */,
+				A9765BAC2485758300FDD115 /* small_vector.h */,
+				A9765BAD2485758300FDD115 /* timer.cpp */,
+				A9765BAE2485758300FDD115 /* timer.h */,
+				A9765BAF2485758300FDD115 /* string_utils.cpp */,
+				A9765BB02485758300FDD115 /* bit_vector.h */,
+				A9765BB12485758300FDD115 /* bitutils.h */,
+				A9765BB22485758300FDD115 /* hex_float.h */,
+				A9765BB32485758300FDD115 /* parse_number.cpp */,
+				A9765BB42485758300FDD115 /* bit_vector.cpp */,
+				A9765BB52485758300FDD115 /* ilist.h */,
+			);
+			path = util;
+			sourceTree = "<group>";
+		};
+		A9765BB92485758300FDD115 /* reduce */ = {
+			isa = PBXGroup;
+			children = (
+				A9765BBA2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.h */,
+				A9765BBB2485758300FDD115 /* remove_selection_reduction_opportunity.cpp */,
+				A9765BBC2485758300FDD115 /* remove_block_reduction_opportunity.h */,
+				A9765BBD2485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h */,
+				A9765BBE2485758300FDD115 /* reduction_pass.cpp */,
+				A9765BBF2485758300FDD115 /* operand_to_const_reduction_opportunity_finder.cpp */,
+				A9765BC02485758300FDD115 /* operand_to_const_reduction_opportunity_finder.h */,
+				A9765BC12485758300FDD115 /* CMakeLists.txt */,
+				A9765BC22485758300FDD115 /* reduction_util.cpp */,
+				A9765BC32485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp */,
+				A9765BC42485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h */,
+				A9765BC52485758300FDD115 /* remove_function_reduction_opportunity_finder.cpp */,
+				A9765BC62485758300FDD115 /* remove_instruction_reduction_opportunity.h */,
+				A9765BC72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h */,
+				A9765BC82485758300FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp */,
+				A9765BC92485758300FDD115 /* remove_function_reduction_opportunity.cpp */,
+				A9765BCA2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp */,
+				A9765BCB2485758300FDD115 /* remove_selection_reduction_opportunity_finder.cpp */,
+				A9765BCC2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp */,
+				A9765BCD2485758300FDD115 /* remove_struct_member_reduction_opportunity.h */,
+				A9765BCE2485758300FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h */,
+				A9765BCF2485758300FDD115 /* merge_blocks_reduction_opportunity.cpp */,
+				A9765BD02485758300FDD115 /* change_operand_reduction_opportunity.cpp */,
+				A9765BD12485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.h */,
+				A9765BD22485758300FDD115 /* remove_function_reduction_opportunity.h */,
+				A9765BD32485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h */,
+				A9765BD42485758300FDD115 /* change_operand_to_undef_reduction_opportunity.h */,
+				A9765BD52485758300FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h */,
+				A9765BD62485758300FDD115 /* remove_selection_reduction_opportunity.h */,
+				A9765BD72485758300FDD115 /* remove_instruction_reduction_opportunity.cpp */,
+				A9765BD82485758300FDD115 /* remove_selection_reduction_opportunity_finder.h */,
+				A9765BD92485758300FDD115 /* merge_blocks_reduction_opportunity_finder.h */,
+				A9765BDA2485758300FDD115 /* pch_source_reduce.cpp */,
+				A9765BDB2485758300FDD115 /* remove_struct_member_reduction_opportunity.cpp */,
+				A9765BDC2485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h */,
+				A9765BDD2485758300FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp */,
+				A9765BDE2485758300FDD115 /* reducer.cpp */,
+				A9765BDF2485758300FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp */,
+				A9765BE02485758300FDD115 /* remove_function_reduction_opportunity_finder.h */,
+				A9765BE12485758300FDD115 /* pch_source_reduce.h */,
+				A9765BE22485758300FDD115 /* merge_blocks_reduction_opportunity_finder.cpp */,
+				A9765BE32485758300FDD115 /* reduction_opportunity.cpp */,
+				A9765BE42485758300FDD115 /* reducer.h */,
+				A9765BE52485758300FDD115 /* change_operand_to_undef_reduction_opportunity.cpp */,
+				A9765BE62485758300FDD115 /* reduction_opportunity.h */,
+				A9765BE72485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h */,
+				A9765BE82485758300FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp */,
+				A9765BE92485758300FDD115 /* reduction_opportunity_finder.h */,
+				A9765BEA2485758300FDD115 /* change_operand_reduction_opportunity.h */,
+				A9765BEB2485758300FDD115 /* remove_block_reduction_opportunity_finder.h */,
+				A9765BEC2485758300FDD115 /* remove_block_reduction_opportunity_finder.cpp */,
+				A9765BED2485758300FDD115 /* reduction_util.h */,
+				A9765BEE2485758300FDD115 /* merge_blocks_reduction_opportunity.h */,
+				A9765BEF2485758300FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp */,
+				A9765BF02485758300FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp */,
+				A9765BF12485758300FDD115 /* remove_block_reduction_opportunity.cpp */,
+				A9765BF22485758300FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp */,
+				A9765BF32485758300FDD115 /* reduction_pass.h */,
+			);
+			path = reduce;
+			sourceTree = "<group>";
+		};
+		A9765C102485758300FDD115 /* link */ = {
+			isa = PBXGroup;
+			children = (
+				A9765C112485758300FDD115 /* CMakeLists.txt */,
+				A9765C122485758300FDD115 /* linker.cpp */,
+			);
+			path = link;
+			sourceTree = "<group>";
+		};
+		A9765C182485758300FDD115 /* opt */ = {
+			isa = PBXGroup;
+			children = (
+				A9765C192485758300FDD115 /* optimizer.cpp */,
+				A9765C1A2485758300FDD115 /* if_conversion.h */,
+				A9765C1B2485758300FDD115 /* register_pressure.cpp */,
+				A9765C1C2485758300FDD115 /* loop_utils.cpp */,
+				A9765C1D2485758300FDD115 /* merge_return_pass.h */,
+				A9765C1E2485758300FDD115 /* inline_opaque_pass.h */,
+				A9765C1F2485758300FDD115 /* loop_fusion.h */,
+				A9765C202485758300FDD115 /* combine_access_chains.cpp */,
+				A9765C212485758300FDD115 /* build_module.cpp */,
+				A9765C222485758300FDD115 /* composite.h */,
+				A9765C232485758300FDD115 /* compact_ids_pass.h */,
+				A9765C242485758300FDD115 /* register_pressure.h */,
+				A9765C252485758300FDD115 /* tree_iterator.h */,
+				A9765C262485758300FDD115 /* graphics_robust_access_pass.h */,
+				A9765C272485758300FDD115 /* strip_atomic_counter_memory_pass.h */,
+				A9765C282485758300FDD115 /* legalize_vector_shuffle_pass.h */,
+				A9765C292485758300FDD115 /* local_single_store_elim_pass.h */,
+				A9765C2A2485758300FDD115 /* reduce_load_size.h */,
+				A9765C2B2485758300FDD115 /* code_sink.cpp */,
+				A9765C2C2485758300FDD115 /* types.cpp */,
+				A9765C2D2485758300FDD115 /* scalar_analysis.h */,
+				A9765C2E2485758300FDD115 /* strip_debug_info_pass.h */,
+				A9765C2F2485758300FDD115 /* cfg.cpp */,
+				A9765C302485758300FDD115 /* strip_atomic_counter_memory_pass.cpp */,
+				A9765C312485758300FDD115 /* decoration_manager.cpp */,
+				A9765C322485758300FDD115 /* local_single_block_elim_pass.cpp */,
+				A9765C332485758300FDD115 /* freeze_spec_constant_value_pass.cpp */,
+				A9765C342485758300FDD115 /* replace_invalid_opc.h */,
+				A9765C352485758300FDD115 /* local_access_chain_convert_pass.h */,
+				A9765C362485758300FDD115 /* inst_bindless_check_pass.cpp */,
+				A9765C372485758300FDD115 /* local_redundancy_elimination.cpp */,
+				A9765C382485758300FDD115 /* CMakeLists.txt */,
+				A9765C392485758300FDD115 /* instrument_pass.cpp */,
+				A9765C3A2485758300FDD115 /* propagator.h */,
+				A9765C3B2485758300FDD115 /* instruction_list.h */,
+				A9765C3C2485758300FDD115 /* feature_manager.cpp */,
+				A9765C3D2485758300FDD115 /* pass.cpp */,
+				A9765C3E2485758300FDD115 /* loop_fission.cpp */,
+				A9765C3F2485758300FDD115 /* dominator_tree.cpp */,
+				A9765C402485758300FDD115 /* amd_ext_to_khr.h */,
+				A9765C412485758300FDD115 /* merge_return_pass.cpp */,
+				A9765C422485758300FDD115 /* ir_context.h */,
+				A9765C432485758300FDD115 /* eliminate_dead_constant_pass.cpp */,
+				A9765C442485758300FDD115 /* cfg_cleanup_pass.cpp */,
+				A9765C452485758300FDD115 /* wrap_opkill.cpp */,
+				A9765C462485758300FDD115 /* const_folding_rules.cpp */,
+				A9765C472485758300FDD115 /* loop_unroller.h */,
+				A9765C482485758300FDD115 /* strip_debug_info_pass.cpp */,
+				A9765C492485758300FDD115 /* ssa_rewrite_pass.cpp */,
+				A9765C4A2485758300FDD115 /* loop_dependence.cpp */,
+				A9765C4B2485758300FDD115 /* unify_const_pass.h */,
+				A9765C4C2485758300FDD115 /* ir_loader.h */,
+				A9765C4D2485758300FDD115 /* inst_debug_printf_pass.cpp */,
+				A9765C4E2485758300FDD115 /* types.h */,
+				A9765C4F2485758300FDD115 /* fold_spec_constant_op_and_composite_pass.h */,
+				A9765C502485758300FDD115 /* mem_pass.cpp */,
+				A9765C512485758300FDD115 /* basic_block.h */,
+				A9765C522485758300FDD115 /* remove_duplicates_pass.cpp */,
+				A9765C532485758300FDD115 /* dead_variable_elimination.cpp */,
+				A9765C542485758300FDD115 /* block_merge_pass.h */,
+				A9765C552485758400FDD115 /* module.cpp */,
+				A9765C562485758400FDD115 /* debug_info_manager.h */,
+				A9765C572485758400FDD115 /* fold_spec_constant_op_and_composite_pass.cpp */,
+				A9765C582485758400FDD115 /* loop_unswitch_pass.cpp */,
+				A9765C592485758400FDD115 /* unify_const_pass.cpp */,
+				A9765C5A2485758400FDD115 /* type_manager.cpp */,
+				A9765C5B2485758400FDD115 /* generate_webgpu_initializers_pass.cpp */,
+				A9765C5C2485758400FDD115 /* private_to_local_pass.h */,
+				A9765C5D2485758400FDD115 /* convert_to_half_pass.h */,
+				A9765C5E2485758400FDD115 /* relax_float_ops_pass.h */,
+				A9765C5F2485758400FDD115 /* inline_pass.cpp */,
+				A9765C602485758400FDD115 /* def_use_manager.h */,
+				A9765C612485758400FDD115 /* ir_loader.cpp */,
+				A9765C622485758400FDD115 /* cfg_cleanup_pass.h */,
+				A9765C632485758400FDD115 /* licm_pass.cpp */,
+				A9765C642485758400FDD115 /* eliminate_dead_functions_pass.cpp */,
+				A9765C652485758400FDD115 /* local_redundancy_elimination.h */,
+				A9765C662485758400FDD115 /* split_invalid_unreachable_pass.cpp */,
+				A9765C672485758400FDD115 /* loop_peeling.h */,
+				A9765C682485758400FDD115 /* vector_dce.cpp */,
+				A9765C692485758400FDD115 /* block_merge_util.h */,
+				A9765C6A2485758400FDD115 /* loop_unroller.cpp */,
+				A9765C6B2485758400FDD115 /* desc_sroa.h */,
+				A9765C6C2485758400FDD115 /* constants.cpp */,
+				A9765C6D2485758400FDD115 /* loop_fusion_pass.h */,
+				A9765C6E2485758400FDD115 /* struct_cfg_analysis.h */,
+				A9765C6F2485758400FDD115 /* inst_buff_addr_check_pass.cpp */,
+				A9765C702485758400FDD115 /* def_use_manager.cpp */,
+				A9765C712485758400FDD115 /* wrap_opkill.h */,
+				A9765C722485758400FDD115 /* strip_reflect_info_pass.cpp */,
+				A9765C732485758400FDD115 /* decoration_manager.h */,
+				A9765C742485758400FDD115 /* ccp_pass.cpp */,
+				A9765C752485758400FDD115 /* process_lines_pass.h */,
+				A9765C762485758400FDD115 /* local_single_block_elim_pass.h */,
+				A9765C772485758400FDD115 /* pch_source_opt.cpp */,
+				A9765C782485758400FDD115 /* inst_buff_addr_check_pass.h */,
+				A9765C792485758400FDD115 /* strength_reduction_pass.h */,
+				A9765C7A2485758400FDD115 /* aggressive_dead_code_elim_pass.cpp */,
+				A9765C7B2485758400FDD115 /* eliminate_dead_functions_util.cpp */,
+				A9765C7C2485758400FDD115 /* inst_debug_printf_pass.h */,
+				A9765C7D2485758400FDD115 /* simplification_pass.cpp */,
+				A9765C7E2485758400FDD115 /* dead_branch_elim_pass.cpp */,
+				A9765C7F2485758400FDD115 /* flatten_decoration_pass.cpp */,
+				A9765C802485758400FDD115 /* dead_insert_elim_pass.h */,
+				A9765C812485758400FDD115 /* folding_rules.cpp */,
+				A9765C822485758400FDD115 /* freeze_spec_constant_value_pass.h */,
+				A9765C832485758400FDD115 /* ir_context.cpp */,
+				A9765C842485758400FDD115 /* instrument_pass.h */,
+				A9765C852485758400FDD115 /* mem_pass.h */,
+				A9765C862485758400FDD115 /* loop_descriptor.cpp */,
+				A9765C872485758400FDD115 /* eliminate_dead_members_pass.h */,
+				A9765C882485758400FDD115 /* function.cpp */,
+				A9765C892485758400FDD115 /* instruction_list.cpp */,
+				A9765C8A2485758400FDD115 /* composite.cpp */,
+				A9765C8B2485758400FDD115 /* convert_to_half_pass.cpp */,
+				A9765C8C2485758400FDD115 /* process_lines_pass.cpp */,
+				A9765C8D2485758400FDD115 /* inline_pass.h */,
+				A9765C8E2485758400FDD115 /* loop_dependence.h */,
+				A9765C8F2485758400FDD115 /* value_number_table.h */,
+				A9765C902485758400FDD115 /* flatten_decoration_pass.h */,
+				A9765C912485758400FDD115 /* if_conversion.cpp */,
+				A9765C922485758400FDD115 /* debug_info_manager.cpp */,
+				A9765C932485758400FDD115 /* inline_exhaustive_pass.h */,
+				A9765C942485758400FDD115 /* constants.h */,
+				A9765C952485758400FDD115 /* eliminate_dead_members_pass.cpp */,
+				A9765C962485758400FDD115 /* strength_reduction_pass.cpp */,
+				A9765C972485758400FDD115 /* desc_sroa.cpp */,
+				A9765C982485758400FDD115 /* block_merge_util.cpp */,
+				A9765C992485758400FDD115 /* upgrade_memory_model.h */,
+				A9765C9A2485758400FDD115 /* copy_prop_arrays.cpp */,
+				A9765C9B2485758400FDD115 /* pass_manager.cpp */,
+				A9765C9C2485758400FDD115 /* inline_exhaustive_pass.cpp */,
+				A9765C9D2485758400FDD115 /* loop_fission.h */,
+				A9765C9E2485758400FDD115 /* workaround1209.h */,
+				A9765C9F2485758400FDD115 /* loop_fusion_pass.cpp */,
+				A9765CA02485758400FDD115 /* log.h */,
+				A9765CA12485758400FDD115 /* split_invalid_unreachable_pass.h */,
+				A9765CA22485758400FDD115 /* copy_prop_arrays.h */,
+				A9765CA32485758400FDD115 /* eliminate_dead_constant_pass.h */,
+				A9765CA42485758400FDD115 /* dead_insert_elim_pass.cpp */,
+				A9765CA52485758400FDD115 /* ssa_rewrite_pass.h */,
+				A9765CA62485758400FDD115 /* scalar_analysis.cpp */,
+				A9765CA72485758400FDD115 /* dead_variable_elimination.h */,
+				A9765CA82485758400FDD115 /* block_merge_pass.cpp */,
+				A9765CA92485758400FDD115 /* dominator_analysis.h */,
+				A9765CAA2485758400FDD115 /* pass.h */,
+				A9765CAB2485758400FDD115 /* folding_rules.h */,
+				A9765CAC2485758400FDD115 /* eliminate_dead_functions_pass.h */,
+				A9765CAD2485758400FDD115 /* eliminate_dead_functions_util.h */,
+				A9765CAE2485758400FDD115 /* fold.h */,
+				A9765CAF2485758400FDD115 /* local_single_store_elim_pass.cpp */,
+				A9765CB02485758400FDD115 /* dead_branch_elim_pass.h */,
+				A9765CB12485758400FDD115 /* private_to_local_pass.cpp */,
+				A9765CB22485758400FDD115 /* scalar_analysis_nodes.h */,
+				A9765CB32485758400FDD115 /* propagator.cpp */,
+				A9765CB42485758400FDD115 /* fix_storage_class.h */,
+				A9765CB52485758400FDD115 /* loop_dependence_helpers.cpp */,
+				A9765CB62485758400FDD115 /* set_spec_constant_default_value_pass.cpp */,
+				A9765CB72485758400FDD115 /* passes.h */,
+				A9765CB82485758400FDD115 /* fold.cpp */,
+				A9765CB92485758400FDD115 /* amd_ext_to_khr.cpp */,
+				A9765CBA2485758400FDD115 /* strip_reflect_info_pass.h */,
+				A9765CBB2485758400FDD115 /* scalar_replacement_pass.cpp */,
+				A9765CBC2485758400FDD115 /* simplification_pass.h */,
+				A9765CBD2485758400FDD115 /* remove_duplicates_pass.h */,
+				A9765CBE2485758400FDD115 /* redundancy_elimination.cpp */,
+				A9765CBF2485758400FDD115 /* reflect.h */,
+				A9765CC02485758400FDD115 /* workaround1209.cpp */,
+				A9765CC12485758400FDD115 /* null_pass.h */,
+				A9765CC22485758400FDD115 /* relax_float_ops_pass.cpp */,
+				A9765CC32485758400FDD115 /* const_folding_rules.h */,
+				A9765CC42485758400FDD115 /* scalar_replacement_pass.h */,
+				A9765CC52485758400FDD115 /* instruction.cpp */,
+				A9765CC62485758400FDD115 /* pch_source_opt.h */,
+				A9765CC72485758400FDD115 /* reduce_load_size.cpp */,
+				A9765CC82485758400FDD115 /* redundancy_elimination.h */,
+				A9765CC92485758400FDD115 /* fix_storage_class.cpp */,
+				A9765CCA2485758400FDD115 /* value_number_table.cpp */,
+				A9765CCB2485758400FDD115 /* inline_opaque_pass.cpp */,
+				A9765CCC2485758400FDD115 /* replace_invalid_opc.cpp */,
+				A9765CCD2485758400FDD115 /* loop_utils.h */,
+				A9765CCE2485758400FDD115 /* module.h */,
+				A9765CCF2485758400FDD115 /* dominator_analysis.cpp */,
+				A9765CD02485758400FDD115 /* decompose_initialized_variables_pass.cpp */,
+				A9765CD12485758400FDD115 /* ir_builder.h */,
+				A9765CD22485758400FDD115 /* loop_unswitch_pass.h */,
+				A9765CD32485758400FDD115 /* cfg.h */,
+				A9765CD42485758400FDD115 /* code_sink.h */,
+				A9765CD52485758400FDD115 /* loop_descriptor.h */,
+				A9765CD62485758400FDD115 /* generate_webgpu_initializers_pass.h */,
+				A9765CD72485758400FDD115 /* instruction.h */,
+				A9765CD82485758400FDD115 /* aggressive_dead_code_elim_pass.h */,
+				A9765CD92485758400FDD115 /* struct_cfg_analysis.cpp */,
+				A9765CDA2485758400FDD115 /* vector_dce.h */,
+				A9765CDB2485758400FDD115 /* combine_access_chains.h */,
+				A9765CDC2485758400FDD115 /* pass_manager.h */,
+				A9765CDD2485758400FDD115 /* local_access_chain_convert_pass.cpp */,
+				A9765CDE2485758400FDD115 /* basic_block.cpp */,
+				A9765CDF2485758400FDD115 /* iterator.h */,
+				A9765CE02485758400FDD115 /* licm_pass.h */,
+				A9765CE12485758400FDD115 /* build_module.h */,
+				A9765CE22485758400FDD115 /* ccp_pass.h */,
+				A9765CE32485758400FDD115 /* graphics_robust_access_pass.cpp */,
+				A9765CE42485758400FDD115 /* decompose_initialized_variables_pass.h */,
+				A9765CE52485758400FDD115 /* function.h */,
+				A9765CE62485758400FDD115 /* loop_fusion.cpp */,
+				A9765CE72485758400FDD115 /* upgrade_memory_model.cpp */,
+				A9765CE82485758400FDD115 /* feature_manager.h */,
+				A9765CE92485758400FDD115 /* inst_bindless_check_pass.h */,
+				A9765CEA2485758400FDD115 /* scalar_analysis_simplification.cpp */,
+				A9765CEB2485758400FDD115 /* set_spec_constant_default_value_pass.h */,
+				A9765CEC2485758400FDD115 /* dominator_tree.h */,
+				A9765CED2485758400FDD115 /* legalize_vector_shuffle_pass.cpp */,
+				A9765CEE2485758400FDD115 /* type_manager.h */,
+				A9765CEF2485758400FDD115 /* compact_ids_pass.cpp */,
+				A9765CF02485758400FDD115 /* loop_peeling.cpp */,
+			);
+			path = opt;
+			sourceTree = "<group>";
+		};
+		A9765DBF2485758500FDD115 /* val */ = {
+			isa = PBXGroup;
+			children = (
+				A9765DC02485758500FDD115 /* validate_annotation.cpp */,
+				A9765DC12485758500FDD115 /* validate_misc.cpp */,
+				A9765DC22485758500FDD115 /* validate_cfg.cpp */,
+				A9765DC32485758500FDD115 /* validate_capability.cpp */,
+				A9765DC42485758500FDD115 /* construct.h */,
+				A9765DC52485758500FDD115 /* validate_barriers.cpp */,
+				A9765DC62485758500FDD115 /* validate_non_uniform.cpp */,
+				A9765DC72485758500FDD115 /* validate_scopes.cpp */,
+				A9765DC82485758500FDD115 /* validate_atomics.cpp */,
+				A9765DC92485758500FDD115 /* basic_block.h */,
+				A9765DCA2485758500FDD115 /* validate_instruction.cpp */,
+				A9765DCB2485758500FDD115 /* validate_decorations.cpp */,
+				A9765DCC2485758500FDD115 /* validate_debug.cpp */,
+				A9765DCD2485758500FDD115 /* validate_builtins.cpp */,
+				A9765DCE2485758500FDD115 /* validate_interfaces.cpp */,
+				A9765DCF2485758500FDD115 /* validate.cpp */,
+				A9765DD02485758500FDD115 /* validation_state.h */,
+				A9765DD12485758500FDD115 /* validate_constants.cpp */,
+				A9765DD22485758500FDD115 /* validate_bitwise.cpp */,
+				A9765DD32485758500FDD115 /* validate_extensions.cpp */,
+				A9765DD42485758500FDD115 /* construct.cpp */,
+				A9765DD52485758500FDD115 /* function.cpp */,
+				A9765DD62485758500FDD115 /* validate.h */,
+				A9765DD72485758500FDD115 /* validate_adjacency.cpp */,
+				A9765DD82485758500FDD115 /* validate_conversion.cpp */,
+				A9765DD92485758500FDD115 /* validate_small_type_uses.cpp */,
+				A9765DDA2485758500FDD115 /* validate_scopes.h */,
+				A9765DDB2485758500FDD115 /* validate_id.cpp */,
+				A9765DDC2485758500FDD115 /* validate_memory_semantics.h */,
+				A9765DDD2485758500FDD115 /* validate_arithmetics.cpp */,
+				A9765DDE2485758500FDD115 /* validate_mode_setting.cpp */,
+				A9765DDF2485758500FDD115 /* validate_memory_semantics.cpp */,
+				A9765DE02485758500FDD115 /* validate_logicals.cpp */,
+				A9765DE12485758500FDD115 /* validate_derivatives.cpp */,
+				A9765DE22485758500FDD115 /* validate_memory.cpp */,
+				A9765DE32485758500FDD115 /* validate_image.cpp */,
+				A9765DE42485758500FDD115 /* validate_literals.cpp */,
+				A9765DE52485758500FDD115 /* instruction.cpp */,
+				A9765DE62485758500FDD115 /* validate_type.cpp */,
+				A9765DE72485758500FDD115 /* instruction.h */,
+				A9765DE82485758500FDD115 /* validate_execution_limitations.cpp */,
+				A9765DE92485758500FDD115 /* validate_layout.cpp */,
+				A9765DEA2485758500FDD115 /* basic_block.cpp */,
+				A9765DEB2485758500FDD115 /* validate_function.cpp */,
+				A9765DEC2485758500FDD115 /* function.h */,
+				A9765DED2485758500FDD115 /* validate_composites.cpp */,
+				A9765DEE2485758500FDD115 /* validation_state.cpp */,
+				A9765DEF2485758500FDD115 /* validate_primitives.cpp */,
+				A9765DF02485758500FDD115 /* decoration.h */,
+			);
+			path = val;
+			sourceTree = "<group>";
+		};
 		A9F55D24198BE6A7004EC31B = {
 			isa = PBXGroup;
 			children = (
@@ -2347,192 +2371,195 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A9415B8B243667F800566F16 /* strip_debug_info_pass.h in Headers */,
-				A9415AB9243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.h in Headers */,
-				A9415CCB243667F800566F16 /* ir_builder.h in Headers */,
-				A9415C6D243667F800566F16 /* copy_prop_arrays.h in Headers */,
-				A9415CB9243667F800566F16 /* redundancy_elimination.h in Headers */,
-				A9415D0B243667F800566F16 /* table.h in Headers */,
-				A9415E8D243667F900566F16 /* binary.h in Headers */,
-				A9415B0B243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */,
-				A9415B89243667F800566F16 /* scalar_analysis.h in Headers */,
-				A9415CAF243667F800566F16 /* const_folding_rules.h in Headers */,
-				A9415D05243667F800566F16 /* type_manager.h in Headers */,
-				A9415E99243667F900566F16 /* construct.h in Headers */,
-				A9415B2F243667F800566F16 /* spirv_reducer_options.h in Headers */,
-				A9415B37243667F800566F16 /* operand.h in Headers */,
-				A9415AFB243667F700566F16 /* remove_function_reduction_opportunity_finder.h in Headers */,
-				A9415CE9243667F800566F16 /* licm_pass.h in Headers */,
-				A9415AD1243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */,
-				A9415C45243667F800566F16 /* inline_pass.h in Headers */,
-				A9415AAB243667F700566F16 /* bitutils.h in Headers */,
-				A9415B51243667F800566F16 /* spirv_endian.h in Headers */,
-				A9415B4F243667F800566F16 /* diagnostic.h in Headers */,
-				A9415BCF243667F800566F16 /* basic_block.h in Headers */,
-				A9415B09243667F700566F16 /* reduction_opportunity.h in Headers */,
-				A9415C1B243667F800566F16 /* inst_buff_addr_check_pass.h in Headers */,
-				A9415CD7243667F800566F16 /* instruction.h in Headers */,
-				A9415AB5243667F700566F16 /* spirv_target_env.h in Headers */,
-				A9415B79243667F800566F16 /* tree_iterator.h in Headers */,
-				A9415C7F243667F800566F16 /* folding_rules.h in Headers */,
-				A9415CA1243667F800566F16 /* simplification_pass.h in Headers */,
-				A9415A9D243667F700566F16 /* make_unique.h in Headers */,
-				A9415CED243667F800566F16 /* ccp_pass.h in Headers */,
-				A9415C6B243667F800566F16 /* split_invalid_unreachable_pass.h in Headers */,
-				A9415CD5243667F800566F16 /* generate_webgpu_initializers_pass.h in Headers */,
-				A9415AED243667F700566F16 /* remove_selection_reduction_opportunity.h in Headers */,
-				A9415C33243667F800566F16 /* instrument_pass.h in Headers */,
-				A9415B2B243667F800566F16 /* enum_string_mapping.h in Headers */,
-				A9415C39243667F800566F16 /* eliminate_dead_members_pass.h in Headers */,
-				A9415C81243667F800566F16 /* eliminate_dead_functions_pass.h in Headers */,
-				A9415BB1243667F800566F16 /* ir_context.h in Headers */,
-				A9415ACF243667F700566F16 /* remove_instruction_reduction_opportunity.h in Headers */,
-				A9415C4B243667F800566F16 /* flatten_decoration_pass.h in Headers */,
-				A9415BC3243667F800566F16 /* unify_const_pass.h in Headers */,
-				A9415B6D243667F800566F16 /* loop_fusion.h in Headers */,
-				A9415C6F243667F800566F16 /* eliminate_dead_constant_pass.h in Headers */,
-				A9415EBD243667F900566F16 /* validate.h in Headers */,
-				A9415B7D243667F800566F16 /* strip_atomic_counter_memory_pass.h in Headers */,
-				A9415A8B243667F700566F16 /* assembly_grammar.h in Headers */,
-				A9415CDF243667F800566F16 /* combine_access_chains.h in Headers */,
-				A9415AE3243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.h in Headers */,
-				A9415B5F243667F800566F16 /* disassemble.h in Headers */,
-				A9415B49243667F800566F16 /* name_mapper.h in Headers */,
-				A9415EE9243667F900566F16 /* function.h in Headers */,
-				A9415BC5243667F800566F16 /* ir_loader.h in Headers */,
-				A9415CFB243667F800566F16 /* inst_bindless_check_pass.h in Headers */,
-				A9415B19243667F700566F16 /* merge_blocks_reduction_opportunity.h in Headers */,
-				A9415B13243667F700566F16 /* remove_block_reduction_opportunity_finder.h in Headers */,
-				A9415CF9243667F800566F16 /* feature_manager.h in Headers */,
-				A9415ABD243667F700566F16 /* remove_block_reduction_opportunity.h in Headers */,
-				A9415BC9243667F800566F16 /* types.h in Headers */,
-				A9415EB1243667F900566F16 /* validation_state.h in Headers */,
-				A9415E81243667F900566F16 /* spirv_optimizer_options.h in Headers */,
-				A9415AFD243667F700566F16 /* pch_source_reduce.h in Headers */,
-				A9415B81243667F800566F16 /* local_single_store_elim_pass.h in Headers */,
-				A9415C07243667F800566F16 /* struct_cfg_analysis.h in Headers */,
-				A9415CC3243667F800566F16 /* loop_utils.h in Headers */,
-				A9415CD3243667F800566F16 /* loop_descriptor.h in Headers */,
-				A9415C15243667F800566F16 /* process_lines_pass.h in Headers */,
-				A9415C97243667F800566F16 /* passes.h in Headers */,
-				A9415ACB243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */,
-				A9415EA3243667F900566F16 /* basic_block.h in Headers */,
-				A9415CD9243667F800566F16 /* aggressive_dead_code_elim_pass.h in Headers */,
-				A9415BEB243667F800566F16 /* def_use_manager.h in Headers */,
-				A9415B75243667F800566F16 /* compact_ids_pass.h in Headers */,
-				A9415C1D243667F800566F16 /* strength_reduction_pass.h in Headers */,
-				A9415AA5243667F700566F16 /* timer.h in Headers */,
-				A9415E7F243667F900566F16 /* instruction.h in Headers */,
-				A9415BF5243667F800566F16 /* local_redundancy_elimination.h in Headers */,
-				A9415C11243667F800566F16 /* decoration_manager.h in Headers */,
-				A9415C9D243667F800566F16 /* strip_reflect_info_pass.h in Headers */,
-				A9415B5B243667F800566F16 /* print.h in Headers */,
-				A9415BA3243667F800566F16 /* instruction_list.h in Headers */,
-				A9415B29243667F800566F16 /* pch_source.h in Headers */,
-				A9415C89243667F800566F16 /* dead_branch_elim_pass.h in Headers */,
-				A9415B23243667F700566F16 /* latest_version_opencl_std_header.h in Headers */,
-				A9415BA1243667F800566F16 /* propagator.h in Headers */,
-				A9415BE3243667F800566F16 /* private_to_local_pass.h in Headers */,
-				A9415EC5243667F900566F16 /* validate_scopes.h in Headers */,
-				A9415C8D243667F800566F16 /* scalar_analysis_nodes.h in Headers */,
-				A9415BFD243667F800566F16 /* block_merge_util.h in Headers */,
-				A9415CDD243667F800566F16 /* vector_dce.h in Headers */,
-				A9415C73243667F800566F16 /* ssa_rewrite_pass.h in Headers */,
-				A9415B41243667F800566F16 /* spirv_validator_options.h in Headers */,
-				A9415B63243667F800566F16 /* if_conversion.h in Headers */,
-				A9415B45243667F800566F16 /* text_handler.h in Headers */,
-				A9415B0F243667F700566F16 /* reduction_opportunity_finder.h in Headers */,
-				A9415AB3243667F700566F16 /* ilist.h in Headers */,
-				A9415B11243667F700566F16 /* change_operand_reduction_opportunity.h in Headers */,
-				A9415B7B243667F800566F16 /* graphics_robust_access_pass.h in Headers */,
-				A9415E89243667F900566F16 /* extensions.h in Headers */,
-				A9415CA7243667F800566F16 /* reflect.h in Headers */,
-				A9415CE7243667F800566F16 /* iterator.h in Headers */,
-				A9415B05243667F700566F16 /* reducer.h in Headers */,
-				A9415C91243667F800566F16 /* fix_storage_class.h in Headers */,
-				A9415AA1243667F700566F16 /* small_vector.h in Headers */,
-				A9415CEB243667F800566F16 /* build_module.h in Headers */,
-				A9415AF1243667F700566F16 /* remove_selection_reduction_opportunity_finder.h in Headers */,
-				A9415B3D243667F800566F16 /* spirv_constant.h in Headers */,
-				A9415AAD243667F700566F16 /* hex_float.h in Headers */,
-				A9415CF1243667F800566F16 /* decompose_initialized_variables_pass.h in Headers */,
-				A9415C0D243667F800566F16 /* wrap_opkill.h in Headers */,
-				A9415A93243667F700566F16 /* text.h in Headers */,
-				A9415BEF243667F800566F16 /* cfg_cleanup_pass.h in Headers */,
-				A9415BCB243667F800566F16 /* fold_spec_constant_op_and_composite_pass.h in Headers */,
-				A9415AF3243667F700566F16 /* merge_blocks_reduction_opportunity_finder.h in Headers */,
-				A9415B21243667F700566F16 /* reduction_pass.h in Headers */,
-				A9415C83243667F800566F16 /* eliminate_dead_functions_util.h in Headers */,
-				A9415B7F243667F800566F16 /* legalize_vector_shuffle_pass.h in Headers */,
-				A9415E77243667F900566F16 /* ext_inst.h in Headers */,
-				A9415A9F243667F700566F16 /* string_utils.h in Headers */,
-				A9415EDF243667F900566F16 /* instruction.h in Headers */,
-				A9415C05243667F800566F16 /* loop_fusion_pass.h in Headers */,
-				A9415C47243667F800566F16 /* loop_dependence.h in Headers */,
-				A9415ABF243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */,
-				A9415C5B243667F800566F16 /* upgrade_memory_model.h in Headers */,
-				A9415A99243667F700566F16 /* parse_number.h in Headers */,
-				A9415ADD243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */,
-				A9415CC5243667F800566F16 /* module.h in Headers */,
-				A9415C35243667F800566F16 /* mem_pass.h in Headers */,
-				A9415B35243667F800566F16 /* spirv_definition.h in Headers */,
-				A9415CB1243667F800566F16 /* scalar_replacement_pass.h in Headers */,
-				A9415B27243667F700566F16 /* cfa.h in Headers */,
-				A9415B3B243667F800566F16 /* macro.h in Headers */,
-				A9415C23243667F800566F16 /* inst_debug_printf_pass.h in Headers */,
-				A9415AE5243667F700566F16 /* remove_function_reduction_opportunity.h in Headers */,
-				A9415B97243667F800566F16 /* replace_invalid_opc.h in Headers */,
-				A9415B83243667F800566F16 /* reduce_load_size.h in Headers */,
-				A9415C49243667F800566F16 /* value_number_table.h in Headers */,
-				A9415C7B243667F800566F16 /* dominator_analysis.h in Headers */,
-				A9415D01243667F800566F16 /* dominator_tree.h in Headers */,
-				A9415A89243667F700566F16 /* spirv_fuzzer_options.h in Headers */,
-				A9415C51243667F800566F16 /* constants.h in Headers */,
-				A9415C65243667F800566F16 /* workaround1209.h in Headers */,
-				A9415CE1243667F800566F16 /* pass_manager.h in Headers */,
-				A9415C63243667F800566F16 /* loop_fission.h in Headers */,
-				A9415B73243667F800566F16 /* composite.h in Headers */,
-				A9415EF1243667F900566F16 /* decoration.h in Headers */,
-				A9415B17243667F700566F16 /* reduction_util.h in Headers */,
-				A9415CB5243667F800566F16 /* pch_source_opt.h in Headers */,
-				A9415BD5243667F800566F16 /* block_merge_pass.h in Headers */,
-				A9415CCF243667F800566F16 /* cfg.h in Headers */,
-				A9415C77243667F800566F16 /* dead_variable_elimination.h in Headers */,
-				A9415C2F243667F800566F16 /* freeze_spec_constant_value_pass.h in Headers */,
-				A9415CD1243667F800566F16 /* code_sink.h in Headers */,
-				A9415BF9243667F800566F16 /* loop_peeling.h in Headers */,
-				A9415EC9243667F900566F16 /* validate_memory_semantics.h in Headers */,
-				A9415AFF243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h in Headers */,
-				A9415A9B243667F700566F16 /* ilist_node.h in Headers */,
-				A9415C2B243667F800566F16 /* dead_insert_elim_pass.h in Headers */,
-				A9415A8D243667F700566F16 /* enum_set.h in Headers */,
-				A9415AC5243667F700566F16 /* operand_to_const_reduction_opportunity_finder.h in Headers */,
-				A9415CFF243667F800566F16 /* set_spec_constant_default_value_pass.h in Headers */,
-				A9415C4F243667F800566F16 /* inline_exhaustive_pass.h in Headers */,
-				A9415C17243667F800566F16 /* local_single_block_elim_pass.h in Headers */,
-				A9415B69243667F800566F16 /* merge_return_pass.h in Headers */,
-				A9415C01243667F800566F16 /* desc_sroa.h in Headers */,
-				A9415BAD243667F800566F16 /* amd_ext_to_khr.h in Headers */,
-				A9415BE7243667F800566F16 /* relax_float_ops_pass.h in Headers */,
-				A9415CAB243667F800566F16 /* null_pass.h in Headers */,
-				A9415B99243667F800566F16 /* local_access_chain_convert_pass.h in Headers */,
-				A9415AEB243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */,
-				A9415E7B243667F900566F16 /* latest_version_spirv_header.h in Headers */,
-				A9415CA3243667F800566F16 /* remove_duplicates_pass.h in Headers */,
-				A9415AE7243667F700566F16 /* change_operand_to_undef_reduction_opportunity.h in Headers */,
-				A9415CCD243667F800566F16 /* loop_unswitch_pass.h in Headers */,
-				A9415BE5243667F800566F16 /* convert_to_half_pass.h in Headers */,
-				A9415C85243667F800566F16 /* fold.h in Headers */,
-				A9415E87243667F900566F16 /* latest_version_glsl_std_450_header.h in Headers */,
-				A9415B77243667F800566F16 /* register_pressure.h in Headers */,
-				A9415B6B243667F800566F16 /* inline_opaque_pass.h in Headers */,
-				A9415C7D243667F800566F16 /* pass.h in Headers */,
-				A9415AA9243667F700566F16 /* bit_vector.h in Headers */,
-				A9415C69243667F800566F16 /* log.h in Headers */,
-				A9415B47243667F800566F16 /* parsed_operand.h in Headers */,
-				A9415CF3243667F800566F16 /* function.h in Headers */,
-				A9415E83243667F900566F16 /* opcode.h in Headers */,
-				A9415BBB243667F800566F16 /* loop_unroller.h in Headers */,
+				A9765F3B2485758600FDD115 /* types.h in Headers */,
+				A97660552485758600FDD115 /* combine_access_chains.h in Headers */,
+				A9765E532485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */,
+				A9765FE12485758600FDD115 /* split_invalid_unreachable_pass.h in Headers */,
+				A9765F472485758600FDD115 /* block_merge_pass.h in Headers */,
+				A9765FF52485758600FDD115 /* folding_rules.h in Headers */,
+				A97660472485758600FDD115 /* code_sink.h in Headers */,
+				A9765F7B2485758600FDD115 /* struct_cfg_analysis.h in Headers */,
+				A976607B2485758600FDD115 /* type_manager.h in Headers */,
+				A97660492485758600FDD115 /* loop_descriptor.h in Headers */,
+				A9765F792485758600FDD115 /* loop_fusion_pass.h in Headers */,
+				A9765EA92485758600FDD115 /* operand.h in Headers */,
+				A9765E832485758600FDD115 /* remove_block_reduction_opportunity_finder.h in Headers */,
+				A9765EAD2485758600FDD115 /* macro.h in Headers */,
+				A9765E7F2485758600FDD115 /* reduction_opportunity_finder.h in Headers */,
+				A9765F892485758600FDD115 /* process_lines_pass.h in Headers */,
+				A9765E992485758600FDD115 /* cfa.h in Headers */,
+				A9765EE52485758600FDD115 /* composite.h in Headers */,
+				A9765F812485758600FDD115 /* wrap_opkill.h in Headers */,
+				A976621F2485758700FDD115 /* construct.h in Headers */,
+				A9765F712485758600FDD115 /* block_merge_util.h in Headers */,
+				A9765E752485758600FDD115 /* reducer.h in Headers */,
+				A9765E232485758500FDD115 /* operand_to_undef_reduction_opportunity_finder.h in Headers */,
+				A97662292485758700FDD115 /* basic_block.h in Headers */,
+				A97661FD2485758700FDD115 /* ext_inst.h in Headers */,
+				A9765EED2485758600FDD115 /* graphics_robust_access_pass.h in Headers */,
+				A97660212485758600FDD115 /* null_pass.h in Headers */,
+				A97660192485758600FDD115 /* remove_duplicates_pass.h in Headers */,
+				A9765E5D2485758600FDD115 /* remove_selection_reduction_opportunity_finder.h in Headers */,
+				A9765EC12485758600FDD115 /* diagnostic.h in Headers */,
+				A9765E3B2485758500FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */,
+				A97660432485758600FDD115 /* loop_unswitch_pass.h in Headers */,
+				A97660612485758600FDD115 /* build_module.h in Headers */,
+				A9765F852485758600FDD115 /* decoration_manager.h in Headers */,
+				A9765FDF2485758600FDD115 /* log.h in Headers */,
+				A9765FA72485758600FDD115 /* instrument_pass.h in Headers */,
+				A9765F132485758600FDD115 /* propagator.h in Headers */,
+				A976620D2485758700FDD115 /* latest_version_glsl_std_450_header.h in Headers */,
+				A97662052485758700FDD115 /* instruction.h in Headers */,
+				A97662092485758700FDD115 /* opcode.h in Headers */,
+				A9765EBB2485758600FDD115 /* name_mapper.h in Headers */,
+				A9765F352485758600FDD115 /* unify_const_pass.h in Headers */,
+				A9765E492485758600FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */,
+				A97660692485758600FDD115 /* function.h in Headers */,
+				A9765ED12485758600FDD115 /* disassemble.h in Headers */,
+				A9765E152485758500FDD115 /* bitutils.h in Headers */,
+				A9765E1F2485758500FDD115 /* spirv_target_env.h in Headers */,
+				A976604D2485758600FDD115 /* instruction.h in Headers */,
+				A9765F2D2485758600FDD115 /* loop_unroller.h in Headers */,
+				A9765EFD2485758600FDD115 /* strip_debug_info_pass.h in Headers */,
+				A9765E6F2485758600FDD115 /* pch_source_reduce.h in Headers */,
+				A9765E072485758500FDD115 /* make_unique.h in Headers */,
+				A9765EA12485758600FDD115 /* spirv_reducer_options.h in Headers */,
+				A9765E392485758500FDD115 /* remove_instruction_reduction_opportunity.h in Headers */,
+				A97660032485758600FDD115 /* scalar_analysis_nodes.h in Headers */,
+				A9765E4F2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.h in Headers */,
+				A9765FE52485758600FDD115 /* eliminate_dead_constant_pass.h in Headers */,
+				A9765FD12485758600FDD115 /* upgrade_memory_model.h in Headers */,
+				A9765DF52485758500FDD115 /* assembly_grammar.h in Headers */,
+				A976602F2485758600FDD115 /* redundancy_elimination.h in Headers */,
+				A9765EAF2485758600FDD115 /* spirv_constant.h in Headers */,
+				A9765E272485758500FDD115 /* remove_block_reduction_opportunity.h in Headers */,
+				A97660572485758600FDD115 /* pass_manager.h in Headers */,
+				A9765FF12485758600FDD115 /* dominator_analysis.h in Headers */,
+				A97660072485758600FDD115 /* fix_storage_class.h in Headers */,
+				A9765F5B2485758600FDD115 /* relax_float_ops_pass.h in Headers */,
+				A9765FD92485758600FDD115 /* loop_fission.h in Headers */,
+				A9765F412485758600FDD115 /* basic_block.h in Headers */,
+				A97660632485758600FDD115 /* ccp_pass.h in Headers */,
+				A9765EF32485758600FDD115 /* local_single_store_elim_pass.h in Headers */,
+				A9765FBD2485758600FDD115 /* value_number_table.h in Headers */,
+				A97660172485758600FDD115 /* simplification_pass.h in Headers */,
+				A97660392485758600FDD115 /* loop_utils.h in Headers */,
+				A9765F692485758600FDD115 /* local_redundancy_elimination.h in Headers */,
+				A9765F972485758600FDD115 /* inst_debug_printf_pass.h in Headers */,
+				A97660712485758600FDD115 /* inst_bindless_check_pass.h in Headers */,
+				A97660672485758600FDD115 /* decompose_initialized_variables_pass.h in Headers */,
+				A9765E472485758600FDD115 /* remove_struct_member_reduction_opportunity.h in Headers */,
+				A9765EFB2485758600FDD115 /* scalar_analysis.h in Headers */,
+				A9765F3D2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.h in Headers */,
+				A97660752485758600FDD115 /* set_spec_constant_default_value_pass.h in Headers */,
+				A976624B2485758700FDD115 /* validate_scopes.h in Headers */,
+				A976605F2485758600FDD115 /* licm_pass.h in Headers */,
+				A9765FDB2485758600FDD115 /* workaround1209.h in Headers */,
+				A9765E932485758600FDD115 /* reduction_pass.h in Headers */,
+				A97660252485758600FDD115 /* const_folding_rules.h in Headers */,
+				A9765F572485758600FDD115 /* private_to_local_pass.h in Headers */,
+				A9765E5F2485758600FDD115 /* merge_blocks_reduction_opportunity_finder.h in Headers */,
+				A9765EF12485758600FDD115 /* legalize_vector_shuffle_pass.h in Headers */,
+				A9765E952485758600FDD115 /* latest_version_opencl_std_header.h in Headers */,
+				A9765EB72485758600FDD115 /* text_handler.h in Headers */,
+				A9765FE92485758600FDD115 /* ssa_rewrite_pass.h in Headers */,
+				A9765E352485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */,
+				A9765FC72485758600FDD115 /* constants.h in Headers */,
+				A976605D2485758600FDD115 /* iterator.h in Headers */,
+				A9765F152485758600FDD115 /* instruction_list.h in Headers */,
+				A9765FF32485758600FDD115 /* pass.h in Headers */,
+				A9765EEB2485758600FDD115 /* tree_iterator.h in Headers */,
+				A9765F372485758600FDD115 /* ir_loader.h in Headers */,
+				A97660412485758600FDD115 /* ir_builder.h in Headers */,
+				A9765E652485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */,
+				A9765F8F2485758600FDD115 /* inst_buff_addr_check_pass.h in Headers */,
+				A97662012485758700FDD115 /* latest_version_spirv_header.h in Headers */,
+				A9765E512485758600FDD115 /* remove_function_reduction_opportunity.h in Headers */,
+				A97660272485758600FDD115 /* scalar_replacement_pass.h in Headers */,
+				A9765E0F2485758500FDD115 /* timer.h in Headers */,
+				A9765E1D2485758500FDD115 /* ilist.h in Headers */,
+				A97662072485758700FDD115 /* spirv_optimizer_options.h in Headers */,
+				A97662372485758700FDD115 /* validation_state.h in Headers */,
+				A9765E0B2485758500FDD115 /* small_vector.h in Headers */,
+				A976626F2485758700FDD115 /* function.h in Headers */,
+				A9765EDB2485758600FDD115 /* merge_return_pass.h in Headers */,
+				A9765E872485758600FDD115 /* reduction_util.h in Headers */,
+				A9765E172485758500FDD115 /* hex_float.h in Headers */,
+				A97662432485758700FDD115 /* validate.h in Headers */,
+				A976601D2485758600FDD115 /* reflect.h in Headers */,
+				A9765F5F2485758600FDD115 /* def_use_manager.h in Headers */,
+				A9765E552485758600FDD115 /* change_operand_to_undef_reduction_opportunity.h in Headers */,
+				A9765FB92485758600FDD115 /* inline_pass.h in Headers */,
+				A9765F752485758600FDD115 /* desc_sroa.h in Headers */,
+				A9765E892485758600FDD115 /* merge_blocks_reduction_opportunity.h in Headers */,
+				A9765F8B2485758600FDD115 /* local_single_block_elim_pass.h in Headers */,
+				A9765E592485758600FDD115 /* remove_selection_reduction_opportunity.h in Headers */,
+				A9765F9F2485758600FDD115 /* dead_insert_elim_pass.h in Headers */,
+				A9765FE32485758600FDD115 /* copy_prop_arrays.h in Headers */,
+				A976604F2485758600FDD115 /* aggressive_dead_code_elim_pass.h in Headers */,
+				A9765FAD2485758600FDD115 /* eliminate_dead_members_pass.h in Headers */,
+				A97662772485758700FDD115 /* decoration.h in Headers */,
+				A9765EDD2485758600FDD115 /* inline_opaque_pass.h in Headers */,
+				A9765E9B2485758600FDD115 /* pch_source.h in Headers */,
+				A9765E9D2485758600FDD115 /* enum_string_mapping.h in Headers */,
+				A9765DFD2485758500FDD115 /* text.h in Headers */,
+				A976603B2485758600FDD115 /* module.h in Headers */,
+				A9765F6D2485758600FDD115 /* loop_peeling.h in Headers */,
+				A976602B2485758600FDD115 /* pch_source_opt.h in Headers */,
+				A97660452485758600FDD115 /* cfg.h in Headers */,
+				A9765FBB2485758600FDD115 /* loop_dependence.h in Headers */,
+				A9765E092485758500FDD115 /* string_utils.h in Headers */,
+				A9765FED2485758600FDD115 /* dead_variable_elimination.h in Headers */,
+				A9765EC32485758600FDD115 /* spirv_endian.h in Headers */,
+				A9765EDF2485758600FDD115 /* loop_fusion.h in Headers */,
+				A9765F4B2485758600FDD115 /* debug_info_manager.h in Headers */,
+				A97660812485758600FDD115 /* table.h in Headers */,
+				A9765F912485758600FDD115 /* strength_reduction_pass.h in Headers */,
+				A9765E292485758500FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */,
+				A9765E032485758500FDD115 /* parse_number.h in Headers */,
+				A9765DF32485758500FDD115 /* spirv_fuzzer_options.h in Headers */,
+				A976604B2485758600FDD115 /* generate_webgpu_initializers_pass.h in Headers */,
+				A9765E052485758500FDD115 /* ilist_node.h in Headers */,
+				A9765FFF2485758600FDD115 /* dead_branch_elim_pass.h in Headers */,
+				A9765E572485758600FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */,
+				A9765F632485758600FDD115 /* cfg_cleanup_pass.h in Headers */,
+				A976600D2485758600FDD115 /* passes.h in Headers */,
+				A97660772485758600FDD115 /* dominator_tree.h in Headers */,
+				A9765F592485758600FDD115 /* convert_to_half_pass.h in Headers */,
+				A9765FA32485758600FDD115 /* freeze_spec_constant_value_pass.h in Headers */,
+				A9765EE92485758600FDD115 /* register_pressure.h in Headers */,
+				A9765EB32485758600FDD115 /* spirv_validator_options.h in Headers */,
+				A9765EA72485758600FDD115 /* spirv_definition.h in Headers */,
+				A9765E6D2485758600FDD115 /* remove_function_reduction_opportunity_finder.h in Headers */,
+				A97662652485758700FDD115 /* instruction.h in Headers */,
+				A9765FF72485758600FDD115 /* eliminate_dead_functions_pass.h in Headers */,
+				A976624F2485758700FDD115 /* validate_memory_semantics.h in Headers */,
+				A9765EE72485758600FDD115 /* compact_ids_pass.h in Headers */,
+				A9765E812485758600FDD115 /* change_operand_reduction_opportunity.h in Headers */,
+				A9765FFB2485758600FDD115 /* fold.h in Headers */,
+				A9765E792485758600FDD115 /* reduction_opportunity.h in Headers */,
+				A97660132485758600FDD115 /* strip_reflect_info_pass.h in Headers */,
+				A976620F2485758700FDD115 /* extensions.h in Headers */,
+				A97660532485758600FDD115 /* vector_dce.h in Headers */,
+				A9765F0B2485758600FDD115 /* local_access_chain_convert_pass.h in Headers */,
+				A9765ECD2485758600FDD115 /* print.h in Headers */,
+				A9765DF72485758500FDD115 /* enum_set.h in Headers */,
+				A9765FBF2485758600FDD115 /* flatten_decoration_pass.h in Headers */,
+				A9765FA92485758600FDD115 /* mem_pass.h in Headers */,
+				A97662132485758700FDD115 /* binary.h in Headers */,
+				A9765ED52485758600FDD115 /* if_conversion.h in Headers */,
+				A9765EEF2485758600FDD115 /* strip_atomic_counter_memory_pass.h in Headers */,
+				A9765E2F2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.h in Headers */,
+				A9765EB92485758600FDD115 /* parsed_operand.h in Headers */,
+				A9765E132485758500FDD115 /* bit_vector.h in Headers */,
+				A976606F2485758600FDD115 /* feature_manager.h in Headers */,
+				A9765E7B2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */,
+				A9765F092485758600FDD115 /* replace_invalid_opc.h in Headers */,
+				A9765FC52485758600FDD115 /* inline_exhaustive_pass.h in Headers */,
+				A9765EF52485758600FDD115 /* reduce_load_size.h in Headers */,
+				A9765FF92485758600FDD115 /* eliminate_dead_functions_util.h in Headers */,
+				A9765F1F2485758600FDD115 /* amd_ext_to_khr.h in Headers */,
+				A9765F232485758600FDD115 /* ir_context.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2540,192 +2567,195 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A9415B8C243667F800566F16 /* strip_debug_info_pass.h in Headers */,
-				A9415ABA243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.h in Headers */,
-				A9415CCC243667F800566F16 /* ir_builder.h in Headers */,
-				A9415C6E243667F800566F16 /* copy_prop_arrays.h in Headers */,
-				A9415CBA243667F800566F16 /* redundancy_elimination.h in Headers */,
-				A9415D0C243667F800566F16 /* table.h in Headers */,
-				A9415E8E243667F900566F16 /* binary.h in Headers */,
-				A9415B0C243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */,
-				A9415B8A243667F800566F16 /* scalar_analysis.h in Headers */,
-				A9415CB0243667F800566F16 /* const_folding_rules.h in Headers */,
-				A9415D06243667F800566F16 /* type_manager.h in Headers */,
-				A9415E9A243667F900566F16 /* construct.h in Headers */,
-				A9415B30243667F800566F16 /* spirv_reducer_options.h in Headers */,
-				A9415B38243667F800566F16 /* operand.h in Headers */,
-				A9415AFC243667F700566F16 /* remove_function_reduction_opportunity_finder.h in Headers */,
-				A9415CEA243667F800566F16 /* licm_pass.h in Headers */,
-				A9415AD2243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */,
-				A9415C46243667F800566F16 /* inline_pass.h in Headers */,
-				A9415AAC243667F700566F16 /* bitutils.h in Headers */,
-				A9415B52243667F800566F16 /* spirv_endian.h in Headers */,
-				A9415B50243667F800566F16 /* diagnostic.h in Headers */,
-				A9415BD0243667F800566F16 /* basic_block.h in Headers */,
-				A9415B0A243667F700566F16 /* reduction_opportunity.h in Headers */,
-				A9415C1C243667F800566F16 /* inst_buff_addr_check_pass.h in Headers */,
-				A9415CD8243667F800566F16 /* instruction.h in Headers */,
-				A9415AB6243667F700566F16 /* spirv_target_env.h in Headers */,
-				A9415B7A243667F800566F16 /* tree_iterator.h in Headers */,
-				A9415C80243667F800566F16 /* folding_rules.h in Headers */,
-				A9415CA2243667F800566F16 /* simplification_pass.h in Headers */,
-				A9415A9E243667F700566F16 /* make_unique.h in Headers */,
-				A9415CEE243667F800566F16 /* ccp_pass.h in Headers */,
-				A9415C6C243667F800566F16 /* split_invalid_unreachable_pass.h in Headers */,
-				A9415CD6243667F800566F16 /* generate_webgpu_initializers_pass.h in Headers */,
-				A9415AEE243667F700566F16 /* remove_selection_reduction_opportunity.h in Headers */,
-				A9415C34243667F800566F16 /* instrument_pass.h in Headers */,
-				A9415B2C243667F800566F16 /* enum_string_mapping.h in Headers */,
-				A9415C3A243667F800566F16 /* eliminate_dead_members_pass.h in Headers */,
-				A9415C82243667F800566F16 /* eliminate_dead_functions_pass.h in Headers */,
-				A9415BB2243667F800566F16 /* ir_context.h in Headers */,
-				A9415AD0243667F700566F16 /* remove_instruction_reduction_opportunity.h in Headers */,
-				A9415C4C243667F800566F16 /* flatten_decoration_pass.h in Headers */,
-				A9415BC4243667F800566F16 /* unify_const_pass.h in Headers */,
-				A9415B6E243667F800566F16 /* loop_fusion.h in Headers */,
-				A9415C70243667F800566F16 /* eliminate_dead_constant_pass.h in Headers */,
-				A9415EBE243667F900566F16 /* validate.h in Headers */,
-				A9415B7E243667F800566F16 /* strip_atomic_counter_memory_pass.h in Headers */,
-				A9415A8C243667F700566F16 /* assembly_grammar.h in Headers */,
-				A9415CE0243667F800566F16 /* combine_access_chains.h in Headers */,
-				A9415AE4243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.h in Headers */,
-				A9415B60243667F800566F16 /* disassemble.h in Headers */,
-				A9415B4A243667F800566F16 /* name_mapper.h in Headers */,
-				A9415EEA243667F900566F16 /* function.h in Headers */,
-				A9415BC6243667F800566F16 /* ir_loader.h in Headers */,
-				A9415CFC243667F800566F16 /* inst_bindless_check_pass.h in Headers */,
-				A9415B1A243667F700566F16 /* merge_blocks_reduction_opportunity.h in Headers */,
-				A9415B14243667F700566F16 /* remove_block_reduction_opportunity_finder.h in Headers */,
-				A9415CFA243667F800566F16 /* feature_manager.h in Headers */,
-				A9415ABE243667F700566F16 /* remove_block_reduction_opportunity.h in Headers */,
-				A9415BCA243667F800566F16 /* types.h in Headers */,
-				A9415EB2243667F900566F16 /* validation_state.h in Headers */,
-				A9415E82243667F900566F16 /* spirv_optimizer_options.h in Headers */,
-				A9415AFE243667F700566F16 /* pch_source_reduce.h in Headers */,
-				A9415B82243667F800566F16 /* local_single_store_elim_pass.h in Headers */,
-				A9415C08243667F800566F16 /* struct_cfg_analysis.h in Headers */,
-				A9415CC4243667F800566F16 /* loop_utils.h in Headers */,
-				A9415CD4243667F800566F16 /* loop_descriptor.h in Headers */,
-				A9415C16243667F800566F16 /* process_lines_pass.h in Headers */,
-				A9415C98243667F800566F16 /* passes.h in Headers */,
-				A9415ACC243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */,
-				A9415EA4243667F900566F16 /* basic_block.h in Headers */,
-				A9415CDA243667F800566F16 /* aggressive_dead_code_elim_pass.h in Headers */,
-				A9415BEC243667F800566F16 /* def_use_manager.h in Headers */,
-				A9415B76243667F800566F16 /* compact_ids_pass.h in Headers */,
-				A9415C1E243667F800566F16 /* strength_reduction_pass.h in Headers */,
-				A9415AA6243667F700566F16 /* timer.h in Headers */,
-				A9415E80243667F900566F16 /* instruction.h in Headers */,
-				A9415BF6243667F800566F16 /* local_redundancy_elimination.h in Headers */,
-				A9415C12243667F800566F16 /* decoration_manager.h in Headers */,
-				A9415C9E243667F800566F16 /* strip_reflect_info_pass.h in Headers */,
-				A9415B5C243667F800566F16 /* print.h in Headers */,
-				A9415BA4243667F800566F16 /* instruction_list.h in Headers */,
-				A9415B2A243667F800566F16 /* pch_source.h in Headers */,
-				A9415C8A243667F800566F16 /* dead_branch_elim_pass.h in Headers */,
-				A9415B24243667F700566F16 /* latest_version_opencl_std_header.h in Headers */,
-				A9415BA2243667F800566F16 /* propagator.h in Headers */,
-				A9415BE4243667F800566F16 /* private_to_local_pass.h in Headers */,
-				A9415EC6243667F900566F16 /* validate_scopes.h in Headers */,
-				A9415C8E243667F800566F16 /* scalar_analysis_nodes.h in Headers */,
-				A9415BFE243667F800566F16 /* block_merge_util.h in Headers */,
-				A9415CDE243667F800566F16 /* vector_dce.h in Headers */,
-				A9415C74243667F800566F16 /* ssa_rewrite_pass.h in Headers */,
-				A9415B42243667F800566F16 /* spirv_validator_options.h in Headers */,
-				A9415B64243667F800566F16 /* if_conversion.h in Headers */,
-				A9415B46243667F800566F16 /* text_handler.h in Headers */,
-				A9415B10243667F700566F16 /* reduction_opportunity_finder.h in Headers */,
-				A9415AB4243667F700566F16 /* ilist.h in Headers */,
-				A9415B12243667F700566F16 /* change_operand_reduction_opportunity.h in Headers */,
-				A9415B7C243667F800566F16 /* graphics_robust_access_pass.h in Headers */,
-				A9415E8A243667F900566F16 /* extensions.h in Headers */,
-				A9415CA8243667F800566F16 /* reflect.h in Headers */,
-				A9415CE8243667F800566F16 /* iterator.h in Headers */,
-				A9415B06243667F700566F16 /* reducer.h in Headers */,
-				A9415C92243667F800566F16 /* fix_storage_class.h in Headers */,
-				A9415AA2243667F700566F16 /* small_vector.h in Headers */,
-				A9415CEC243667F800566F16 /* build_module.h in Headers */,
-				A9415AF2243667F700566F16 /* remove_selection_reduction_opportunity_finder.h in Headers */,
-				A9415B3E243667F800566F16 /* spirv_constant.h in Headers */,
-				A9415AAE243667F700566F16 /* hex_float.h in Headers */,
-				A9415CF2243667F800566F16 /* decompose_initialized_variables_pass.h in Headers */,
-				A9415C0E243667F800566F16 /* wrap_opkill.h in Headers */,
-				A9415A94243667F700566F16 /* text.h in Headers */,
-				A9415BF0243667F800566F16 /* cfg_cleanup_pass.h in Headers */,
-				A9415BCC243667F800566F16 /* fold_spec_constant_op_and_composite_pass.h in Headers */,
-				A9415AF4243667F700566F16 /* merge_blocks_reduction_opportunity_finder.h in Headers */,
-				A9415B22243667F700566F16 /* reduction_pass.h in Headers */,
-				A9415C84243667F800566F16 /* eliminate_dead_functions_util.h in Headers */,
-				A9415B80243667F800566F16 /* legalize_vector_shuffle_pass.h in Headers */,
-				A9415E78243667F900566F16 /* ext_inst.h in Headers */,
-				A9415AA0243667F700566F16 /* string_utils.h in Headers */,
-				A9415EE0243667F900566F16 /* instruction.h in Headers */,
-				A9415C06243667F800566F16 /* loop_fusion_pass.h in Headers */,
-				A9415C48243667F800566F16 /* loop_dependence.h in Headers */,
-				A9415AC0243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */,
-				A9415C5C243667F800566F16 /* upgrade_memory_model.h in Headers */,
-				A9415A9A243667F700566F16 /* parse_number.h in Headers */,
-				A9415ADE243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */,
-				A9415CC6243667F800566F16 /* module.h in Headers */,
-				A9415C36243667F800566F16 /* mem_pass.h in Headers */,
-				A9415B36243667F800566F16 /* spirv_definition.h in Headers */,
-				A9415CB2243667F800566F16 /* scalar_replacement_pass.h in Headers */,
-				A9415B28243667F800566F16 /* cfa.h in Headers */,
-				A9415B3C243667F800566F16 /* macro.h in Headers */,
-				A9415C24243667F800566F16 /* inst_debug_printf_pass.h in Headers */,
-				A9415AE6243667F700566F16 /* remove_function_reduction_opportunity.h in Headers */,
-				A9415B98243667F800566F16 /* replace_invalid_opc.h in Headers */,
-				A9415B84243667F800566F16 /* reduce_load_size.h in Headers */,
-				A9415C4A243667F800566F16 /* value_number_table.h in Headers */,
-				A9415C7C243667F800566F16 /* dominator_analysis.h in Headers */,
-				A9415D02243667F800566F16 /* dominator_tree.h in Headers */,
-				A9415A8A243667F700566F16 /* spirv_fuzzer_options.h in Headers */,
-				A9415C52243667F800566F16 /* constants.h in Headers */,
-				A9415C66243667F800566F16 /* workaround1209.h in Headers */,
-				A9415CE2243667F800566F16 /* pass_manager.h in Headers */,
-				A9415C64243667F800566F16 /* loop_fission.h in Headers */,
-				A9415B74243667F800566F16 /* composite.h in Headers */,
-				A9415EF2243667F900566F16 /* decoration.h in Headers */,
-				A9415B18243667F700566F16 /* reduction_util.h in Headers */,
-				A9415CB6243667F800566F16 /* pch_source_opt.h in Headers */,
-				A9415BD6243667F800566F16 /* block_merge_pass.h in Headers */,
-				A9415CD0243667F800566F16 /* cfg.h in Headers */,
-				A9415C78243667F800566F16 /* dead_variable_elimination.h in Headers */,
-				A9415C30243667F800566F16 /* freeze_spec_constant_value_pass.h in Headers */,
-				A9415CD2243667F800566F16 /* code_sink.h in Headers */,
-				A9415BFA243667F800566F16 /* loop_peeling.h in Headers */,
-				A9415ECA243667F900566F16 /* validate_memory_semantics.h in Headers */,
-				A9415B00243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.h in Headers */,
-				A9415A9C243667F700566F16 /* ilist_node.h in Headers */,
-				A9415C2C243667F800566F16 /* dead_insert_elim_pass.h in Headers */,
-				A9415A8E243667F700566F16 /* enum_set.h in Headers */,
-				A9415AC6243667F700566F16 /* operand_to_const_reduction_opportunity_finder.h in Headers */,
-				A9415D00243667F800566F16 /* set_spec_constant_default_value_pass.h in Headers */,
-				A9415C50243667F800566F16 /* inline_exhaustive_pass.h in Headers */,
-				A9415C18243667F800566F16 /* local_single_block_elim_pass.h in Headers */,
-				A9415B6A243667F800566F16 /* merge_return_pass.h in Headers */,
-				A9415C02243667F800566F16 /* desc_sroa.h in Headers */,
-				A9415BAE243667F800566F16 /* amd_ext_to_khr.h in Headers */,
-				A9415BE8243667F800566F16 /* relax_float_ops_pass.h in Headers */,
-				A9415CAC243667F800566F16 /* null_pass.h in Headers */,
-				A9415B9A243667F800566F16 /* local_access_chain_convert_pass.h in Headers */,
-				A9415AEC243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */,
-				A9415E7C243667F900566F16 /* latest_version_spirv_header.h in Headers */,
-				A9415CA4243667F800566F16 /* remove_duplicates_pass.h in Headers */,
-				A9415AE8243667F700566F16 /* change_operand_to_undef_reduction_opportunity.h in Headers */,
-				A9415CCE243667F800566F16 /* loop_unswitch_pass.h in Headers */,
-				A9415BE6243667F800566F16 /* convert_to_half_pass.h in Headers */,
-				A9415C86243667F800566F16 /* fold.h in Headers */,
-				A9415E88243667F900566F16 /* latest_version_glsl_std_450_header.h in Headers */,
-				A9415B78243667F800566F16 /* register_pressure.h in Headers */,
-				A9415B6C243667F800566F16 /* inline_opaque_pass.h in Headers */,
-				A9415C7E243667F800566F16 /* pass.h in Headers */,
-				A9415AAA243667F700566F16 /* bit_vector.h in Headers */,
-				A9415C6A243667F800566F16 /* log.h in Headers */,
-				A9415B48243667F800566F16 /* parsed_operand.h in Headers */,
-				A9415CF4243667F800566F16 /* function.h in Headers */,
-				A9415E84243667F900566F16 /* opcode.h in Headers */,
-				A9415BBC243667F800566F16 /* loop_unroller.h in Headers */,
+				A9765F3C2485758600FDD115 /* types.h in Headers */,
+				A97660562485758600FDD115 /* combine_access_chains.h in Headers */,
+				A9765E542485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.h in Headers */,
+				A9765FE22485758600FDD115 /* split_invalid_unreachable_pass.h in Headers */,
+				A9765F482485758600FDD115 /* block_merge_pass.h in Headers */,
+				A9765FF62485758600FDD115 /* folding_rules.h in Headers */,
+				A97660482485758600FDD115 /* code_sink.h in Headers */,
+				A9765F7C2485758600FDD115 /* struct_cfg_analysis.h in Headers */,
+				A976607C2485758600FDD115 /* type_manager.h in Headers */,
+				A976604A2485758600FDD115 /* loop_descriptor.h in Headers */,
+				A9765F7A2485758600FDD115 /* loop_fusion_pass.h in Headers */,
+				A9765EAA2485758600FDD115 /* operand.h in Headers */,
+				A9765E842485758600FDD115 /* remove_block_reduction_opportunity_finder.h in Headers */,
+				A9765EAE2485758600FDD115 /* macro.h in Headers */,
+				A9765E802485758600FDD115 /* reduction_opportunity_finder.h in Headers */,
+				A9765F8A2485758600FDD115 /* process_lines_pass.h in Headers */,
+				A9765E9A2485758600FDD115 /* cfa.h in Headers */,
+				A9765EE62485758600FDD115 /* composite.h in Headers */,
+				A9765F822485758600FDD115 /* wrap_opkill.h in Headers */,
+				A97662202485758700FDD115 /* construct.h in Headers */,
+				A9765F722485758600FDD115 /* block_merge_util.h in Headers */,
+				A9765E762485758600FDD115 /* reducer.h in Headers */,
+				A9765E242485758500FDD115 /* operand_to_undef_reduction_opportunity_finder.h in Headers */,
+				A976622A2485758700FDD115 /* basic_block.h in Headers */,
+				A97661FE2485758700FDD115 /* ext_inst.h in Headers */,
+				A9765EEE2485758600FDD115 /* graphics_robust_access_pass.h in Headers */,
+				A97660222485758600FDD115 /* null_pass.h in Headers */,
+				A976601A2485758600FDD115 /* remove_duplicates_pass.h in Headers */,
+				A9765E5E2485758600FDD115 /* remove_selection_reduction_opportunity_finder.h in Headers */,
+				A9765EC22485758600FDD115 /* diagnostic.h in Headers */,
+				A9765E3C2485758500FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.h in Headers */,
+				A97660442485758600FDD115 /* loop_unswitch_pass.h in Headers */,
+				A97660622485758600FDD115 /* build_module.h in Headers */,
+				A9765F862485758600FDD115 /* decoration_manager.h in Headers */,
+				A9765FE02485758600FDD115 /* log.h in Headers */,
+				A9765FA82485758600FDD115 /* instrument_pass.h in Headers */,
+				A9765F142485758600FDD115 /* propagator.h in Headers */,
+				A976620E2485758700FDD115 /* latest_version_glsl_std_450_header.h in Headers */,
+				A97662062485758700FDD115 /* instruction.h in Headers */,
+				A976620A2485758700FDD115 /* opcode.h in Headers */,
+				A9765EBC2485758600FDD115 /* name_mapper.h in Headers */,
+				A9765F362485758600FDD115 /* unify_const_pass.h in Headers */,
+				A9765E4A2485758600FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.h in Headers */,
+				A976606A2485758600FDD115 /* function.h in Headers */,
+				A9765ED22485758600FDD115 /* disassemble.h in Headers */,
+				A9765E162485758500FDD115 /* bitutils.h in Headers */,
+				A9765E202485758500FDD115 /* spirv_target_env.h in Headers */,
+				A976604E2485758600FDD115 /* instruction.h in Headers */,
+				A9765F2E2485758600FDD115 /* loop_unroller.h in Headers */,
+				A9765EFE2485758600FDD115 /* strip_debug_info_pass.h in Headers */,
+				A9765E702485758600FDD115 /* pch_source_reduce.h in Headers */,
+				A9765E082485758500FDD115 /* make_unique.h in Headers */,
+				A9765EA22485758600FDD115 /* spirv_reducer_options.h in Headers */,
+				A9765E3A2485758500FDD115 /* remove_instruction_reduction_opportunity.h in Headers */,
+				A97660042485758600FDD115 /* scalar_analysis_nodes.h in Headers */,
+				A9765E502485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.h in Headers */,
+				A9765FE62485758600FDD115 /* eliminate_dead_constant_pass.h in Headers */,
+				A9765FD22485758600FDD115 /* upgrade_memory_model.h in Headers */,
+				A9765DF62485758500FDD115 /* assembly_grammar.h in Headers */,
+				A97660302485758600FDD115 /* redundancy_elimination.h in Headers */,
+				A9765EB02485758600FDD115 /* spirv_constant.h in Headers */,
+				A9765E282485758500FDD115 /* remove_block_reduction_opportunity.h in Headers */,
+				A97660582485758600FDD115 /* pass_manager.h in Headers */,
+				A9765FF22485758600FDD115 /* dominator_analysis.h in Headers */,
+				A97660082485758600FDD115 /* fix_storage_class.h in Headers */,
+				A9765F5C2485758600FDD115 /* relax_float_ops_pass.h in Headers */,
+				A9765FDA2485758600FDD115 /* loop_fission.h in Headers */,
+				A9765F422485758600FDD115 /* basic_block.h in Headers */,
+				A97660642485758600FDD115 /* ccp_pass.h in Headers */,
+				A9765EF42485758600FDD115 /* local_single_store_elim_pass.h in Headers */,
+				A9765FBE2485758600FDD115 /* value_number_table.h in Headers */,
+				A97660182485758600FDD115 /* simplification_pass.h in Headers */,
+				A976603A2485758600FDD115 /* loop_utils.h in Headers */,
+				A9765F6A2485758600FDD115 /* local_redundancy_elimination.h in Headers */,
+				A9765F982485758600FDD115 /* inst_debug_printf_pass.h in Headers */,
+				A97660722485758600FDD115 /* inst_bindless_check_pass.h in Headers */,
+				A97660682485758600FDD115 /* decompose_initialized_variables_pass.h in Headers */,
+				A9765E482485758600FDD115 /* remove_struct_member_reduction_opportunity.h in Headers */,
+				A9765EFC2485758600FDD115 /* scalar_analysis.h in Headers */,
+				A9765F3E2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.h in Headers */,
+				A97660762485758600FDD115 /* set_spec_constant_default_value_pass.h in Headers */,
+				A976624C2485758700FDD115 /* validate_scopes.h in Headers */,
+				A97660602485758600FDD115 /* licm_pass.h in Headers */,
+				A9765FDC2485758600FDD115 /* workaround1209.h in Headers */,
+				A9765E942485758600FDD115 /* reduction_pass.h in Headers */,
+				A97660262485758600FDD115 /* const_folding_rules.h in Headers */,
+				A9765F582485758600FDD115 /* private_to_local_pass.h in Headers */,
+				A9765E602485758600FDD115 /* merge_blocks_reduction_opportunity_finder.h in Headers */,
+				A9765EF22485758600FDD115 /* legalize_vector_shuffle_pass.h in Headers */,
+				A9765E962485758600FDD115 /* latest_version_opencl_std_header.h in Headers */,
+				A9765EB82485758600FDD115 /* text_handler.h in Headers */,
+				A9765FEA2485758600FDD115 /* ssa_rewrite_pass.h in Headers */,
+				A9765E362485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.h in Headers */,
+				A9765FC82485758600FDD115 /* constants.h in Headers */,
+				A976605E2485758600FDD115 /* iterator.h in Headers */,
+				A9765F162485758600FDD115 /* instruction_list.h in Headers */,
+				A9765FF42485758600FDD115 /* pass.h in Headers */,
+				A9765EEC2485758600FDD115 /* tree_iterator.h in Headers */,
+				A9765F382485758600FDD115 /* ir_loader.h in Headers */,
+				A97660422485758600FDD115 /* ir_builder.h in Headers */,
+				A9765E662485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.h in Headers */,
+				A9765F902485758600FDD115 /* inst_buff_addr_check_pass.h in Headers */,
+				A97662022485758700FDD115 /* latest_version_spirv_header.h in Headers */,
+				A9765E522485758600FDD115 /* remove_function_reduction_opportunity.h in Headers */,
+				A97660282485758600FDD115 /* scalar_replacement_pass.h in Headers */,
+				A9765E102485758500FDD115 /* timer.h in Headers */,
+				A9765E1E2485758500FDD115 /* ilist.h in Headers */,
+				A97662082485758700FDD115 /* spirv_optimizer_options.h in Headers */,
+				A97662382485758700FDD115 /* validation_state.h in Headers */,
+				A9765E0C2485758500FDD115 /* small_vector.h in Headers */,
+				A97662702485758700FDD115 /* function.h in Headers */,
+				A9765EDC2485758600FDD115 /* merge_return_pass.h in Headers */,
+				A9765E882485758600FDD115 /* reduction_util.h in Headers */,
+				A9765E182485758500FDD115 /* hex_float.h in Headers */,
+				A97662442485758700FDD115 /* validate.h in Headers */,
+				A976601E2485758600FDD115 /* reflect.h in Headers */,
+				A9765F602485758600FDD115 /* def_use_manager.h in Headers */,
+				A9765E562485758600FDD115 /* change_operand_to_undef_reduction_opportunity.h in Headers */,
+				A9765FBA2485758600FDD115 /* inline_pass.h in Headers */,
+				A9765F762485758600FDD115 /* desc_sroa.h in Headers */,
+				A9765E8A2485758600FDD115 /* merge_blocks_reduction_opportunity.h in Headers */,
+				A9765F8C2485758600FDD115 /* local_single_block_elim_pass.h in Headers */,
+				A9765E5A2485758600FDD115 /* remove_selection_reduction_opportunity.h in Headers */,
+				A9765FA02485758600FDD115 /* dead_insert_elim_pass.h in Headers */,
+				A9765FE42485758600FDD115 /* copy_prop_arrays.h in Headers */,
+				A97660502485758600FDD115 /* aggressive_dead_code_elim_pass.h in Headers */,
+				A9765FAE2485758600FDD115 /* eliminate_dead_members_pass.h in Headers */,
+				A97662782485758700FDD115 /* decoration.h in Headers */,
+				A9765EDE2485758600FDD115 /* inline_opaque_pass.h in Headers */,
+				A9765E9C2485758600FDD115 /* pch_source.h in Headers */,
+				A9765E9E2485758600FDD115 /* enum_string_mapping.h in Headers */,
+				A9765DFE2485758500FDD115 /* text.h in Headers */,
+				A976603C2485758600FDD115 /* module.h in Headers */,
+				A9765F6E2485758600FDD115 /* loop_peeling.h in Headers */,
+				A976602C2485758600FDD115 /* pch_source_opt.h in Headers */,
+				A97660462485758600FDD115 /* cfg.h in Headers */,
+				A9765FBC2485758600FDD115 /* loop_dependence.h in Headers */,
+				A9765E0A2485758500FDD115 /* string_utils.h in Headers */,
+				A9765FEE2485758600FDD115 /* dead_variable_elimination.h in Headers */,
+				A9765EC42485758600FDD115 /* spirv_endian.h in Headers */,
+				A9765EE02485758600FDD115 /* loop_fusion.h in Headers */,
+				A9765F4C2485758600FDD115 /* debug_info_manager.h in Headers */,
+				A97660822485758600FDD115 /* table.h in Headers */,
+				A9765F922485758600FDD115 /* strength_reduction_pass.h in Headers */,
+				A9765E2A2485758500FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.h in Headers */,
+				A9765E042485758500FDD115 /* parse_number.h in Headers */,
+				A9765DF42485758500FDD115 /* spirv_fuzzer_options.h in Headers */,
+				A976604C2485758600FDD115 /* generate_webgpu_initializers_pass.h in Headers */,
+				A9765E062485758500FDD115 /* ilist_node.h in Headers */,
+				A97660002485758600FDD115 /* dead_branch_elim_pass.h in Headers */,
+				A9765E582485758600FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.h in Headers */,
+				A9765F642485758600FDD115 /* cfg_cleanup_pass.h in Headers */,
+				A976600E2485758600FDD115 /* passes.h in Headers */,
+				A97660782485758600FDD115 /* dominator_tree.h in Headers */,
+				A9765F5A2485758600FDD115 /* convert_to_half_pass.h in Headers */,
+				A9765FA42485758600FDD115 /* freeze_spec_constant_value_pass.h in Headers */,
+				A9765EEA2485758600FDD115 /* register_pressure.h in Headers */,
+				A9765EB42485758600FDD115 /* spirv_validator_options.h in Headers */,
+				A9765EA82485758600FDD115 /* spirv_definition.h in Headers */,
+				A9765E6E2485758600FDD115 /* remove_function_reduction_opportunity_finder.h in Headers */,
+				A97662662485758700FDD115 /* instruction.h in Headers */,
+				A9765FF82485758600FDD115 /* eliminate_dead_functions_pass.h in Headers */,
+				A97662502485758700FDD115 /* validate_memory_semantics.h in Headers */,
+				A9765EE82485758600FDD115 /* compact_ids_pass.h in Headers */,
+				A9765E822485758600FDD115 /* change_operand_reduction_opportunity.h in Headers */,
+				A9765FFC2485758600FDD115 /* fold.h in Headers */,
+				A9765E7A2485758600FDD115 /* reduction_opportunity.h in Headers */,
+				A97660142485758600FDD115 /* strip_reflect_info_pass.h in Headers */,
+				A97662102485758700FDD115 /* extensions.h in Headers */,
+				A97660542485758600FDD115 /* vector_dce.h in Headers */,
+				A9765F0C2485758600FDD115 /* local_access_chain_convert_pass.h in Headers */,
+				A9765ECE2485758600FDD115 /* print.h in Headers */,
+				A9765DF82485758500FDD115 /* enum_set.h in Headers */,
+				A9765FC02485758600FDD115 /* flatten_decoration_pass.h in Headers */,
+				A9765FAA2485758600FDD115 /* mem_pass.h in Headers */,
+				A97662142485758700FDD115 /* binary.h in Headers */,
+				A9765ED62485758600FDD115 /* if_conversion.h in Headers */,
+				A9765EF02485758600FDD115 /* strip_atomic_counter_memory_pass.h in Headers */,
+				A9765E302485758500FDD115 /* operand_to_const_reduction_opportunity_finder.h in Headers */,
+				A9765EBA2485758600FDD115 /* parsed_operand.h in Headers */,
+				A9765E142485758500FDD115 /* bit_vector.h in Headers */,
+				A97660702485758600FDD115 /* feature_manager.h in Headers */,
+				A9765E7C2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.h in Headers */,
+				A9765F0A2485758600FDD115 /* replace_invalid_opc.h in Headers */,
+				A9765FC62485758600FDD115 /* inline_exhaustive_pass.h in Headers */,
+				A9765EF62485758600FDD115 /* reduce_load_size.h in Headers */,
+				A9765FFA2485758600FDD115 /* eliminate_dead_functions_util.h in Headers */,
+				A9765F202485758600FDD115 /* amd_ext_to_khr.h in Headers */,
+				A9765F242485758600FDD115 /* ir_context.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2980,7 +3010,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A972A7E421CEC72F0013AB25 = {
@@ -3101,205 +3131,208 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A9415C31243667F800566F16 /* ir_context.cpp in Sources */,
-				A9415BF7243667F800566F16 /* split_invalid_unreachable_pass.cpp in Sources */,
-				A9415C67243667F800566F16 /* loop_fusion_pass.cpp in Sources */,
-				A9415C9B243667F800566F16 /* amd_ext_to_khr.cpp in Sources */,
-				A9415EC7243667F900566F16 /* validate_id.cpp in Sources */,
-				A9415B9D243667F800566F16 /* local_redundancy_elimination.cpp in Sources */,
-				A9415ECD243667F900566F16 /* validate_mode_setting.cpp in Sources */,
-				A9415E91243667F900566F16 /* validate_annotation.cpp in Sources */,
-				A9415B4D243667F800566F16 /* parsed_operand.cpp in Sources */,
-				A9415BB5243667F800566F16 /* cfg_cleanup_pass.cpp in Sources */,
-				A9415C95243667F800566F16 /* set_spec_constant_default_value_pass.cpp in Sources */,
-				A9415C55243667F800566F16 /* strength_reduction_pass.cpp in Sources */,
-				A9415B8F243667F800566F16 /* strip_atomic_counter_memory_pass.cpp in Sources */,
-				A9415EA7243667F900566F16 /* validate_decorations.cpp in Sources */,
-				A9415AF7243667F700566F16 /* reducer.cpp in Sources */,
-				A9415C5D243667F800566F16 /* copy_prop_arrays.cpp in Sources */,
-				A9415ECF243667F900566F16 /* validate_memory_semantics.cpp in Sources */,
-				A9415C43243667F800566F16 /* process_lines_pass.cpp in Sources */,
-				A9415BFF243667F800566F16 /* loop_unroller.cpp in Sources */,
-				A9415BC1243667F800566F16 /* loop_dependence.cpp in Sources */,
-				A9415AD3243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */,
-				A9415B95243667F800566F16 /* freeze_spec_constant_value_pass.cpp in Sources */,
-				A9415BA5243667F800566F16 /* feature_manager.cpp in Sources */,
-				A9415BFB243667F800566F16 /* vector_dce.cpp in Sources */,
-				A9415E7D243667F900566F16 /* libspirv.cpp in Sources */,
-				A9415B15243667F700566F16 /* remove_block_reduction_opportunity_finder.cpp in Sources */,
-				A9415D03243667F800566F16 /* legalize_vector_shuffle_pass.cpp in Sources */,
-				A9415EE1243667F900566F16 /* validate_execution_limitations.cpp in Sources */,
-				A9415E79243667F900566F16 /* diagnostic.cpp in Sources */,
-				A9415BCD243667F800566F16 /* mem_pass.cpp in Sources */,
-				A9415C5F243667F800566F16 /* pass_manager.cpp in Sources */,
-				A9415B91243667F800566F16 /* decoration_manager.cpp in Sources */,
-				A9415C8B243667F800566F16 /* private_to_local_pass.cpp in Sources */,
-				A9415C13243667F800566F16 /* ccp_pass.cpp in Sources */,
-				A9415CBF243667F800566F16 /* inline_opaque_pass.cpp in Sources */,
-				A9415BA7243667F800566F16 /* pass.cpp in Sources */,
-				A9415D07243667F800566F16 /* compact_ids_pass.cpp in Sources */,
-				A9415BBF243667F800566F16 /* ssa_rewrite_pass.cpp in Sources */,
-				A9415AEF243667F700566F16 /* remove_instruction_reduction_opportunity.cpp in Sources */,
-				A9415BAF243667F800566F16 /* merge_return_pass.cpp in Sources */,
-				A9415BB7243667F800566F16 /* wrap_opkill.cpp in Sources */,
-				A9415B5D243667F800566F16 /* ext_inst.cpp in Sources */,
-				A9415C25243667F800566F16 /* simplification_pass.cpp in Sources */,
-				A9415B1D243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */,
-				A9415A8F243667F700566F16 /* text.cpp in Sources */,
-				A9415EBF243667F900566F16 /* validate_adjacency.cpp in Sources */,
-				A9415C3F243667F800566F16 /* composite.cpp in Sources */,
-				A9415BD9243667F800566F16 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */,
-				A9415B55243667F800566F16 /* linker.cpp in Sources */,
-				A9415B4B243667F800566F16 /* spirv_reducer_options.cpp in Sources */,
-				A9415B67243667F800566F16 /* loop_utils.cpp in Sources */,
-				A9415A97243667F700566F16 /* pch_source.cpp in Sources */,
-				A9415C1F243667F800566F16 /* aggressive_dead_code_elim_pass.cpp in Sources */,
-				A9415CB3243667F800566F16 /* instruction.cpp in Sources */,
-				A9415CC9243667F800566F16 /* decompose_initialized_variables_pass.cpp in Sources */,
-				A9415B2D243667F800566F16 /* spirv_fuzzer_options.cpp in Sources */,
-				A9415BB3243667F800566F16 /* eliminate_dead_constant_pass.cpp in Sources */,
-				A9415AD5243667F700566F16 /* remove_function_reduction_opportunity.cpp in Sources */,
-				A9415AD9243667F700566F16 /* remove_selection_reduction_opportunity_finder.cpp in Sources */,
-				A9415C93243667F800566F16 /* loop_dependence_helpers.cpp in Sources */,
-				A9415BD1243667F800566F16 /* remove_duplicates_pass.cpp in Sources */,
-				A9415ADB243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */,
-				A9415ED7243667F900566F16 /* validate_image.cpp in Sources */,
-				A9415AB7243667F700566F16 /* table.cpp in Sources */,
-				A9415CAD243667F800566F16 /* relax_float_ops_pass.cpp in Sources */,
-				A9415B31243667F800566F16 /* spirv_validator_options.cpp in Sources */,
-				A9415BBD243667F800566F16 /* strip_debug_info_pass.cpp in Sources */,
-				A9415ED1243667F900566F16 /* validate_logicals.cpp in Sources */,
-				A9415B0D243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */,
-				A9415ACD243667F700566F16 /* remove_function_reduction_opportunity_finder.cpp in Sources */,
-				A9415C41243667F800566F16 /* convert_to_half_pass.cpp in Sources */,
-				A9415EE7243667F900566F16 /* validate_function.cpp in Sources */,
-				A9415B33243667F800566F16 /* print.cpp in Sources */,
-				A9415EC3243667F900566F16 /* validate_small_type_uses.cpp in Sources */,
-				A9415A87243667F700566F16 /* spirv_target_env.cpp in Sources */,
-				A9415ABB243667F700566F16 /* remove_selection_reduction_opportunity.cpp in Sources */,
-				A9415C61243667F800566F16 /* inline_exhaustive_pass.cpp in Sources */,
-				A9415BDB243667F800566F16 /* loop_unswitch_pass.cpp in Sources */,
-				A9415BAB243667F800566F16 /* dominator_tree.cpp in Sources */,
-				A9415AA7243667F700566F16 /* string_utils.cpp in Sources */,
-				A9415EE5243667F900566F16 /* basic_block.cpp in Sources */,
-				A9415BF3243667F800566F16 /* eliminate_dead_functions_pass.cpp in Sources */,
-				A9415CA9243667F800566F16 /* workaround1209.cpp in Sources */,
-				A9415ED5243667F900566F16 /* validate_memory.cpp in Sources */,
-				A9415BED243667F800566F16 /* ir_loader.cpp in Sources */,
-				A9415AAF243667F700566F16 /* parse_number.cpp in Sources */,
-				A9415AC7243667F700566F16 /* reduction_util.cpp in Sources */,
-				A9415C8F243667F800566F16 /* propagator.cpp in Sources */,
-				A9415B03243667F700566F16 /* reduction_opportunity.cpp in Sources */,
-				A9415C2D243667F800566F16 /* folding_rules.cpp in Sources */,
-				A9415C53243667F800566F16 /* eliminate_dead_members_pass.cpp in Sources */,
-				A9415BE9243667F800566F16 /* inline_pass.cpp in Sources */,
-				A9415EA9243667F900566F16 /* validate_debug.cpp in Sources */,
-				A9415BD7243667F800566F16 /* module.cpp in Sources */,
-				A9415BD3243667F800566F16 /* dead_variable_elimination.cpp in Sources */,
-				A9415A91243667F700566F16 /* assembly_grammar.cpp in Sources */,
-				A9415C4D243667F800566F16 /* if_conversion.cpp in Sources */,
-				A9415AE1243667F700566F16 /* change_operand_reduction_opportunity.cpp in Sources */,
-				A9415AD7243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */,
-				A9415E85243667F900566F16 /* operand.cpp in Sources */,
-				A9415BE1243667F800566F16 /* generate_webgpu_initializers_pass.cpp in Sources */,
-				A9415EB7243667F900566F16 /* validate_extensions.cpp in Sources */,
-				A9415C87243667F800566F16 /* local_single_store_elim_pass.cpp in Sources */,
-				A9415C79243667F800566F16 /* block_merge_pass.cpp in Sources */,
-				A9415AE9243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp in Sources */,
-				A9415C21243667F800566F16 /* eliminate_dead_functions_util.cpp in Sources */,
-				A9415C59243667F800566F16 /* block_merge_util.cpp in Sources */,
-				A9415CFD243667F800566F16 /* scalar_analysis_simplification.cpp in Sources */,
-				A9415AF5243667F700566F16 /* pch_source_reduce.cpp in Sources */,
-				A9415CB7243667F800566F16 /* reduce_load_size.cpp in Sources */,
-				A9415C09243667F800566F16 /* inst_buff_addr_check_pass.cpp in Sources */,
-				A9415C99243667F800566F16 /* fold.cpp in Sources */,
-				A9415EAB243667F900566F16 /* validate_builtins.cpp in Sources */,
-				A9415C3D243667F800566F16 /* instruction_list.cpp in Sources */,
-				A9415AB1243667F700566F16 /* bit_vector.cpp in Sources */,
-				A9415B93243667F800566F16 /* local_single_block_elim_pass.cpp in Sources */,
-				A9415E8B243667F900566F16 /* disassemble.cpp in Sources */,
-				A9415B3F243667F800566F16 /* binary.cpp in Sources */,
-				A9415B61243667F800566F16 /* optimizer.cpp in Sources */,
-				A9415BB9243667F800566F16 /* const_folding_rules.cpp in Sources */,
-				A9415AF9243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */,
-				A9415A95243667F700566F16 /* extensions.cpp in Sources */,
-				A9415C3B243667F800566F16 /* function.cpp in Sources */,
-				A9415CE5243667F800566F16 /* basic_block.cpp in Sources */,
-				A9415E95243667F900566F16 /* validate_cfg.cpp in Sources */,
-				A9415B1F243667F700566F16 /* remove_block_reduction_opportunity.cpp in Sources */,
-				A9415C57243667F800566F16 /* desc_sroa.cpp in Sources */,
-				A9415B1B243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */,
-				A9415C27243667F800566F16 /* dead_branch_elim_pass.cpp in Sources */,
-				A9415CF5243667F800566F16 /* loop_fusion.cpp in Sources */,
-				A9415EBB243667F900566F16 /* function.cpp in Sources */,
-				A9415EB9243667F900566F16 /* construct.cpp in Sources */,
-				A9415B25243667F700566F16 /* spirv_optimizer_options.cpp in Sources */,
-				A9415BF1243667F800566F16 /* licm_pass.cpp in Sources */,
-				A9415EEB243667F900566F16 /* validate_composites.cpp in Sources */,
-				A9415ED3243667F900566F16 /* validate_derivatives.cpp in Sources */,
-				A9415B8D243667F800566F16 /* cfg.cpp in Sources */,
-				A9415C9F243667F800566F16 /* scalar_replacement_pass.cpp in Sources */,
-				A9415E9F243667F900566F16 /* validate_scopes.cpp in Sources */,
-				A9415E93243667F900566F16 /* validate_misc.cpp in Sources */,
-				A9415B57243667F800566F16 /* software_version.cpp in Sources */,
-				A9415E9B243667F900566F16 /* validate_barriers.cpp in Sources */,
-				A9415CEF243667F800566F16 /* graphics_robust_access_pass.cpp in Sources */,
-				A9415B87243667F800566F16 /* types.cpp in Sources */,
-				A9415EAF243667F900566F16 /* validate.cpp in Sources */,
-				A9415BDD243667F800566F16 /* unify_const_pass.cpp in Sources */,
-				A9415EE3243667F900566F16 /* validate_layout.cpp in Sources */,
-				A9415EA5243667F900566F16 /* validate_instruction.cpp in Sources */,
-				A9415EDB243667F900566F16 /* instruction.cpp in Sources */,
-				A9415C19243667F800566F16 /* pch_source_opt.cpp in Sources */,
-				A9415AC9243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */,
-				A9415CBD243667F800566F16 /* value_number_table.cpp in Sources */,
-				A9415B9B243667F800566F16 /* inst_bindless_check_pass.cpp in Sources */,
-				A9415ED9243667F900566F16 /* validate_literals.cpp in Sources */,
-				A9415ADF243667F700566F16 /* merge_blocks_reduction_opportunity.cpp in Sources */,
-				A9415B6F243667F800566F16 /* combine_access_chains.cpp in Sources */,
-				A9415C0F243667F800566F16 /* strip_reflect_info_pass.cpp in Sources */,
-				A9415E9D243667F900566F16 /* validate_non_uniform.cpp in Sources */,
-				A9415B07243667F700566F16 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */,
-				A9415B71243667F800566F16 /* build_module.cpp in Sources */,
-				A9415EED243667F900566F16 /* validation_state.cpp in Sources */,
-				A9415EDD243667F900566F16 /* validate_type.cpp in Sources */,
-				A9415AC1243667F700566F16 /* reduction_pass.cpp in Sources */,
-				A9415C71243667F800566F16 /* dead_insert_elim_pass.cpp in Sources */,
-				A9415D09243667F800566F16 /* loop_peeling.cpp in Sources */,
-				A9415CF7243667F800566F16 /* upgrade_memory_model.cpp in Sources */,
-				A9415B59243667F800566F16 /* opcode.cpp in Sources */,
-				A9415C29243667F800566F16 /* flatten_decoration_pass.cpp in Sources */,
-				A9415AA3243667F700566F16 /* timer.cpp in Sources */,
-				A9415C75243667F800566F16 /* scalar_analysis.cpp in Sources */,
-				A9415BDF243667F800566F16 /* type_manager.cpp in Sources */,
-				A9415CDB243667F800566F16 /* struct_cfg_analysis.cpp in Sources */,
-				A9415B53243667F800566F16 /* name_mapper.cpp in Sources */,
-				A9415C0B243667F800566F16 /* def_use_manager.cpp in Sources */,
-				A9415B9F243667F800566F16 /* instrument_pass.cpp in Sources */,
-				A9415BA9243667F800566F16 /* loop_fission.cpp in Sources */,
-				A9415B65243667F800566F16 /* register_pressure.cpp in Sources */,
-				A9415C37243667F800566F16 /* loop_descriptor.cpp in Sources */,
-				A9415CC7243667F800566F16 /* dominator_analysis.cpp in Sources */,
-				A9415AC3243667F700566F16 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */,
-				A9415EA1243667F900566F16 /* validate_atomics.cpp in Sources */,
-				A9415BC7243667F800566F16 /* inst_debug_printf_pass.cpp in Sources */,
-				A9415EB5243667F900566F16 /* validate_bitwise.cpp in Sources */,
-				A9415B01243667F700566F16 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */,
-				A9415ECB243667F900566F16 /* validate_arithmetics.cpp in Sources */,
-				A9415E97243667F900566F16 /* validate_capability.cpp in Sources */,
-				A9415EEF243667F900566F16 /* validate_primitives.cpp in Sources */,
-				A9415CE3243667F800566F16 /* local_access_chain_convert_pass.cpp in Sources */,
-				A9415EB3243667F900566F16 /* validate_constants.cpp in Sources */,
-				A9415EAD243667F900566F16 /* validate_interfaces.cpp in Sources */,
-				A9415EC1243667F900566F16 /* validate_conversion.cpp in Sources */,
-				A9415B85243667F800566F16 /* code_sink.cpp in Sources */,
-				A9415CA5243667F800566F16 /* redundancy_elimination.cpp in Sources */,
-				A9415B39243667F800566F16 /* spirv_endian.cpp in Sources */,
-				A9415C03243667F800566F16 /* constants.cpp in Sources */,
-				A9415CC1243667F800566F16 /* replace_invalid_opc.cpp in Sources */,
-				A9415B43243667F800566F16 /* enum_string_mapping.cpp in Sources */,
-				A9415E8F243667F900566F16 /* text_handler.cpp in Sources */,
-				A9415CBB243667F800566F16 /* fix_storage_class.cpp in Sources */,
+				A976626B2485758700FDD115 /* basic_block.cpp in Sources */,
+				A9765EBD2485758600FDD115 /* spirv_reducer_options.cpp in Sources */,
+				A97662252485758700FDD115 /* validate_scopes.cpp in Sources */,
+				A9765F7F2485758600FDD115 /* def_use_manager.cpp in Sources */,
+				A9765FC32485758600FDD115 /* debug_info_manager.cpp in Sources */,
+				A9765F1B2485758600FDD115 /* loop_fission.cpp in Sources */,
+				A9765FDD2485758600FDD115 /* loop_fusion_pass.cpp in Sources */,
+				A97662392485758700FDD115 /* validate_constants.cpp in Sources */,
+				A9765F772485758600FDD115 /* constants.cpp in Sources */,
+				A976600F2485758600FDD115 /* fold.cpp in Sources */,
+				A9765EB12485758600FDD115 /* binary.cpp in Sources */,
+				A9765FAF2485758600FDD115 /* function.cpp in Sources */,
+				A9765E7D2485758600FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */,
+				A9765EF72485758600FDD115 /* code_sink.cpp in Sources */,
+				A9765E3D2485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */,
+				A97662312485758700FDD115 /* validate_builtins.cpp in Sources */,
+				A9765F552485758600FDD115 /* generate_webgpu_initializers_pass.cpp in Sources */,
+				A9765DF92485758500FDD115 /* text.cpp in Sources */,
+				A97660732485758600FDD115 /* scalar_analysis_simplification.cpp in Sources */,
+				A976622D2485758700FDD115 /* validate_decorations.cpp in Sources */,
+				A9765ECB2485758600FDD115 /* opcode.cpp in Sources */,
+				A9765E692485758600FDD115 /* reducer.cpp in Sources */,
+				A97662032485758700FDD115 /* libspirv.cpp in Sources */,
+				A9765F192485758600FDD115 /* pass.cpp in Sources */,
+				A97662192485758700FDD115 /* validate_misc.cpp in Sources */,
+				A97662672485758700FDD115 /* validate_execution_limitations.cpp in Sources */,
+				A9765E012485758500FDD115 /* pch_source.cpp in Sources */,
+				A97660292485758600FDD115 /* instruction.cpp in Sources */,
+				A97662592485758700FDD115 /* validate_derivatives.cpp in Sources */,
+				A9765F212485758600FDD115 /* merge_return_pass.cpp in Sources */,
+				A9765F832485758600FDD115 /* strip_reflect_info_pass.cpp in Sources */,
+				A9765E3F2485758500FDD115 /* remove_function_reduction_opportunity.cpp in Sources */,
+				A97662512485758700FDD115 /* validate_arithmetics.cpp in Sources */,
+				A976603F2485758600FDD115 /* decompose_initialized_variables_pass.cpp in Sources */,
+				A9765F072485758600FDD115 /* freeze_spec_constant_value_pass.cpp in Sources */,
+				A976603D2485758600FDD115 /* dominator_analysis.cpp in Sources */,
+				A97662492485758700FDD115 /* validate_small_type_uses.cpp in Sources */,
+				A9765FEF2485758600FDD115 /* block_merge_pass.cpp in Sources */,
+				A9765E672485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */,
+				A97660652485758600FDD115 /* graphics_robust_access_pass.cpp in Sources */,
+				A97662732485758700FDD115 /* validation_state.cpp in Sources */,
+				A97660512485758600FDD115 /* struct_cfg_analysis.cpp in Sources */,
+				A9765E432485758500FDD115 /* remove_selection_reduction_opportunity_finder.cpp in Sources */,
+				A9765EFF2485758600FDD115 /* cfg.cpp in Sources */,
+				A9765F7D2485758600FDD115 /* inst_buff_addr_check_pass.cpp in Sources */,
+				A9765E452485758600FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */,
+				A9765E712485758600FDD115 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */,
+				A976621B2485758700FDD115 /* validate_cfg.cpp in Sources */,
+				A9765F992485758600FDD115 /* simplification_pass.cpp in Sources */,
+				A9765E212485758500FDD115 /* table.cpp in Sources */,
+				A9765F292485758600FDD115 /* wrap_opkill.cpp in Sources */,
+				A97662412485758700FDD115 /* function.cpp in Sources */,
+				A9765FB72485758600FDD115 /* process_lines_pass.cpp in Sources */,
+				A97660312485758600FDD115 /* fix_storage_class.cpp in Sources */,
+				A97660372485758600FDD115 /* replace_invalid_opc.cpp in Sources */,
+				A9765F4F2485758600FDD115 /* loop_unswitch_pass.cpp in Sources */,
+				A9765E372485758500FDD115 /* remove_function_reduction_opportunity_finder.cpp in Sources */,
+				A9765FEB2485758600FDD115 /* scalar_analysis.cpp in Sources */,
+				A9765EE32485758600FDD115 /* build_module.cpp in Sources */,
+				A9765F252485758600FDD115 /* eliminate_dead_constant_pass.cpp in Sources */,
+				A9765E772485758600FDD115 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */,
+				A9765ED32485758600FDD115 /* optimizer.cpp in Sources */,
+				A976602D2485758600FDD115 /* reduce_load_size.cpp in Sources */,
+				A9765EC92485758600FDD115 /* software_version.cpp in Sources */,
+				A9765F652485758600FDD115 /* licm_pass.cpp in Sources */,
+				A9765F3F2485758600FDD115 /* mem_pass.cpp in Sources */,
+				A9765F532485758600FDD115 /* type_manager.cpp in Sources */,
+				A9765F112485758600FDD115 /* instrument_pass.cpp in Sources */,
+				A9765F672485758600FDD115 /* eliminate_dead_functions_pass.cpp in Sources */,
+				A976621D2485758700FDD115 /* validate_capability.cpp in Sources */,
+				A976623B2485758700FDD115 /* validate_bitwise.cpp in Sources */,
+				A9765F9B2485758600FDD115 /* dead_branch_elim_pass.cpp in Sources */,
+				A9765E9F2485758600FDD115 /* spirv_fuzzer_options.cpp in Sources */,
+				A976625B2485758700FDD115 /* validate_memory.cpp in Sources */,
+				A97662272485758700FDD115 /* validate_atomics.cpp in Sources */,
+				A9765DF12485758500FDD115 /* spirv_target_env.cpp in Sources */,
+				A97662712485758700FDD115 /* validate_composites.cpp in Sources */,
+				A976622B2485758700FDD115 /* validate_instruction.cpp in Sources */,
+				A97662352485758700FDD115 /* validate.cpp in Sources */,
+				A9765F0D2485758600FDD115 /* inst_bindless_check_pass.cpp in Sources */,
+				A9765ECF2485758600FDD115 /* ext_inst.cpp in Sources */,
+				A97660592485758600FDD115 /* local_access_chain_convert_pass.cpp in Sources */,
+				A9765E252485758500FDD115 /* remove_selection_reduction_opportunity.cpp in Sources */,
+				A97662572485758700FDD115 /* validate_logicals.cpp in Sources */,
+				A97662552485758700FDD115 /* validate_memory_semantics.cpp in Sources */,
+				A9765F312485758600FDD115 /* ssa_rewrite_pass.cpp in Sources */,
+				A976625F2485758700FDD115 /* validate_literals.cpp in Sources */,
+				A976625D2485758700FDD115 /* validate_image.cpp in Sources */,
+				A9765FD72485758600FDD115 /* inline_exhaustive_pass.cpp in Sources */,
+				A9765F272485758600FDD115 /* cfg_cleanup_pass.cpp in Sources */,
+				A9765E112485758500FDD115 /* string_utils.cpp in Sources */,
+				A97660232485758600FDD115 /* relax_float_ops_pass.cpp in Sources */,
+				A9765E732485758600FDD115 /* reduction_opportunity.cpp in Sources */,
+				A97662472485758700FDD115 /* validate_conversion.cpp in Sources */,
+				A9765F052485758600FDD115 /* local_single_block_elim_pass.cpp in Sources */,
+				A9765FB32485758600FDD115 /* composite.cpp in Sources */,
+				A9765F8D2485758600FDD115 /* pch_source_opt.cpp in Sources */,
+				A9765E192485758500FDD115 /* parse_number.cpp in Sources */,
+				A97662632485758700FDD115 /* validate_type.cpp in Sources */,
+				A976624D2485758700FDD115 /* validate_id.cpp in Sources */,
+				A9765E312485758500FDD115 /* reduction_util.cpp in Sources */,
+				A9765F2B2485758600FDD115 /* const_folding_rules.cpp in Sources */,
+				A9765F952485758600FDD115 /* eliminate_dead_functions_util.cpp in Sources */,
+				A9765F452485758600FDD115 /* dead_variable_elimination.cpp in Sources */,
+				A9765E972485758600FDD115 /* spirv_optimizer_options.cpp in Sources */,
+				A9765E6B2485758600FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */,
+				A97662232485758700FDD115 /* validate_non_uniform.cpp in Sources */,
+				A97662692485758700FDD115 /* validate_layout.cpp in Sources */,
+				A976605B2485758600FDD115 /* basic_block.cpp in Sources */,
+				A976626D2485758700FDD115 /* validate_function.cpp in Sources */,
+				A9765DFB2485758500FDD115 /* assembly_grammar.cpp in Sources */,
+				A97662152485758700FDD115 /* text_handler.cpp in Sources */,
+				A9765F512485758600FDD115 /* unify_const_pass.cpp in Sources */,
+				A9765ED92485758600FDD115 /* loop_utils.cpp in Sources */,
+				A97660012485758600FDD115 /* private_to_local_pass.cpp in Sources */,
+				A97662212485758700FDD115 /* validate_barriers.cpp in Sources */,
+				A97662172485758700FDD115 /* validate_annotation.cpp in Sources */,
+				A9765F032485758600FDD115 /* decoration_manager.cpp in Sources */,
+				A9765EA32485758600FDD115 /* spirv_validator_options.cpp in Sources */,
+				A9765F4D2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */,
+				A9765E8F2485758600FDD115 /* remove_block_reduction_opportunity.cpp in Sources */,
+				A9765FC92485758600FDD115 /* eliminate_dead_members_pass.cpp in Sources */,
+				A9765FB12485758600FDD115 /* instruction_list.cpp in Sources */,
+				A9765E4D2485758600FDD115 /* change_operand_reduction_opportunity.cpp in Sources */,
+				A9765F432485758600FDD115 /* remove_duplicates_pass.cpp in Sources */,
+				A9765FCD2485758600FDD115 /* desc_sroa.cpp in Sources */,
+				A9765E8B2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */,
+				A9765F012485758600FDD115 /* strip_atomic_counter_memory_pass.cpp in Sources */,
+				A9765E912485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */,
+				A9765FCF2485758600FDD115 /* block_merge_util.cpp in Sources */,
+				A9765E612485758600FDD115 /* pch_source_reduce.cpp in Sources */,
+				A976607D2485758600FDD115 /* compact_ids_pass.cpp in Sources */,
+				A9765E412485758500FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */,
+				A9765E1B2485758500FDD115 /* bit_vector.cpp in Sources */,
+				A976623D2485758700FDD115 /* validate_extensions.cpp in Sources */,
+				A9765F332485758600FDD115 /* loop_dependence.cpp in Sources */,
+				A97661FF2485758700FDD115 /* diagnostic.cpp in Sources */,
+				A9765FE72485758600FDD115 /* dead_insert_elim_pass.cpp in Sources */,
+				A976600B2485758600FDD115 /* set_spec_constant_default_value_pass.cpp in Sources */,
+				A9765DFF2485758500FDD115 /* extensions.cpp in Sources */,
+				A9765FB52485758600FDD115 /* convert_to_half_pass.cpp in Sources */,
+				A9765E332485758500FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */,
+				A9765FD32485758600FDD115 /* copy_prop_arrays.cpp in Sources */,
+				A9765EBF2485758600FDD115 /* parsed_operand.cpp in Sources */,
+				A9765E632485758600FDD115 /* remove_struct_member_reduction_opportunity.cpp in Sources */,
+				A97662752485758700FDD115 /* validate_primitives.cpp in Sources */,
+				A9765EC52485758600FDD115 /* name_mapper.cpp in Sources */,
+				A9765FCB2485758600FDD115 /* strength_reduction_pass.cpp in Sources */,
+				A9765EAB2485758600FDD115 /* spirv_endian.cpp in Sources */,
+				A97662452485758700FDD115 /* validate_adjacency.cpp in Sources */,
+				A976622F2485758700FDD115 /* validate_debug.cpp in Sources */,
+				A9765F9D2485758600FDD115 /* flatten_decoration_pass.cpp in Sources */,
+				A9765F6B2485758600FDD115 /* split_invalid_unreachable_pass.cpp in Sources */,
+				A976601F2485758600FDD115 /* workaround1209.cpp in Sources */,
+				A976606D2485758600FDD115 /* upgrade_memory_model.cpp in Sources */,
+				A9765F0F2485758600FDD115 /* local_redundancy_elimination.cpp in Sources */,
+				A97660112485758600FDD115 /* amd_ext_to_khr.cpp in Sources */,
+				A9765F172485758600FDD115 /* feature_manager.cpp in Sources */,
+				A9765FA52485758600FDD115 /* ir_context.cpp in Sources */,
+				A9765FD52485758600FDD115 /* pass_manager.cpp in Sources */,
+				A976623F2485758700FDD115 /* construct.cpp in Sources */,
+				A9765E4B2485758600FDD115 /* merge_blocks_reduction_opportunity.cpp in Sources */,
+				A976607F2485758600FDD115 /* loop_peeling.cpp in Sources */,
+				A97660052485758600FDD115 /* propagator.cpp in Sources */,
+				A97662532485758700FDD115 /* validate_mode_setting.cpp in Sources */,
+				A9765F2F2485758600FDD115 /* strip_debug_info_pass.cpp in Sources */,
+				A9765F492485758600FDD115 /* module.cpp in Sources */,
+				A9765FA12485758600FDD115 /* folding_rules.cpp in Sources */,
+				A97660152485758600FDD115 /* scalar_replacement_pass.cpp in Sources */,
+				A9765F732485758600FDD115 /* loop_unroller.cpp in Sources */,
+				A976620B2485758700FDD115 /* operand.cpp in Sources */,
+				A97660352485758600FDD115 /* inline_opaque_pass.cpp in Sources */,
+				A9765EF92485758600FDD115 /* types.cpp in Sources */,
+				A9765EB52485758600FDD115 /* enum_string_mapping.cpp in Sources */,
+				A97660792485758600FDD115 /* legalize_vector_shuffle_pass.cpp in Sources */,
+				A9765EA52485758600FDD115 /* print.cpp in Sources */,
+				A9765F932485758600FDD115 /* aggressive_dead_code_elim_pass.cpp in Sources */,
+				A9765FFD2485758600FDD115 /* local_single_store_elim_pass.cpp in Sources */,
+				A9765F612485758600FDD115 /* ir_loader.cpp in Sources */,
+				A9765E5B2485758600FDD115 /* remove_instruction_reduction_opportunity.cpp in Sources */,
+				A976606B2485758600FDD115 /* loop_fusion.cpp in Sources */,
+				A9765F6F2485758600FDD115 /* vector_dce.cpp in Sources */,
+				A97662612485758700FDD115 /* instruction.cpp in Sources */,
+				A976601B2485758600FDD115 /* redundancy_elimination.cpp in Sources */,
+				A9765FC12485758600FDD115 /* if_conversion.cpp in Sources */,
+				A97660092485758600FDD115 /* loop_dependence_helpers.cpp in Sources */,
+				A9765F5D2485758600FDD115 /* inline_pass.cpp in Sources */,
+				A9765F1D2485758600FDD115 /* dominator_tree.cpp in Sources */,
+				A97662112485758700FDD115 /* disassemble.cpp in Sources */,
+				A9765F392485758600FDD115 /* inst_debug_printf_pass.cpp in Sources */,
+				A9765F872485758600FDD115 /* ccp_pass.cpp in Sources */,
+				A9765ED72485758600FDD115 /* register_pressure.cpp in Sources */,
+				A9765EC72485758600FDD115 /* linker.cpp in Sources */,
+				A9765E2B2485758500FDD115 /* reduction_pass.cpp in Sources */,
+				A9765E8D2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */,
+				A9765E0D2485758500FDD115 /* timer.cpp in Sources */,
+				A97662332485758700FDD115 /* validate_interfaces.cpp in Sources */,
+				A97660332485758600FDD115 /* value_number_table.cpp in Sources */,
+				A9765FAB2485758600FDD115 /* loop_descriptor.cpp in Sources */,
+				A9765EE12485758600FDD115 /* combine_access_chains.cpp in Sources */,
+				A9765E2D2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */,
+				A9765E852485758600FDD115 /* remove_block_reduction_opportunity_finder.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3307,205 +3340,208 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A9415C32243667F800566F16 /* ir_context.cpp in Sources */,
-				A9415BF8243667F800566F16 /* split_invalid_unreachable_pass.cpp in Sources */,
-				A9415C68243667F800566F16 /* loop_fusion_pass.cpp in Sources */,
-				A9415C9C243667F800566F16 /* amd_ext_to_khr.cpp in Sources */,
-				A9415EC8243667F900566F16 /* validate_id.cpp in Sources */,
-				A9415B9E243667F800566F16 /* local_redundancy_elimination.cpp in Sources */,
-				A9415ECE243667F900566F16 /* validate_mode_setting.cpp in Sources */,
-				A9415E92243667F900566F16 /* validate_annotation.cpp in Sources */,
-				A9415B4E243667F800566F16 /* parsed_operand.cpp in Sources */,
-				A9415BB6243667F800566F16 /* cfg_cleanup_pass.cpp in Sources */,
-				A9415C96243667F800566F16 /* set_spec_constant_default_value_pass.cpp in Sources */,
-				A9415C56243667F800566F16 /* strength_reduction_pass.cpp in Sources */,
-				A9415B90243667F800566F16 /* strip_atomic_counter_memory_pass.cpp in Sources */,
-				A9415EA8243667F900566F16 /* validate_decorations.cpp in Sources */,
-				A9415AF8243667F700566F16 /* reducer.cpp in Sources */,
-				A9415C5E243667F800566F16 /* copy_prop_arrays.cpp in Sources */,
-				A9415ED0243667F900566F16 /* validate_memory_semantics.cpp in Sources */,
-				A9415C44243667F800566F16 /* process_lines_pass.cpp in Sources */,
-				A9415C00243667F800566F16 /* loop_unroller.cpp in Sources */,
-				A9415BC2243667F800566F16 /* loop_dependence.cpp in Sources */,
-				A9415AD4243667F700566F16 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */,
-				A9415B96243667F800566F16 /* freeze_spec_constant_value_pass.cpp in Sources */,
-				A9415BA6243667F800566F16 /* feature_manager.cpp in Sources */,
-				A9415BFC243667F800566F16 /* vector_dce.cpp in Sources */,
-				A9415E7E243667F900566F16 /* libspirv.cpp in Sources */,
-				A9415B16243667F700566F16 /* remove_block_reduction_opportunity_finder.cpp in Sources */,
-				A9415D04243667F800566F16 /* legalize_vector_shuffle_pass.cpp in Sources */,
-				A9415EE2243667F900566F16 /* validate_execution_limitations.cpp in Sources */,
-				A9415E7A243667F900566F16 /* diagnostic.cpp in Sources */,
-				A9415BCE243667F800566F16 /* mem_pass.cpp in Sources */,
-				A9415C60243667F800566F16 /* pass_manager.cpp in Sources */,
-				A9415B92243667F800566F16 /* decoration_manager.cpp in Sources */,
-				A9415C8C243667F800566F16 /* private_to_local_pass.cpp in Sources */,
-				A9415C14243667F800566F16 /* ccp_pass.cpp in Sources */,
-				A9415CC0243667F800566F16 /* inline_opaque_pass.cpp in Sources */,
-				A9415BA8243667F800566F16 /* pass.cpp in Sources */,
-				A9415D08243667F800566F16 /* compact_ids_pass.cpp in Sources */,
-				A9415BC0243667F800566F16 /* ssa_rewrite_pass.cpp in Sources */,
-				A9415AF0243667F700566F16 /* remove_instruction_reduction_opportunity.cpp in Sources */,
-				A9415BB0243667F800566F16 /* merge_return_pass.cpp in Sources */,
-				A9415BB8243667F800566F16 /* wrap_opkill.cpp in Sources */,
-				A9415B5E243667F800566F16 /* ext_inst.cpp in Sources */,
-				A9415C26243667F800566F16 /* simplification_pass.cpp in Sources */,
-				A9415B1E243667F700566F16 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */,
-				A9415A90243667F700566F16 /* text.cpp in Sources */,
-				A9415EC0243667F900566F16 /* validate_adjacency.cpp in Sources */,
-				A9415C40243667F800566F16 /* composite.cpp in Sources */,
-				A9415BDA243667F800566F16 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */,
-				A9415B56243667F800566F16 /* linker.cpp in Sources */,
-				A9415B4C243667F800566F16 /* spirv_reducer_options.cpp in Sources */,
-				A9415B68243667F800566F16 /* loop_utils.cpp in Sources */,
-				A9415A98243667F700566F16 /* pch_source.cpp in Sources */,
-				A9415C20243667F800566F16 /* aggressive_dead_code_elim_pass.cpp in Sources */,
-				A9415CB4243667F800566F16 /* instruction.cpp in Sources */,
-				A9415CCA243667F800566F16 /* decompose_initialized_variables_pass.cpp in Sources */,
-				A9415B2E243667F800566F16 /* spirv_fuzzer_options.cpp in Sources */,
-				A9415BB4243667F800566F16 /* eliminate_dead_constant_pass.cpp in Sources */,
-				A9415AD6243667F700566F16 /* remove_function_reduction_opportunity.cpp in Sources */,
-				A9415ADA243667F700566F16 /* remove_selection_reduction_opportunity_finder.cpp in Sources */,
-				A9415C94243667F800566F16 /* loop_dependence_helpers.cpp in Sources */,
-				A9415BD2243667F800566F16 /* remove_duplicates_pass.cpp in Sources */,
-				A9415ADC243667F700566F16 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */,
-				A9415ED8243667F900566F16 /* validate_image.cpp in Sources */,
-				A9415AB8243667F700566F16 /* table.cpp in Sources */,
-				A9415CAE243667F800566F16 /* relax_float_ops_pass.cpp in Sources */,
-				A9415B32243667F800566F16 /* spirv_validator_options.cpp in Sources */,
-				A9415BBE243667F800566F16 /* strip_debug_info_pass.cpp in Sources */,
-				A9415ED2243667F900566F16 /* validate_logicals.cpp in Sources */,
-				A9415B0E243667F700566F16 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */,
-				A9415ACE243667F700566F16 /* remove_function_reduction_opportunity_finder.cpp in Sources */,
-				A9415C42243667F800566F16 /* convert_to_half_pass.cpp in Sources */,
-				A9415EE8243667F900566F16 /* validate_function.cpp in Sources */,
-				A9415B34243667F800566F16 /* print.cpp in Sources */,
-				A9415EC4243667F900566F16 /* validate_small_type_uses.cpp in Sources */,
-				A9415A88243667F700566F16 /* spirv_target_env.cpp in Sources */,
-				A9415ABC243667F700566F16 /* remove_selection_reduction_opportunity.cpp in Sources */,
-				A9415C62243667F800566F16 /* inline_exhaustive_pass.cpp in Sources */,
-				A9415BDC243667F800566F16 /* loop_unswitch_pass.cpp in Sources */,
-				A9415BAC243667F800566F16 /* dominator_tree.cpp in Sources */,
-				A9415AA8243667F700566F16 /* string_utils.cpp in Sources */,
-				A9415EE6243667F900566F16 /* basic_block.cpp in Sources */,
-				A9415BF4243667F800566F16 /* eliminate_dead_functions_pass.cpp in Sources */,
-				A9415CAA243667F800566F16 /* workaround1209.cpp in Sources */,
-				A9415ED6243667F900566F16 /* validate_memory.cpp in Sources */,
-				A9415BEE243667F800566F16 /* ir_loader.cpp in Sources */,
-				A9415AB0243667F700566F16 /* parse_number.cpp in Sources */,
-				A9415AC8243667F700566F16 /* reduction_util.cpp in Sources */,
-				A9415C90243667F800566F16 /* propagator.cpp in Sources */,
-				A9415B04243667F700566F16 /* reduction_opportunity.cpp in Sources */,
-				A9415C2E243667F800566F16 /* folding_rules.cpp in Sources */,
-				A9415C54243667F800566F16 /* eliminate_dead_members_pass.cpp in Sources */,
-				A9415BEA243667F800566F16 /* inline_pass.cpp in Sources */,
-				A9415EAA243667F900566F16 /* validate_debug.cpp in Sources */,
-				A9415BD8243667F800566F16 /* module.cpp in Sources */,
-				A9415BD4243667F800566F16 /* dead_variable_elimination.cpp in Sources */,
-				A9415A92243667F700566F16 /* assembly_grammar.cpp in Sources */,
-				A9415C4E243667F800566F16 /* if_conversion.cpp in Sources */,
-				A9415AE2243667F700566F16 /* change_operand_reduction_opportunity.cpp in Sources */,
-				A9415AD8243667F700566F16 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */,
-				A9415E86243667F900566F16 /* operand.cpp in Sources */,
-				A9415BE2243667F800566F16 /* generate_webgpu_initializers_pass.cpp in Sources */,
-				A9415EB8243667F900566F16 /* validate_extensions.cpp in Sources */,
-				A9415C88243667F800566F16 /* local_single_store_elim_pass.cpp in Sources */,
-				A9415C7A243667F800566F16 /* block_merge_pass.cpp in Sources */,
-				A9415AEA243667F700566F16 /* remove_unreferenced_instruction_reduction_opportunity_finder.cpp in Sources */,
-				A9415C22243667F800566F16 /* eliminate_dead_functions_util.cpp in Sources */,
-				A9415C5A243667F800566F16 /* block_merge_util.cpp in Sources */,
-				A9415CFE243667F800566F16 /* scalar_analysis_simplification.cpp in Sources */,
-				A9415AF6243667F700566F16 /* pch_source_reduce.cpp in Sources */,
-				A9415CB8243667F800566F16 /* reduce_load_size.cpp in Sources */,
-				A9415C0A243667F800566F16 /* inst_buff_addr_check_pass.cpp in Sources */,
-				A9415C9A243667F800566F16 /* fold.cpp in Sources */,
-				A9415EAC243667F900566F16 /* validate_builtins.cpp in Sources */,
-				A9415C3E243667F800566F16 /* instruction_list.cpp in Sources */,
-				A9415AB2243667F700566F16 /* bit_vector.cpp in Sources */,
-				A9415B94243667F800566F16 /* local_single_block_elim_pass.cpp in Sources */,
-				A9415E8C243667F900566F16 /* disassemble.cpp in Sources */,
-				A9415B40243667F800566F16 /* binary.cpp in Sources */,
-				A9415B62243667F800566F16 /* optimizer.cpp in Sources */,
-				A9415BBA243667F800566F16 /* const_folding_rules.cpp in Sources */,
-				A9415AFA243667F700566F16 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */,
-				A9415A96243667F700566F16 /* extensions.cpp in Sources */,
-				A9415C3C243667F800566F16 /* function.cpp in Sources */,
-				A9415CE6243667F800566F16 /* basic_block.cpp in Sources */,
-				A9415E96243667F900566F16 /* validate_cfg.cpp in Sources */,
-				A9415B20243667F700566F16 /* remove_block_reduction_opportunity.cpp in Sources */,
-				A9415C58243667F800566F16 /* desc_sroa.cpp in Sources */,
-				A9415B1C243667F700566F16 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */,
-				A9415C28243667F800566F16 /* dead_branch_elim_pass.cpp in Sources */,
-				A9415CF6243667F800566F16 /* loop_fusion.cpp in Sources */,
-				A9415EBC243667F900566F16 /* function.cpp in Sources */,
-				A9415EBA243667F900566F16 /* construct.cpp in Sources */,
-				A9415B26243667F700566F16 /* spirv_optimizer_options.cpp in Sources */,
-				A9415BF2243667F800566F16 /* licm_pass.cpp in Sources */,
-				A9415EEC243667F900566F16 /* validate_composites.cpp in Sources */,
-				A9415ED4243667F900566F16 /* validate_derivatives.cpp in Sources */,
-				A9415B8E243667F800566F16 /* cfg.cpp in Sources */,
-				A9415CA0243667F800566F16 /* scalar_replacement_pass.cpp in Sources */,
-				A9415EA0243667F900566F16 /* validate_scopes.cpp in Sources */,
-				A9415E94243667F900566F16 /* validate_misc.cpp in Sources */,
-				A9415B58243667F800566F16 /* software_version.cpp in Sources */,
-				A9415E9C243667F900566F16 /* validate_barriers.cpp in Sources */,
-				A9415CF0243667F800566F16 /* graphics_robust_access_pass.cpp in Sources */,
-				A9415B88243667F800566F16 /* types.cpp in Sources */,
-				A9415EB0243667F900566F16 /* validate.cpp in Sources */,
-				A9415BDE243667F800566F16 /* unify_const_pass.cpp in Sources */,
-				A9415EE4243667F900566F16 /* validate_layout.cpp in Sources */,
-				A9415EA6243667F900566F16 /* validate_instruction.cpp in Sources */,
-				A9415EDC243667F900566F16 /* instruction.cpp in Sources */,
-				A9415C1A243667F800566F16 /* pch_source_opt.cpp in Sources */,
-				A9415ACA243667F700566F16 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */,
-				A9415CBE243667F800566F16 /* value_number_table.cpp in Sources */,
-				A9415B9C243667F800566F16 /* inst_bindless_check_pass.cpp in Sources */,
-				A9415EDA243667F900566F16 /* validate_literals.cpp in Sources */,
-				A9415AE0243667F700566F16 /* merge_blocks_reduction_opportunity.cpp in Sources */,
-				A9415B70243667F800566F16 /* combine_access_chains.cpp in Sources */,
-				A9415C10243667F800566F16 /* strip_reflect_info_pass.cpp in Sources */,
-				A9415E9E243667F900566F16 /* validate_non_uniform.cpp in Sources */,
-				A9415B08243667F700566F16 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */,
-				A9415B72243667F800566F16 /* build_module.cpp in Sources */,
-				A9415EEE243667F900566F16 /* validation_state.cpp in Sources */,
-				A9415EDE243667F900566F16 /* validate_type.cpp in Sources */,
-				A9415AC2243667F700566F16 /* reduction_pass.cpp in Sources */,
-				A9415C72243667F800566F16 /* dead_insert_elim_pass.cpp in Sources */,
-				A9415D0A243667F800566F16 /* loop_peeling.cpp in Sources */,
-				A9415CF8243667F800566F16 /* upgrade_memory_model.cpp in Sources */,
-				A9415B5A243667F800566F16 /* opcode.cpp in Sources */,
-				A9415C2A243667F800566F16 /* flatten_decoration_pass.cpp in Sources */,
-				A9415AA4243667F700566F16 /* timer.cpp in Sources */,
-				A9415C76243667F800566F16 /* scalar_analysis.cpp in Sources */,
-				A9415BE0243667F800566F16 /* type_manager.cpp in Sources */,
-				A9415CDC243667F800566F16 /* struct_cfg_analysis.cpp in Sources */,
-				A9415B54243667F800566F16 /* name_mapper.cpp in Sources */,
-				A9415C0C243667F800566F16 /* def_use_manager.cpp in Sources */,
-				A9415BA0243667F800566F16 /* instrument_pass.cpp in Sources */,
-				A9415BAA243667F800566F16 /* loop_fission.cpp in Sources */,
-				A9415B66243667F800566F16 /* register_pressure.cpp in Sources */,
-				A9415C38243667F800566F16 /* loop_descriptor.cpp in Sources */,
-				A9415CC8243667F800566F16 /* dominator_analysis.cpp in Sources */,
-				A9415AC4243667F700566F16 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */,
-				A9415EA2243667F900566F16 /* validate_atomics.cpp in Sources */,
-				A9415BC8243667F800566F16 /* inst_debug_printf_pass.cpp in Sources */,
-				A9415EB6243667F900566F16 /* validate_bitwise.cpp in Sources */,
-				A9415B02243667F700566F16 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */,
-				A9415ECC243667F900566F16 /* validate_arithmetics.cpp in Sources */,
-				A9415E98243667F900566F16 /* validate_capability.cpp in Sources */,
-				A9415EF0243667F900566F16 /* validate_primitives.cpp in Sources */,
-				A9415CE4243667F800566F16 /* local_access_chain_convert_pass.cpp in Sources */,
-				A9415EB4243667F900566F16 /* validate_constants.cpp in Sources */,
-				A9415EAE243667F900566F16 /* validate_interfaces.cpp in Sources */,
-				A9415EC2243667F900566F16 /* validate_conversion.cpp in Sources */,
-				A9415B86243667F800566F16 /* code_sink.cpp in Sources */,
-				A9415CA6243667F800566F16 /* redundancy_elimination.cpp in Sources */,
-				A9415B3A243667F800566F16 /* spirv_endian.cpp in Sources */,
-				A9415C04243667F800566F16 /* constants.cpp in Sources */,
-				A9415CC2243667F800566F16 /* replace_invalid_opc.cpp in Sources */,
-				A9415B44243667F800566F16 /* enum_string_mapping.cpp in Sources */,
-				A9415E90243667F900566F16 /* text_handler.cpp in Sources */,
-				A9415CBC243667F800566F16 /* fix_storage_class.cpp in Sources */,
+				A976626C2485758700FDD115 /* basic_block.cpp in Sources */,
+				A9765EBE2485758600FDD115 /* spirv_reducer_options.cpp in Sources */,
+				A97662262485758700FDD115 /* validate_scopes.cpp in Sources */,
+				A9765F802485758600FDD115 /* def_use_manager.cpp in Sources */,
+				A9765FC42485758600FDD115 /* debug_info_manager.cpp in Sources */,
+				A9765F1C2485758600FDD115 /* loop_fission.cpp in Sources */,
+				A9765FDE2485758600FDD115 /* loop_fusion_pass.cpp in Sources */,
+				A976623A2485758700FDD115 /* validate_constants.cpp in Sources */,
+				A9765F782485758600FDD115 /* constants.cpp in Sources */,
+				A97660102485758600FDD115 /* fold.cpp in Sources */,
+				A9765EB22485758600FDD115 /* binary.cpp in Sources */,
+				A9765FB02485758600FDD115 /* function.cpp in Sources */,
+				A9765E7E2485758600FDD115 /* operand_to_dominating_id_reduction_opportunity_finder.cpp in Sources */,
+				A9765EF82485758600FDD115 /* code_sink.cpp in Sources */,
+				A9765E3E2485758500FDD115 /* simple_conditional_branch_to_branch_reduction_opportunity.cpp in Sources */,
+				A97662322485758700FDD115 /* validate_builtins.cpp in Sources */,
+				A9765F562485758600FDD115 /* generate_webgpu_initializers_pass.cpp in Sources */,
+				A9765DFA2485758500FDD115 /* text.cpp in Sources */,
+				A97660742485758600FDD115 /* scalar_analysis_simplification.cpp in Sources */,
+				A976622E2485758700FDD115 /* validate_decorations.cpp in Sources */,
+				A9765ECC2485758600FDD115 /* opcode.cpp in Sources */,
+				A9765E6A2485758600FDD115 /* reducer.cpp in Sources */,
+				A97662042485758700FDD115 /* libspirv.cpp in Sources */,
+				A9765F1A2485758600FDD115 /* pass.cpp in Sources */,
+				A976621A2485758700FDD115 /* validate_misc.cpp in Sources */,
+				A97662682485758700FDD115 /* validate_execution_limitations.cpp in Sources */,
+				A9765E022485758500FDD115 /* pch_source.cpp in Sources */,
+				A976602A2485758600FDD115 /* instruction.cpp in Sources */,
+				A976625A2485758700FDD115 /* validate_derivatives.cpp in Sources */,
+				A9765F222485758600FDD115 /* merge_return_pass.cpp in Sources */,
+				A9765F842485758600FDD115 /* strip_reflect_info_pass.cpp in Sources */,
+				A9765E402485758500FDD115 /* remove_function_reduction_opportunity.cpp in Sources */,
+				A97662522485758700FDD115 /* validate_arithmetics.cpp in Sources */,
+				A97660402485758600FDD115 /* decompose_initialized_variables_pass.cpp in Sources */,
+				A9765F082485758600FDD115 /* freeze_spec_constant_value_pass.cpp in Sources */,
+				A976603E2485758600FDD115 /* dominator_analysis.cpp in Sources */,
+				A976624A2485758700FDD115 /* validate_small_type_uses.cpp in Sources */,
+				A9765FF02485758600FDD115 /* block_merge_pass.cpp in Sources */,
+				A9765E682485758600FDD115 /* remove_unused_instruction_reduction_opportunity_finder.cpp in Sources */,
+				A97660662485758600FDD115 /* graphics_robust_access_pass.cpp in Sources */,
+				A97662742485758700FDD115 /* validation_state.cpp in Sources */,
+				A97660522485758600FDD115 /* struct_cfg_analysis.cpp in Sources */,
+				A9765E442485758600FDD115 /* remove_selection_reduction_opportunity_finder.cpp in Sources */,
+				A9765F002485758600FDD115 /* cfg.cpp in Sources */,
+				A9765F7E2485758600FDD115 /* inst_buff_addr_check_pass.cpp in Sources */,
+				A9765E462485758600FDD115 /* conditional_branch_to_simple_conditional_branch_reduction_opportunity.cpp in Sources */,
+				A9765E722485758600FDD115 /* merge_blocks_reduction_opportunity_finder.cpp in Sources */,
+				A976621C2485758700FDD115 /* validate_cfg.cpp in Sources */,
+				A9765F9A2485758600FDD115 /* simplification_pass.cpp in Sources */,
+				A9765E222485758500FDD115 /* table.cpp in Sources */,
+				A9765F2A2485758600FDD115 /* wrap_opkill.cpp in Sources */,
+				A97662422485758700FDD115 /* function.cpp in Sources */,
+				A9765FB82485758600FDD115 /* process_lines_pass.cpp in Sources */,
+				A97660322485758600FDD115 /* fix_storage_class.cpp in Sources */,
+				A97660382485758600FDD115 /* replace_invalid_opc.cpp in Sources */,
+				A9765F502485758600FDD115 /* loop_unswitch_pass.cpp in Sources */,
+				A9765E382485758500FDD115 /* remove_function_reduction_opportunity_finder.cpp in Sources */,
+				A9765FEC2485758600FDD115 /* scalar_analysis.cpp in Sources */,
+				A9765EE42485758600FDD115 /* build_module.cpp in Sources */,
+				A9765F262485758600FDD115 /* eliminate_dead_constant_pass.cpp in Sources */,
+				A9765E782485758600FDD115 /* change_operand_to_undef_reduction_opportunity.cpp in Sources */,
+				A9765ED42485758600FDD115 /* optimizer.cpp in Sources */,
+				A976602E2485758600FDD115 /* reduce_load_size.cpp in Sources */,
+				A9765ECA2485758600FDD115 /* software_version.cpp in Sources */,
+				A9765F662485758600FDD115 /* licm_pass.cpp in Sources */,
+				A9765F402485758600FDD115 /* mem_pass.cpp in Sources */,
+				A9765F542485758600FDD115 /* type_manager.cpp in Sources */,
+				A9765F122485758600FDD115 /* instrument_pass.cpp in Sources */,
+				A9765F682485758600FDD115 /* eliminate_dead_functions_pass.cpp in Sources */,
+				A976621E2485758700FDD115 /* validate_capability.cpp in Sources */,
+				A976623C2485758700FDD115 /* validate_bitwise.cpp in Sources */,
+				A9765F9C2485758600FDD115 /* dead_branch_elim_pass.cpp in Sources */,
+				A9765EA02485758600FDD115 /* spirv_fuzzer_options.cpp in Sources */,
+				A976625C2485758700FDD115 /* validate_memory.cpp in Sources */,
+				A97662282485758700FDD115 /* validate_atomics.cpp in Sources */,
+				A9765DF22485758500FDD115 /* spirv_target_env.cpp in Sources */,
+				A97662722485758700FDD115 /* validate_composites.cpp in Sources */,
+				A976622C2485758700FDD115 /* validate_instruction.cpp in Sources */,
+				A97662362485758700FDD115 /* validate.cpp in Sources */,
+				A9765F0E2485758600FDD115 /* inst_bindless_check_pass.cpp in Sources */,
+				A9765ED02485758600FDD115 /* ext_inst.cpp in Sources */,
+				A976605A2485758600FDD115 /* local_access_chain_convert_pass.cpp in Sources */,
+				A9765E262485758500FDD115 /* remove_selection_reduction_opportunity.cpp in Sources */,
+				A97662582485758700FDD115 /* validate_logicals.cpp in Sources */,
+				A97662562485758700FDD115 /* validate_memory_semantics.cpp in Sources */,
+				A9765F322485758600FDD115 /* ssa_rewrite_pass.cpp in Sources */,
+				A97662602485758700FDD115 /* validate_literals.cpp in Sources */,
+				A976625E2485758700FDD115 /* validate_image.cpp in Sources */,
+				A9765FD82485758600FDD115 /* inline_exhaustive_pass.cpp in Sources */,
+				A9765F282485758600FDD115 /* cfg_cleanup_pass.cpp in Sources */,
+				A9765E122485758500FDD115 /* string_utils.cpp in Sources */,
+				A97660242485758600FDD115 /* relax_float_ops_pass.cpp in Sources */,
+				A9765E742485758600FDD115 /* reduction_opportunity.cpp in Sources */,
+				A97662482485758700FDD115 /* validate_conversion.cpp in Sources */,
+				A9765F062485758600FDD115 /* local_single_block_elim_pass.cpp in Sources */,
+				A9765FB42485758600FDD115 /* composite.cpp in Sources */,
+				A9765F8E2485758600FDD115 /* pch_source_opt.cpp in Sources */,
+				A9765E1A2485758500FDD115 /* parse_number.cpp in Sources */,
+				A97662642485758700FDD115 /* validate_type.cpp in Sources */,
+				A976624E2485758700FDD115 /* validate_id.cpp in Sources */,
+				A9765E322485758500FDD115 /* reduction_util.cpp in Sources */,
+				A9765F2C2485758600FDD115 /* const_folding_rules.cpp in Sources */,
+				A9765F962485758600FDD115 /* eliminate_dead_functions_util.cpp in Sources */,
+				A9765F462485758600FDD115 /* dead_variable_elimination.cpp in Sources */,
+				A9765E982485758600FDD115 /* spirv_optimizer_options.cpp in Sources */,
+				A9765E6C2485758600FDD115 /* operand_to_undef_reduction_opportunity_finder.cpp in Sources */,
+				A97662242485758700FDD115 /* validate_non_uniform.cpp in Sources */,
+				A976626A2485758700FDD115 /* validate_layout.cpp in Sources */,
+				A976605C2485758600FDD115 /* basic_block.cpp in Sources */,
+				A976626E2485758700FDD115 /* validate_function.cpp in Sources */,
+				A9765DFC2485758500FDD115 /* assembly_grammar.cpp in Sources */,
+				A97662162485758700FDD115 /* text_handler.cpp in Sources */,
+				A9765F522485758600FDD115 /* unify_const_pass.cpp in Sources */,
+				A9765EDA2485758600FDD115 /* loop_utils.cpp in Sources */,
+				A97660022485758600FDD115 /* private_to_local_pass.cpp in Sources */,
+				A97662222485758700FDD115 /* validate_barriers.cpp in Sources */,
+				A97662182485758700FDD115 /* validate_annotation.cpp in Sources */,
+				A9765F042485758600FDD115 /* decoration_manager.cpp in Sources */,
+				A9765EA42485758600FDD115 /* spirv_validator_options.cpp in Sources */,
+				A9765F4E2485758600FDD115 /* fold_spec_constant_op_and_composite_pass.cpp in Sources */,
+				A9765E902485758600FDD115 /* remove_block_reduction_opportunity.cpp in Sources */,
+				A9765FCA2485758600FDD115 /* eliminate_dead_members_pass.cpp in Sources */,
+				A9765FB22485758600FDD115 /* instruction_list.cpp in Sources */,
+				A9765E4E2485758600FDD115 /* change_operand_reduction_opportunity.cpp in Sources */,
+				A9765F442485758600FDD115 /* remove_duplicates_pass.cpp in Sources */,
+				A9765FCE2485758600FDD115 /* desc_sroa.cpp in Sources */,
+				A9765E8C2485758600FDD115 /* conditional_branch_to_simple_conditional_branch_opportunity_finder.cpp in Sources */,
+				A9765F022485758600FDD115 /* strip_atomic_counter_memory_pass.cpp in Sources */,
+				A9765E922485758600FDD115 /* remove_unused_struct_member_reduction_opportunity_finder.cpp in Sources */,
+				A9765FD02485758600FDD115 /* block_merge_util.cpp in Sources */,
+				A9765E622485758600FDD115 /* pch_source_reduce.cpp in Sources */,
+				A976607E2485758600FDD115 /* compact_ids_pass.cpp in Sources */,
+				A9765E422485758500FDD115 /* simple_conditional_branch_to_branch_opportunity_finder.cpp in Sources */,
+				A9765E1C2485758500FDD115 /* bit_vector.cpp in Sources */,
+				A976623E2485758700FDD115 /* validate_extensions.cpp in Sources */,
+				A9765F342485758600FDD115 /* loop_dependence.cpp in Sources */,
+				A97662002485758700FDD115 /* diagnostic.cpp in Sources */,
+				A9765FE82485758600FDD115 /* dead_insert_elim_pass.cpp in Sources */,
+				A976600C2485758600FDD115 /* set_spec_constant_default_value_pass.cpp in Sources */,
+				A9765E002485758500FDD115 /* extensions.cpp in Sources */,
+				A9765FB62485758600FDD115 /* convert_to_half_pass.cpp in Sources */,
+				A9765E342485758500FDD115 /* structured_loop_to_selection_reduction_opportunity_finder.cpp in Sources */,
+				A9765FD42485758600FDD115 /* copy_prop_arrays.cpp in Sources */,
+				A9765EC02485758600FDD115 /* parsed_operand.cpp in Sources */,
+				A9765E642485758600FDD115 /* remove_struct_member_reduction_opportunity.cpp in Sources */,
+				A97662762485758700FDD115 /* validate_primitives.cpp in Sources */,
+				A9765EC62485758600FDD115 /* name_mapper.cpp in Sources */,
+				A9765FCC2485758600FDD115 /* strength_reduction_pass.cpp in Sources */,
+				A9765EAC2485758600FDD115 /* spirv_endian.cpp in Sources */,
+				A97662462485758700FDD115 /* validate_adjacency.cpp in Sources */,
+				A97662302485758700FDD115 /* validate_debug.cpp in Sources */,
+				A9765F9E2485758600FDD115 /* flatten_decoration_pass.cpp in Sources */,
+				A9765F6C2485758600FDD115 /* split_invalid_unreachable_pass.cpp in Sources */,
+				A97660202485758600FDD115 /* workaround1209.cpp in Sources */,
+				A976606E2485758600FDD115 /* upgrade_memory_model.cpp in Sources */,
+				A9765F102485758600FDD115 /* local_redundancy_elimination.cpp in Sources */,
+				A97660122485758600FDD115 /* amd_ext_to_khr.cpp in Sources */,
+				A9765F182485758600FDD115 /* feature_manager.cpp in Sources */,
+				A9765FA62485758600FDD115 /* ir_context.cpp in Sources */,
+				A9765FD62485758600FDD115 /* pass_manager.cpp in Sources */,
+				A97662402485758700FDD115 /* construct.cpp in Sources */,
+				A9765E4C2485758600FDD115 /* merge_blocks_reduction_opportunity.cpp in Sources */,
+				A97660802485758600FDD115 /* loop_peeling.cpp in Sources */,
+				A97660062485758600FDD115 /* propagator.cpp in Sources */,
+				A97662542485758700FDD115 /* validate_mode_setting.cpp in Sources */,
+				A9765F302485758600FDD115 /* strip_debug_info_pass.cpp in Sources */,
+				A9765F4A2485758600FDD115 /* module.cpp in Sources */,
+				A9765FA22485758600FDD115 /* folding_rules.cpp in Sources */,
+				A97660162485758600FDD115 /* scalar_replacement_pass.cpp in Sources */,
+				A9765F742485758600FDD115 /* loop_unroller.cpp in Sources */,
+				A976620C2485758700FDD115 /* operand.cpp in Sources */,
+				A97660362485758600FDD115 /* inline_opaque_pass.cpp in Sources */,
+				A9765EFA2485758600FDD115 /* types.cpp in Sources */,
+				A9765EB62485758600FDD115 /* enum_string_mapping.cpp in Sources */,
+				A976607A2485758600FDD115 /* legalize_vector_shuffle_pass.cpp in Sources */,
+				A9765EA62485758600FDD115 /* print.cpp in Sources */,
+				A9765F942485758600FDD115 /* aggressive_dead_code_elim_pass.cpp in Sources */,
+				A9765FFE2485758600FDD115 /* local_single_store_elim_pass.cpp in Sources */,
+				A9765F622485758600FDD115 /* ir_loader.cpp in Sources */,
+				A9765E5C2485758600FDD115 /* remove_instruction_reduction_opportunity.cpp in Sources */,
+				A976606C2485758600FDD115 /* loop_fusion.cpp in Sources */,
+				A9765F702485758600FDD115 /* vector_dce.cpp in Sources */,
+				A97662622485758700FDD115 /* instruction.cpp in Sources */,
+				A976601C2485758600FDD115 /* redundancy_elimination.cpp in Sources */,
+				A9765FC22485758600FDD115 /* if_conversion.cpp in Sources */,
+				A976600A2485758600FDD115 /* loop_dependence_helpers.cpp in Sources */,
+				A9765F5E2485758600FDD115 /* inline_pass.cpp in Sources */,
+				A9765F1E2485758600FDD115 /* dominator_tree.cpp in Sources */,
+				A97662122485758700FDD115 /* disassemble.cpp in Sources */,
+				A9765F3A2485758600FDD115 /* inst_debug_printf_pass.cpp in Sources */,
+				A9765F882485758600FDD115 /* ccp_pass.cpp in Sources */,
+				A9765ED82485758600FDD115 /* register_pressure.cpp in Sources */,
+				A9765EC82485758600FDD115 /* linker.cpp in Sources */,
+				A9765E2C2485758500FDD115 /* reduction_pass.cpp in Sources */,
+				A9765E8E2485758600FDD115 /* structured_loop_to_selection_reduction_opportunity.cpp in Sources */,
+				A9765E0E2485758500FDD115 /* timer.cpp in Sources */,
+				A97662342485758700FDD115 /* validate_interfaces.cpp in Sources */,
+				A97660342485758600FDD115 /* value_number_table.cpp in Sources */,
+				A9765FAC2485758600FDD115 /* loop_descriptor.cpp in Sources */,
+				A9765EE22485758600FDD115 /* combine_access_chains.cpp in Sources */,
+				A9765E2E2485758500FDD115 /* operand_to_const_reduction_opportunity_finder.cpp in Sources */,
+				A9765E862485758600FDD115 /* remove_block_reduction_opportunity_finder.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -3684,34 +3720,24 @@
 		A90FD89D21CC4EAB00B92BB2 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
 				);
 				PRODUCT_NAME = SPIRVCross;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A90FD89E21CC4EAB00B92BB2 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
 				);
 				PRODUCT_NAME = SPIRVCross;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -3790,10 +3816,6 @@
 		A972A80D21CECBBF0013AB25 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				DEPLOYMENT_POSTPROCESSING = YES;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				HEADER_SEARCH_PATHS = (
@@ -3805,17 +3827,12 @@
 				);
 				PRODUCT_NAME = SPIRVTools;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A972A80E21CECBBF0013AB25 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				DEPLOYMENT_POSTPROCESSING = YES;
 				GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
 				HEADER_SEARCH_PATHS = (
@@ -3827,7 +3844,6 @@
 				);
 				PRODUCT_NAME = SPIRVTools;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -3868,11 +3884,7 @@
 		A972ABDA21CED7BC0013AB25 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"AMD_EXTENSIONS=1",
@@ -3888,18 +3900,13 @@
 				);
 				PRODUCT_NAME = glslang;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A972ABDB21CED7BC0013AB25 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
-				CODE_SIGN_IDENTITY = "iPhone Developer";
-				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"AMD_EXTENSIONS=1",
@@ -3915,7 +3922,6 @@
 				);
 				PRODUCT_NAME = glslang;
 				SDKROOT = iphoneos;
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -3967,6 +3973,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
@@ -4014,6 +4021,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
diff --git "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme" "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
index 18a6d08..9677c5a 100644
--- "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
+++ "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
index fab5380..f5912bb 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
index 2313055..72e1129 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
index 2ebf29f..7d3952c 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
index 944ddf4..50db954 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
index 9f89d19..a4ceebf 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
index 03437e5..915c7e2 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
index cbfbdd3..2f53c1a 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
index dc8c0d1..62d3081 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
index 4a85559..4b203b9 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ExternalRevisions/README.md b/ExternalRevisions/README.md
index 6eb1886..b14fd7b 100644
--- a/ExternalRevisions/README.md
+++ b/ExternalRevisions/README.md
@@ -202,9 +202,10 @@
 
 5. Remove the *Group* named `fuzz` from under the *Group* named `External/SPIRV-Tools/source`.
 
-6. In the `Scripts` folder, run `./packagePregenSpirvToolsHeaders` to update `Templates/spirv-tools/build.zip` 
-   from the `*.h` and `*.inc` files in `External/glslang/External/spirv-tools/build`, and test by running 
-   `./fetchDependencies --skip-spirv-tools-build`, and a **MoltenVK** build.
+6. In the `Scripts` folder, run `./packagePregenSpirvToolsHeaders`, which will fetch and build the 
+   full `SPIRV-Tools` library and will update `Templates/spirv-tools/build.zip` from the `*.h` and 
+   `*.inc` files in `External/glslang/External/spirv-tools/build`. Test by running `./fetchDependencies` 
+   and a **MoltenVK** build.
 
 
 
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index e20a35a..9fa21a3 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-fbc560782c42bab4581dbc7705da5013bf864956
+d385bf096f5dabbc4cdaeb6872b0f64be1a63ad0
diff --git a/ExternalRevisions/Vulkan-Headers_repo_revision b/ExternalRevisions/Vulkan-Headers_repo_revision
index 9c7eac2..20b16f5 100644
--- a/ExternalRevisions/Vulkan-Headers_repo_revision
+++ b/ExternalRevisions/Vulkan-Headers_repo_revision
@@ -1 +1 @@
-fb7f9c9bcd1d1544ea203a1f3d4253d0e90c5a90
+09531f27933bf04bffde9074acb302e026e8f181
diff --git a/ExternalRevisions/Vulkan-Tools_repo_revision b/ExternalRevisions/Vulkan-Tools_repo_revision
index 133c330..625057d 100644
--- a/ExternalRevisions/Vulkan-Tools_repo_revision
+++ b/ExternalRevisions/Vulkan-Tools_repo_revision
@@ -1 +1 @@
-7844b9b4e180612c7ca35bcb07ce7f86610b22c4
+e5b2ff8935cbe779fbbaa02d3aa7659167eb7e35
diff --git a/ExternalRevisions/VulkanSamples_repo_revision b/ExternalRevisions/VulkanSamples_repo_revision
index a359707..d5f3abe 100644
--- a/ExternalRevisions/VulkanSamples_repo_revision
+++ b/ExternalRevisions/VulkanSamples_repo_revision
@@ -1 +1 @@
-036541ca8f65333bf911b3957afa2c49f83fa0cd
+f938eb1daf5c2c9f895c70563760c35e074acc03
diff --git a/ExternalRevisions/glslang_repo_revision b/ExternalRevisions/glslang_repo_revision
index f6d25e5..6fd2550 100644
--- a/ExternalRevisions/glslang_repo_revision
+++ b/ExternalRevisions/glslang_repo_revision
@@ -1 +1 @@
-e157435c1e777aa1052f446dafed162b4a722e03
+e00d27c6d65b7d3e72506a311d7f053da4051295
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index ea3ae46..0ade7b8 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -233,6 +233,10 @@
 		A9F042A51FB4CF83009FCCB8 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */; };
 		A9F042A61FB4CF83009FCCB8 /* MVKLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */; };
 		A9F042A71FB4CF83009FCCB8 /* MVKLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */; };
+		A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; };
+		A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; };
+		A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; };
+		A9F3D9DF24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -423,6 +427,9 @@
 		A9E53DFE21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPipelineDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
 		A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommonEnvironment.h; sourceTree = "<group>"; };
 		A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLogging.h; sourceTree = "<group>"; };
+		A9F2559121F96814008C7785 /* vulkan-portability */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vulkan-portability"; sourceTree = "<group>"; };
+		A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVectorAllocator.h; sourceTree = "<group>"; };
+		A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVector.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXGroup section */
@@ -569,6 +576,8 @@
 				A98149451FB6A3F7005F00B4 /* MVKFoundation.cpp */,
 				A98149441FB6A3F7005F00B4 /* MVKFoundation.h */,
 				A98149461FB6A3F7005F00B4 /* MVKObjectPool.h */,
+				A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */,
+				A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */,
 				83A4AD2521BD75570006C935 /* MVKVector.h */,
 				83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */,
 				A98149491FB6A3F7005F00B4 /* MVKWatermark.h */,
@@ -686,6 +695,7 @@
 				A9E53DE32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
 				A94FB8181C7DFB4800632CA3 /* MVKSync.h in Headers */,
 				A94FB7E41C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+				A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */,
 				83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */,
 				A94FB7D41C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
 				A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
@@ -703,6 +713,7 @@
 				A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */,
 				A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */,
 				A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
+				A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
 				A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
 				A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */,
 				4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
@@ -756,6 +767,7 @@
 				A9E53DE42100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
 				A94FB8191C7DFB4800632CA3 /* MVKSync.h in Headers */,
 				A94FB7E51C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+				A9F3D9DF24732A4D00745190 /* MVKSmallVector.h in Headers */,
 				83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */,
 				A94FB7D51C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
 				A94FB80D1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
@@ -773,6 +785,7 @@
 				A9B51BDA225E986A00AC74D2 /* MVKOSExtensions.h in Headers */,
 				A94FB7C51C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */,
 				A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
+				A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
 				A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
 				A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */,
 				4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
@@ -846,7 +859,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A9B8EE091A98D796009C5A02 = {
@@ -1132,24 +1145,18 @@
 		A9B8EE1E1A98D796009C5A02 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A9B8EE1F1A98D796009C5A02 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				IPHONEOS_DEPLOYMENT_TARGET = 9.0;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -1158,7 +1165,6 @@
 			buildSettings = {
 				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				SDKROOT = macosx;
-				VALID_ARCHS = x86_64;
 			};
 			name = Debug;
 		};
@@ -1167,7 +1173,6 @@
 			buildSettings = {
 				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				SDKROOT = macosx;
-				VALID_ARCHS = x86_64;
 			};
 			name = Release;
 		};
@@ -1175,6 +1180,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
@@ -1235,6 +1241,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
index fcfb674..5be3d34 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
index 6e4b83f..7c9db07 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index effbd3d..71e165e 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -50,12 +50,12 @@
  */
 #define MVK_VERSION_MAJOR   1
 #define MVK_VERSION_MINOR   0
-#define MVK_VERSION_PATCH   42
+#define MVK_VERSION_PATCH   44
 
 #define MVK_MAKE_VERSION(major, minor, patch)    (((major) * 10000) + ((minor) * 100) + (patch))
 #define MVK_VERSION     MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
 
-#define VK_MVK_MOLTENVK_SPEC_VERSION            25
+#define VK_MVK_MOLTENVK_SPEC_VERSION            26
 #define VK_MVK_MOLTENVK_EXTENSION_NAME          "VK_MVK_moltenvk"
 
 /**
@@ -609,7 +609,8 @@
 	VkBool32 native3DCompressedTextures;		/**< If true, 3D compressed images are supported natively, without manual decompression. */
 	VkBool32 nativeTextureSwizzle;				/**< If true, component swizzle is supported natively, without manual swizzling in shaders. */
 	VkBool32 placementHeaps;					/**< If true, MTLHeap objects support placement of resources. */
-	VkDeviceSize pushConstantSizeAlignment;     /**< The alignment used internally when allocating memory for push constants. Must be PoT. */
+	VkDeviceSize pushConstantSizeAlignment;		/**< The alignment used internally when allocating memory for push constants. Must be PoT. */
+	uint32_t maxTextureLayers;					/**< The maximum number of layers in an array texture. */
 } MVKPhysicalDeviceMetalFeatures;
 
 /** MoltenVK performance of a particular type of activity. */
@@ -643,7 +644,7 @@
 
 /** MoltenVK performance of queue activities. */
 typedef struct {
-	MVKPerformanceTracker mtlQueueAccess;               /** Create an MTLCommmandQueue or access an existing cached instance. */
+	MVKPerformanceTracker mtlQueueAccess;               /** Create an MTLCommandQueue or access an existing cached instance. */
 	MVKPerformanceTracker mtlCommandBufferCompletion;   /** Completion of a MTLCommandBuffer on the GPU, from commit to completion callback. */
 	MVKPerformanceTracker nextCAMetalDrawable;			/** Retrieve next CAMetalDrawable from CAMetalLayer during presentation. */
 	MVKPerformanceTracker frameInterval;				/** Frame presentation interval (1000/FPS). */
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.h b/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.h
index 336355d..4fef8b0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDispatch.h
@@ -19,7 +19,6 @@
 #pragma once
 
 #include "MVKCommand.h"
-#include "MVKMTLResourceBindings.h"
 
 #import <Metal/Metal.h>
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
index 8d453fe..1d67b39 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
@@ -20,7 +20,7 @@
 
 #include "MVKCommand.h"
 #include "MVKMTLResourceBindings.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 #import <Metal/Metal.h>
 
@@ -28,7 +28,11 @@
 #pragma mark -
 #pragma mark MVKCmdBindVertexBuffers
 
-/** Vulkan command to bind buffers containing vertex content. */
+/**
+ * Vulkan command to bind buffers containing vertex content.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdBindVertexBuffers : public MVKCommand {
 
 public:
@@ -43,9 +47,14 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-    MVKVectorInline<MVKMTLBufferBinding, 8> _bindings;
+    MVKSmallVector<MVKMTLBufferBinding, N> _bindings;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdBindVertexBuffers<1> MVKCmdBindVertexBuffers1;
+typedef MVKCmdBindVertexBuffers<2> MVKCmdBindVertexBuffers2;
+typedef MVKCmdBindVertexBuffers<8> MVKCmdBindVertexBuffersMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdBindIndexBuffer
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
index e8fbe51..14abfc7 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -28,11 +28,12 @@
 #pragma mark -
 #pragma mark MVKCmdBindVertexBuffers
 
-VkResult MVKCmdBindVertexBuffers::setContent(MVKCommandBuffer* cmdBuff,
-											 uint32_t startBinding,
-											 uint32_t bindingCount,
-											 const VkBuffer* pBuffers,
-											 const VkDeviceSize* pOffsets) {
+template <size_t N>
+VkResult MVKCmdBindVertexBuffers<N>::setContent(MVKCommandBuffer* cmdBuff,
+												uint32_t startBinding,
+												uint32_t bindingCount,
+												const VkBuffer* pBuffers,
+												const VkDeviceSize* pOffsets) {
 
 	MVKDevice* mvkDvc = cmdBuff->getDevice();
 	_bindings.clear();	// Clear for reuse
@@ -49,10 +50,15 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdBindVertexBuffers::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdBindVertexBuffers<N>::encode(MVKCommandEncoder* cmdEncoder) {
     for (auto& b : _bindings) { cmdEncoder->_graphicsResourcesState.bindBuffer(kMVKShaderStageVertex, b); }
 }
 
+template class MVKCmdBindVertexBuffers<1>;
+template class MVKCmdBindVertexBuffers<2>;
+template class MVKCmdBindVertexBuffers<8>;
+
 
 #pragma mark -
 #pragma mark MVKCmdBindIndexBuffer
@@ -102,7 +108,7 @@
 
     auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
 
-    MVKVectorInline<uint32_t, 4> stages;
+	MVKPiplineStages stages;
     pipeline->getStages(stages);
 
     const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
@@ -296,11 +302,11 @@
 
     auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
 
-    MVKVectorInline<uint32_t, 4> stages;
+	MVKPiplineStages stages;
     pipeline->getStages(stages);
 
     MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
-    size_t idxSize = mvkMTLIndexTypeSizeInBytes(ibb.mtlIndexType);
+    size_t idxSize = mvkMTLIndexTypeSizeInBytes((MTLIndexType)ibb.mtlIndexType);
     VkDeviceSize idxBuffOffset = ibb.offset + (_firstIndex * idxSize);
 
     const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
@@ -327,7 +333,7 @@
             // Yeah, this sucks. But there aren't many good ways for dealing with this issue.
             mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationControl);
             tcIndexBuff = cmdEncoder->getTempMTLBuffer(_instanceCount * patchCount * outControlPointCount * idxSize);
-            id<MTLComputePipelineState> mtlCopyIndexState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(ibb.mtlIndexType);
+            id<MTLComputePipelineState> mtlCopyIndexState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState((MTLIndexType)ibb.mtlIndexType);
             [mtlTessCtlEncoder setComputePipelineState: mtlCopyIndexState];
             [mtlTessCtlEncoder setBuffer: ibb.mtlBuffer
                                   offset: ibb.offset
@@ -376,7 +382,7 @@
                 if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
                     [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: MTLPrimitiveTypePoint
                                                               indexCount: _indexCount
-                                                               indexType: ibb.mtlIndexType
+                                                               indexType: (MTLIndexType)ibb.mtlIndexType
                                                              indexBuffer: ibb.mtlBuffer
                                                        indexBufferOffset: idxBuffOffset
                                                            instanceCount: _instanceCount
@@ -385,7 +391,7 @@
                 } else {
                     [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: MTLPrimitiveTypePoint
                                                               indexCount: _indexCount
-                                                               indexType: ibb.mtlIndexType
+                                                               indexType: (MTLIndexType)ibb.mtlIndexType
                                                              indexBuffer: ibb.mtlBuffer
                                                        indexBufferOffset: idxBuffOffset
                                                            instanceCount: _instanceCount];
@@ -476,7 +482,7 @@
                     if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
                         [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
                                                                   indexCount: _indexCount
-                                                                   indexType: ibb.mtlIndexType
+                                                                   indexType: (MTLIndexType)ibb.mtlIndexType
                                                                  indexBuffer: ibb.mtlBuffer
                                                            indexBufferOffset: idxBuffOffset
                                                                instanceCount: _instanceCount
@@ -485,7 +491,7 @@
                     } else {
                         [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
                                                                   indexCount: _indexCount
-                                                                   indexType: ibb.mtlIndexType
+                                                                   indexType: (MTLIndexType)ibb.mtlIndexType
                                                                  indexBuffer: ibb.mtlBuffer
                                                            indexBufferOffset: idxBuffOffset
                                                                instanceCount: _instanceCount];
@@ -582,7 +588,7 @@
         }
     }
 
-    MVKVectorInline<uint32_t, 4> stages;
+	MVKPiplineStages stages;
     pipeline->getStages(stages);
 
     VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
@@ -769,7 +775,7 @@
 void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
 
     MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
-    size_t idxSize = mvkMTLIndexTypeSizeInBytes(ibb.mtlIndexType);
+    size_t idxSize = mvkMTLIndexTypeSizeInBytes((MTLIndexType)ibb.mtlIndexType);
     auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
     // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats.
     // We have to convert from the drawIndexedPrimitives:... format to them.
@@ -810,7 +816,7 @@
         tcIndexBuff = cmdEncoder->getTempMTLBuffer(patchCount * outControlPointCount * idxSize);
     }
 
-    MVKVectorInline<uint32_t, 4> stages;
+	MVKPiplineStages stages;
     pipeline->getStages(stages);
 
     VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
@@ -857,7 +863,7 @@
                 // or not there are gaps in it, because there's no way to tell Metal to
                 // offset an index buffer from a value in an indirect buffer. This also
                 // means that, to make a copy, we have to use a compute shader.
-                id<MTLComputePipelineState> mtlCopyIndexState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(ibb.mtlIndexType);
+                id<MTLComputePipelineState> mtlCopyIndexState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState((MTLIndexType)ibb.mtlIndexType);
                 [mtlTessCtlEncoder setComputePipelineState: mtlCopyIndexState];
                 [mtlTessCtlEncoder setBuffer: ibb.mtlBuffer
                                       offset: ibb.offset
@@ -896,7 +902,7 @@
                                                               atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
                     }
                     [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: MTLPrimitiveTypePoint
-                                                               indexType: ibb.mtlIndexType
+                                                               indexType: (MTLIndexType)ibb.mtlIndexType
                                                              indexBuffer: ibb.mtlBuffer
                                                        indexBufferOffset: ibb.offset
                                                           indirectBuffer: _mtlIndirectBuffer
@@ -985,7 +991,7 @@
                         cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
                     } else {
                         [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
-                                                                   indexType: ibb.mtlIndexType
+                                                                   indexType: (MTLIndexType)ibb.mtlIndexType
                                                                  indexBuffer: ibb.mtlBuffer
                                                            indexBufferOffset: ibb.offset
                                                               indirectBuffer: _mtlIndirectBuffer
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
index 22471b7..b2985ee 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
@@ -19,8 +19,9 @@
 #pragma once
 
 #include "MVKCommand.h"
+#include "MVKMTLResourceBindings.h"
 #include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 class MVKCommandBuffer;
 class MVKPipeline;
@@ -32,7 +33,11 @@
 #pragma mark -
 #pragma mark MVKCmdPipelineBarrier
 
-/** Represents an abstract Vulkan command to add a pipeline barrier. */
+/**
+ * Vulkan command to add a pipeline barrier.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdPipelineBarrier : public MVKCommand {
 
 public:
@@ -51,45 +56,113 @@
 
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	bool coversTextures();
 
+	MVKSmallVector<MVKPipelineBarrier, N> _barriers;
 	VkPipelineStageFlags _srcStageMask;
 	VkPipelineStageFlags _dstStageMask;
 	VkDependencyFlags _dependencyFlags;
-	MVKVectorInline<VkMemoryBarrier, 4> _memoryBarriers;
-	MVKVectorInline<VkBufferMemoryBarrier, 4> _bufferMemoryBarriers;
-	MVKVectorInline<VkImageMemoryBarrier, 4> _imageMemoryBarriers;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdPipelineBarrier<1> MVKCmdPipelineBarrier1;
+typedef MVKCmdPipelineBarrier<4> MVKCmdPipelineBarrier4;
+typedef MVKCmdPipelineBarrier<32> MVKCmdPipelineBarrierMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdBindPipeline
 
-/** Vulkan command to bind the pipeline state. */
+/** Abstract Vulkan command to bind a pipeline. */
 class MVKCmdBindPipeline : public MVKCommand {
 
 public:
-	VkResult setContent(MVKCommandBuffer* cmdBuff,
-						VkPipelineBindPoint pipelineBindPoint,
-						VkPipeline pipeline);
+	VkResult setContent(MVKCommandBuffer* cmdBuff, VkPipeline pipeline);
 
-	void encode(MVKCommandEncoder* cmdEncoder) override;
-
-	bool isTessellationPipeline();
+	virtual bool isTessellationPipeline() { return false; };
 
 protected:
-	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
-
-	VkPipelineBindPoint _bindPoint;
 	MVKPipeline* _pipeline;
 
 };
 
 
 #pragma mark -
-#pragma mark MVKCmdBindDescriptorSets
+#pragma mark MVKCmdBindGraphicsPipeline
 
-/** Vulkan command to bind descriptor sets. */
-class MVKCmdBindDescriptorSets : public MVKCommand {
+/** Vulkan command to bind a graphics pipeline. */
+class MVKCmdBindGraphicsPipeline : public MVKCmdBindPipeline {
+
+public:
+	void encode(MVKCommandEncoder* cmdEncoder) override;
+
+	bool isTessellationPipeline() override;
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+
+};
+
+
+#pragma mark -
+#pragma mark MVKCmdBindComputePipeline
+
+/** Vulkan command to bind a compute pipeline. */
+class MVKCmdBindComputePipeline : public MVKCmdBindPipeline {
+
+public:
+	void encode(MVKCommandEncoder* cmdEncoder) override;
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+
+};
+
+
+#pragma mark -
+#pragma mark MVKCmdBindDescriptorSetsStatic
+
+/**
+ * Vulkan command to bind descriptor sets without dynamic offsets.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdBindDescriptorSetsStatic : public MVKCommand {
+
+public:
+	VkResult setContent(MVKCommandBuffer* cmdBuff,
+						VkPipelineBindPoint pipelineBindPoint,
+						VkPipelineLayout layout,
+						uint32_t firstSet,
+						uint32_t setCount,
+						const VkDescriptorSet* pDescriptorSets);
+
+	void encode(MVKCommandEncoder* cmdEncoder) override;
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+
+	MVKSmallVector<MVKDescriptorSet*, N> _descriptorSets;
+	MVKPipelineLayout* _pipelineLayout;
+	VkPipelineBindPoint _pipelineBindPoint;
+	uint32_t _firstSet;
+};
+
+// Concrete template class implementations.
+typedef MVKCmdBindDescriptorSetsStatic<1> MVKCmdBindDescriptorSetsStatic1;
+typedef MVKCmdBindDescriptorSetsStatic<4> MVKCmdBindDescriptorSetsStatic4;
+typedef MVKCmdBindDescriptorSetsStatic<8> MVKCmdBindDescriptorSetsStaticMulti;
+
+
+#pragma mark -
+#pragma mark MVKCmdBindDescriptorSetsDynamic
+
+/**
+ * Vulkan command to bind descriptor sets with dynamic offsets.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdBindDescriptorSetsDynamic : public MVKCmdBindDescriptorSetsStatic<N> {
 
 public:
 	VkResult setContent(MVKCommandBuffer* cmdBuff,
@@ -106,18 +179,22 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-	VkPipelineBindPoint _pipelineBindPoint;
-	MVKPipelineLayout* _pipelineLayout;
-	MVKVectorInline<MVKDescriptorSet*, 8> _descriptorSets;
-	MVKVectorInline<uint32_t, 8>          _dynamicOffsets;
-	uint32_t _firstSet;
+	MVKSmallVector<uint32_t, N> _dynamicOffsets;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdBindDescriptorSetsDynamic<4> MVKCmdBindDescriptorSetsDynamic4;
+typedef MVKCmdBindDescriptorSetsDynamic<8> MVKCmdBindDescriptorSetsDynamicMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdPushConstants
 
-/** Vulkan command to bind push constants. */
+/**
+ * Vulkan command to bind push constants.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdPushConstants : public MVKCommand {
 
 public:
@@ -133,12 +210,17 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
+	MVKSmallVector<char, N> _pushConstants;
 	MVKPipelineLayout* _pipelineLayout;
 	VkShaderStageFlags _stageFlags;
 	uint32_t _offset;
-	MVKVectorInline<char, 128> _pushConstants;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdPushConstants<64> MVKCmdPushConstants64;
+typedef MVKCmdPushConstants<128> MVKCmdPushConstants128;
+typedef MVKCmdPushConstants<512> MVKCmdPushConstantsMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdPushDescriptorSet
@@ -162,9 +244,9 @@
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 	void clearDescriptorWrites();
 
-	VkPipelineBindPoint _pipelineBindPoint;
+	MVKSmallVector<VkWriteDescriptorSet, 1> _descriptorWrites;
 	MVKPipelineLayout* _pipelineLayout;
-	MVKVectorInline<VkWriteDescriptorSet, 8> _descriptorWrites;
+	VkPipelineBindPoint _pipelineBindPoint;
 	uint32_t _set;
 };
 
@@ -191,30 +273,54 @@
 
 	MVKDescriptorUpdateTemplate* _descUpdateTemplate;
 	MVKPipelineLayout* _pipelineLayout;
-	uint32_t _set;
 	void* _pData = nullptr;
+	uint32_t _set;
 };
 
 
 #pragma mark -
 #pragma mark MVKCmdSetResetEvent
 
-/** Vulkan command to set or reset an event. */
+/** Abstract Vulkan command to set or reset an event. */
 class MVKCmdSetResetEvent : public MVKCommand {
 
 public:
 	VkResult setContent(MVKCommandBuffer* cmdBuff,
 						VkEvent event,
-						VkPipelineStageFlags stageMask,
-						bool status);
+						VkPipelineStageFlags stageMask);
 
+protected:
+	MVKEvent* _mvkEvent;
+
+};
+
+
+#pragma mark -
+#pragma mark MVKCmdSetEvent
+
+/** Vulkan command to set an event. */
+class MVKCmdSetEvent : public MVKCmdSetResetEvent {
+
+public:
 	void encode(MVKCommandEncoder* cmdEncoder) override;
 
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-	MVKEvent* _mvkEvent;
-	bool _status;
+};
+
+
+#pragma mark -
+#pragma mark MVKCmdResetEvent
+
+/** Vulkan command to reset an event. */
+class MVKCmdResetEvent : public MVKCmdSetResetEvent {
+
+public:
+	void encode(MVKCommandEncoder* cmdEncoder) override;
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
 };
 
@@ -223,6 +329,11 @@
 #pragma mark MVKCmdWaitEvents
 
 /** Vulkan command to wait for an event to be signaled. */
+/**
+ * Vulkan command to wait for an event to be signaled.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdWaitEvents : public MVKCommand {
 
 public:
@@ -243,6 +354,10 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-	MVKVectorInline<MVKEvent*, 4> _mvkEvents;
+	MVKSmallVector<MVKEvent*, N> _mvkEvents;
 
 };
+
+// Concrete template class implementations.
+typedef MVKCmdWaitEvents<1> MVKCmdWaitEvents1;
+typedef MVKCmdWaitEvents<8> MVKCmdWaitEventsMulti;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index 01b8daf..4e12de5 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -30,108 +30,131 @@
 #pragma mark -
 #pragma mark MVKCmdPipelineBarrier
 
-VkResult MVKCmdPipelineBarrier::setContent(MVKCommandBuffer* cmdBuff,
-										   VkPipelineStageFlags srcStageMask,
-										   VkPipelineStageFlags dstStageMask,
-										   VkDependencyFlags dependencyFlags,
-										   uint32_t memoryBarrierCount,
-										   const VkMemoryBarrier* pMemoryBarriers,
-										   uint32_t bufferMemoryBarrierCount,
-										   const VkBufferMemoryBarrier* pBufferMemoryBarriers,
-										   uint32_t imageMemoryBarrierCount,
-										   const VkImageMemoryBarrier* pImageMemoryBarriers) {
+template <size_t N>
+VkResult MVKCmdPipelineBarrier<N>::setContent(MVKCommandBuffer* cmdBuff,
+											  VkPipelineStageFlags srcStageMask,
+											  VkPipelineStageFlags dstStageMask,
+											  VkDependencyFlags dependencyFlags,
+											  uint32_t memoryBarrierCount,
+											  const VkMemoryBarrier* pMemoryBarriers,
+											  uint32_t bufferMemoryBarrierCount,
+											  const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+											  uint32_t imageMemoryBarrierCount,
+											  const VkImageMemoryBarrier* pImageMemoryBarriers) {
 	_srcStageMask = srcStageMask;
 	_dstStageMask = dstStageMask;
 	_dependencyFlags = dependencyFlags;
 
-	_memoryBarriers.clear();	// Clear for reuse
-	_memoryBarriers.reserve(memoryBarrierCount);
+	_barriers.clear();	// Clear for reuse
+	_barriers.reserve(memoryBarrierCount + bufferMemoryBarrierCount + imageMemoryBarrierCount);
+
 	for (uint32_t i = 0; i < memoryBarrierCount; i++) {
-		_memoryBarriers.push_back(pMemoryBarriers[i]);
+		_barriers.emplace_back(pMemoryBarriers[i]);
 	}
-
-	_bufferMemoryBarriers.clear();	// Clear for reuse
-	_bufferMemoryBarriers.reserve(bufferMemoryBarrierCount);
 	for (uint32_t i = 0; i < bufferMemoryBarrierCount; i++) {
-		_bufferMemoryBarriers.push_back(pBufferMemoryBarriers[i]);
+		_barriers.emplace_back(pBufferMemoryBarriers[i]);
 	}
-
-	_imageMemoryBarriers.clear();	// Clear for reuse
-	_imageMemoryBarriers.reserve(imageMemoryBarrierCount);
 	for (uint32_t i = 0; i < imageMemoryBarrierCount; i++) {
-		_imageMemoryBarriers.push_back(pImageMemoryBarriers[i]);
+		_barriers.emplace_back(pImageMemoryBarriers[i]);
 	}
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdPipelineBarrier::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdPipelineBarrier<N>::encode(MVKCommandEncoder* cmdEncoder) {
 
 #if MVK_MACOS
-    // Calls below invoke MTLBlitCommandEncoder so must apply this first.
+	// Calls below invoke MTLBlitCommandEncoder so must apply this first.
 	// Check if pipeline barriers are available and we are in a renderpass.
 	if (cmdEncoder->getDevice()->_pMetalFeatures->memoryBarriers && cmdEncoder->_mtlRenderEncoder) {
 		MTLRenderStages srcStages = mvkMTLRenderStagesFromVkPipelineStageFlags(_srcStageMask, false);
 		MTLRenderStages dstStages = mvkMTLRenderStagesFromVkPipelineStageFlags(_dstStageMask, true);
-		for (auto& mb : _memoryBarriers) {
-			MTLBarrierScope scope = mvkMTLBarrierScopeFromVkAccessFlags(mb.dstAccessMask);
-			scope |= mvkMTLBarrierScopeFromVkAccessFlags(mb.srcAccessMask);
-			[cmdEncoder->_mtlRenderEncoder memoryBarrierWithScope: scope
-													  afterStages: srcStages
-													 beforeStages: dstStages];
+
+		id<MTLResource> resources[_barriers.size()];
+		uint32_t rezCnt = 0;
+
+		for (auto& b : _barriers) {
+			switch (b.type) {
+				case MVKPipelineBarrier::Memory: {
+					MTLBarrierScope scope = (mvkMTLBarrierScopeFromVkAccessFlags(b.srcAccessMask) |
+											 mvkMTLBarrierScopeFromVkAccessFlags(b.dstAccessMask));
+					[cmdEncoder->_mtlRenderEncoder memoryBarrierWithScope: scope
+															  afterStages: srcStages
+															 beforeStages: dstStages];
+					break;
+				}
+
+				case MVKPipelineBarrier::Buffer:
+					resources[rezCnt++] = b.mvkBuffer->getMTLBuffer();
+					break;
+
+				case MVKPipelineBarrier::Image:
+                    for (uint8_t planeIndex = 0; planeIndex < b.mvkImage->getPlaneCount(); planeIndex++) {
+                        resources[rezCnt++] = b.mvkImage->getMTLTexture(planeIndex);
+                    }
+					break;
+
+				default:
+					break;
+			}
 		}
-		MVKVectorInline<id<MTLResource>, 16> resources;
-		resources.reserve(_bufferMemoryBarriers.size() + _imageMemoryBarriers.size());
-		for (auto& mb : _bufferMemoryBarriers) {
-			auto* mvkBuff = (MVKBuffer*)mb.buffer;
-			resources.push_back(mvkBuff->getMTLBuffer());
-		}
-		for (auto& mb : _imageMemoryBarriers) {
-			auto* mvkImg = (MVKImage*)mb.image;
-			resources.push_back(mvkImg->getMTLTexture());
-		}
-		if ( !resources.empty() ) {
-			[cmdEncoder->_mtlRenderEncoder memoryBarrierWithResources: resources.data()
-																count: resources.size()
+
+		if (rezCnt) {
+			[cmdEncoder->_mtlRenderEncoder memoryBarrierWithResources: resources
+																count: rezCnt
 														  afterStages: srcStages
 														 beforeStages: dstStages];
 		}
 	} else {
-		if ( !(_memoryBarriers.empty() && _imageMemoryBarriers.empty()) ) {
-			[cmdEncoder->_mtlRenderEncoder textureBarrier];
-		}
+		if (coversTextures()) { [cmdEncoder->_mtlRenderEncoder textureBarrier]; }
 	}
 #endif
 
 	MVKDevice* mvkDvc = cmdEncoder->getDevice();
-    MVKCommandUse cmdUse = kMVKCommandUsePipelineBarrier;
+	MVKCommandUse cmdUse = kMVKCommandUsePipelineBarrier;
 
-	// Apply global memory barriers
-    for (auto& mb : _memoryBarriers) {
-        mvkDvc->applyMemoryBarrier(_srcStageMask, _dstStageMask, &mb, cmdEncoder, cmdUse);
-    }
+	for (auto& b : _barriers) {
+		switch (b.type) {
+			case MVKPipelineBarrier::Memory:
+				mvkDvc->applyMemoryBarrier(_srcStageMask, _dstStageMask, b, cmdEncoder, cmdUse);
+				break;
 
-    // Apply specific buffer barriers
-    for (auto& mb : _bufferMemoryBarriers) {
-        MVKBuffer* mvkBuff = (MVKBuffer*)mb.buffer;
-        mvkBuff->applyBufferMemoryBarrier(_srcStageMask, _dstStageMask, &mb, cmdEncoder, cmdUse);
-    }
+			case MVKPipelineBarrier::Buffer:
+				b.mvkBuffer->applyBufferMemoryBarrier(_srcStageMask, _dstStageMask, b, cmdEncoder, cmdUse);
+				break;
 
-    // Apply specific image barriers
-    for (auto& mb : _imageMemoryBarriers) {
-        MVKImage* mvkImg = (MVKImage*)mb.image;
-        mvkImg->applyImageMemoryBarrier(_srcStageMask, _dstStageMask, &mb, cmdEncoder, cmdUse);
-    }
+			case MVKPipelineBarrier::Image:
+				b.mvkImage->applyImageMemoryBarrier(_srcStageMask, _dstStageMask, b, cmdEncoder, cmdUse);
+				break;
+
+			default:
+				break;
+		}
+	}
 }
 
+template <size_t N>
+bool MVKCmdPipelineBarrier<N>::coversTextures() {
+	for (auto& b : _barriers) {
+		switch (b.type) {
+			case MVKPipelineBarrier::Memory:	return true;
+			case MVKPipelineBarrier::Image: 	return true;
+			default: 							break;
+		}
+	}
+	return false;
+}
+
+template class MVKCmdPipelineBarrier<1>;
+template class MVKCmdPipelineBarrier<4>;
+template class MVKCmdPipelineBarrier<32>;
+
 
 #pragma mark -
 #pragma mark MVKCmdBindPipeline
 
-VkResult MVKCmdBindPipeline::setContent(MVKCommandBuffer* cmdBuff,
-										VkPipelineBindPoint pipelineBindPoint,
-										VkPipeline pipeline) {
-	_bindPoint = pipelineBindPoint;
+VkResult MVKCmdBindPipeline::setContent(MVKCommandBuffer* cmdBuff, VkPipeline pipeline) {
 	_pipeline = (MVKPipeline*)pipeline;
 
 	cmdBuff->recordBindPipeline(this);
@@ -139,29 +162,37 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdBindPipeline::encode(MVKCommandEncoder* cmdEncoder) {
-    cmdEncoder->bindPipeline(_bindPoint, _pipeline);
+
+#pragma mark -
+#pragma mark MVKCmdBindGraphicsPipeline
+
+void MVKCmdBindGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder) {
+	cmdEncoder->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, _pipeline);
 }
 
-bool MVKCmdBindPipeline::isTessellationPipeline() {
-	if (_bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS)
-		return ((MVKGraphicsPipeline*)_pipeline)->isTessellationPipeline();
-	else
-		return false;
+bool MVKCmdBindGraphicsPipeline::isTessellationPipeline() {
+	return ((MVKGraphicsPipeline*)_pipeline)->isTessellationPipeline();
 }
 
 
 #pragma mark -
-#pragma mark MVKCmdBindDescriptorSets
+#pragma mark MVKCmdBindComputePipeline
 
-VkResult MVKCmdBindDescriptorSets::setContent(MVKCommandBuffer* cmdBuff,
-											  VkPipelineBindPoint pipelineBindPoint,
-											  VkPipelineLayout layout,
-											  uint32_t firstSet,
-											  uint32_t setCount,
-											  const VkDescriptorSet* pDescriptorSets,
-											  uint32_t dynamicOffsetCount,
-											  const uint32_t* pDynamicOffsets) {
+void MVKCmdBindComputePipeline::encode(MVKCommandEncoder* cmdEncoder) {
+	cmdEncoder->bindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, _pipeline);
+}
+
+
+#pragma mark -
+#pragma mark MVKCmdBindDescriptorSetsStatic
+
+template <size_t N>
+VkResult MVKCmdBindDescriptorSetsStatic<N>::setContent(MVKCommandBuffer* cmdBuff,
+													   VkPipelineBindPoint pipelineBindPoint,
+													   VkPipelineLayout layout,
+													   uint32_t firstSet,
+													   uint32_t setCount,
+													   const VkDescriptorSet* pDescriptorSets) {
 	_pipelineBindPoint = pipelineBindPoint;
 	_pipelineLayout = (MVKPipelineLayout*)layout;
 	_firstSet = firstSet;
@@ -173,6 +204,35 @@
 		_descriptorSets.push_back((MVKDescriptorSet*)pDescriptorSets[dsIdx]);
 	}
 
+	return VK_SUCCESS;
+}
+
+template <size_t N>
+void MVKCmdBindDescriptorSetsStatic<N>::encode(MVKCommandEncoder* cmdEncoder) {
+	_pipelineLayout->bindDescriptorSets(cmdEncoder, _descriptorSets.contents(), _firstSet, MVKArrayRef<uint32_t>());
+}
+
+template class MVKCmdBindDescriptorSetsStatic<1>;
+template class MVKCmdBindDescriptorSetsStatic<4>;
+template class MVKCmdBindDescriptorSetsStatic<8>;
+
+
+#pragma mark -
+#pragma mark MVKCmdBindDescriptorSetsDynamic
+
+template <size_t N>
+VkResult MVKCmdBindDescriptorSetsDynamic<N>::setContent(MVKCommandBuffer* cmdBuff,
+														VkPipelineBindPoint pipelineBindPoint,
+														VkPipelineLayout layout,
+														uint32_t firstSet,
+														uint32_t setCount,
+														const VkDescriptorSet* pDescriptorSets,
+														uint32_t dynamicOffsetCount,
+														const uint32_t* pDynamicOffsets) {
+
+	MVKCmdBindDescriptorSetsStatic<N>::setContent(cmdBuff, pipelineBindPoint, layout,
+												  firstSet, setCount, pDescriptorSets);
+
 	// Add the dynamic offsets
 	_dynamicOffsets.clear();	// Clear for reuse
 	_dynamicOffsets.reserve(dynamicOffsetCount);
@@ -183,20 +243,25 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdBindDescriptorSets::encode(MVKCommandEncoder* cmdEncoder) {
-	_pipelineLayout->bindDescriptorSets(cmdEncoder, _descriptorSets, _firstSet, _dynamicOffsets);
+template <size_t N>
+void MVKCmdBindDescriptorSetsDynamic<N>::encode(MVKCommandEncoder* cmdEncoder) {
+	MVKCmdBindDescriptorSetsStatic<N>::_pipelineLayout->bindDescriptorSets(cmdEncoder, MVKCmdBindDescriptorSetsStatic<N>::_descriptorSets.contents(), MVKCmdBindDescriptorSetsStatic<N>::_firstSet, _dynamicOffsets.contents());
 }
 
+template class MVKCmdBindDescriptorSetsDynamic<4>;
+template class MVKCmdBindDescriptorSetsDynamic<8>;
+
 
 #pragma mark -
 #pragma mark MVKCmdPushConstants
 
-VkResult MVKCmdPushConstants::setContent(MVKCommandBuffer* cmdBuff,
-										 VkPipelineLayout layout,
-										 VkShaderStageFlags stageFlags,
-										 uint32_t offset,
-										 uint32_t size,
-										 const void* pValues) {
+template <size_t N>
+VkResult MVKCmdPushConstants<N>::setContent(MVKCommandBuffer* cmdBuff,
+											VkPipelineLayout layout,
+											VkShaderStageFlags stageFlags,
+											uint32_t offset,
+											uint32_t size,
+											const void* pValues) {
 	_pipelineLayout = (MVKPipelineLayout*)layout;
 	_stageFlags = stageFlags;
 	_offset = offset;
@@ -207,7 +272,8 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdPushConstants::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdPushConstants<N>::encode(MVKCommandEncoder* cmdEncoder) {
     VkShaderStageFlagBits stages[] = {
         VK_SHADER_STAGE_VERTEX_BIT,
         VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
@@ -217,11 +283,15 @@
     };
     for (auto stage : stages) {
         if (mvkAreAllFlagsEnabled(_stageFlags, stage)) {
-            cmdEncoder->getPushConstants(stage)->setPushConstants(_offset, _pushConstants);
+			cmdEncoder->getPushConstants(stage)->setPushConstants(_offset, _pushConstants.contents());
         }
     }
 }
 
+template class MVKCmdPushConstants<64>;
+template class MVKCmdPushConstants<128>;
+template class MVKCmdPushConstants<512>;
+
 
 #pragma mark -
 #pragma mark MVKCmdPushDescriptorSet
@@ -261,18 +331,17 @@
 		}
         if (mvkDvc->_enabledExtensions.vk_EXT_inline_uniform_block.enabled) {
             const VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock = nullptr;
-            for (auto* next = (VkWriteDescriptorSetInlineUniformBlockEXT*)descWrite.pNext; next; next = (VkWriteDescriptorSetInlineUniformBlockEXT*)next->pNext)
-            {
+			for (const auto* next = (VkBaseInStructure*)descWrite.pNext; next; next = next->pNext) {
                 switch (next->sType) {
                 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: {
-                    pInlineUniformBlock = next;
+                    pInlineUniformBlock = (VkWriteDescriptorSetInlineUniformBlockEXT*)next;
                     break;
                 }
                 default:
                     break;
                 }
             }
-            if (pInlineUniformBlock != nullptr) {
+            if (pInlineUniformBlock) {
                 auto *pNewInlineUniformBlock = new VkWriteDescriptorSetInlineUniformBlockEXT(*pInlineUniformBlock);
                 pNewInlineUniformBlock->pNext = nullptr; // clear pNext just in case, no other extensions are supported at this time
                 descWrite.pNext = pNewInlineUniformBlock;
@@ -286,7 +355,7 @@
 }
 
 void MVKCmdPushDescriptorSet::encode(MVKCommandEncoder* cmdEncoder) {
-	_pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites, _set);
+	_pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites.contents(), _set);
 }
 
 MVKCmdPushDescriptorSet::~MVKCmdPushDescriptorSet() {
@@ -300,11 +369,10 @@
 		if (descWrite.pTexelBufferView) { delete[] descWrite.pTexelBufferView; }
 
 		const VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock = nullptr;
-		for (auto* next = (VkWriteDescriptorSetInlineUniformBlockEXT*)descWrite.pNext; next; next = (VkWriteDescriptorSetInlineUniformBlockEXT*)next->pNext)
-		{
+		for (const auto* next = (VkBaseInStructure*)descWrite.pNext; next; next = next->pNext) {
 			switch (next->sType) {
 				case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: {
-					pInlineUniformBlock = next;
+					pInlineUniformBlock = (VkWriteDescriptorSetInlineUniformBlockEXT*)next;
 					break;
 				}
 				default:
@@ -384,33 +452,44 @@
 
 VkResult MVKCmdSetResetEvent::setContent(MVKCommandBuffer* cmdBuff,
 										 VkEvent event,
-										 VkPipelineStageFlags stageMask,
-										 bool status) {
+										 VkPipelineStageFlags stageMask) {
 	_mvkEvent = (MVKEvent*)event;
-	_status = status;
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdSetResetEvent::encode(MVKCommandEncoder* cmdEncoder) {
-	cmdEncoder->signalEvent(_mvkEvent, _status);
+
+#pragma mark -
+#pragma mark MVKCmdSetEvent
+
+void MVKCmdSetEvent::encode(MVKCommandEncoder* cmdEncoder) {
+	cmdEncoder->signalEvent(_mvkEvent, true);
+}
+
+
+#pragma mark -
+#pragma mark MVKCmdResetEvent
+
+void MVKCmdResetEvent::encode(MVKCommandEncoder* cmdEncoder) {
+	cmdEncoder->signalEvent(_mvkEvent, false);
 }
 
 
 #pragma mark -
 #pragma mark MVKCmdWaitEvents
 
-VkResult MVKCmdWaitEvents::setContent(MVKCommandBuffer* cmdBuff,
-									  uint32_t eventCount,
-									  const VkEvent* pEvents,
-									  VkPipelineStageFlags srcStageMask,
-									  VkPipelineStageFlags dstStageMask,
-									  uint32_t memoryBarrierCount,
-									  const VkMemoryBarrier* pMemoryBarriers,
-									  uint32_t bufferMemoryBarrierCount,
-									  const VkBufferMemoryBarrier* pBufferMemoryBarriers,
-									  uint32_t imageMemoryBarrierCount,
-									  const VkImageMemoryBarrier* pImageMemoryBarriers) {
+template <size_t N>
+VkResult MVKCmdWaitEvents<N>::setContent(MVKCommandBuffer* cmdBuff,
+										 uint32_t eventCount,
+										 const VkEvent* pEvents,
+										 VkPipelineStageFlags srcStageMask,
+										 VkPipelineStageFlags dstStageMask,
+										 uint32_t memoryBarrierCount,
+										 const VkMemoryBarrier* pMemoryBarriers,
+										 uint32_t bufferMemoryBarrierCount,
+										 const VkBufferMemoryBarrier* pBufferMemoryBarriers,
+										 uint32_t imageMemoryBarrierCount,
+										 const VkImageMemoryBarrier* pImageMemoryBarriers) {
 	_mvkEvents.clear();	// Clear for reuse
 	_mvkEvents.reserve(eventCount);
 	for (uint32_t i = 0; i < eventCount; i++) {
@@ -420,9 +499,13 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdWaitEvents::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdWaitEvents<N>::encode(MVKCommandEncoder* cmdEncoder) {
 	for (MVKEvent* mvkEvt : _mvkEvents) {
 		mvkEvt->encodeWait(cmdEncoder->_mtlCmdBuffer);
 	}
 }
 
+template class MVKCmdWaitEvents<1>;
+template class MVKCmdWaitEvents<8>;
+
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdQueries.h b/MoltenVK/MoltenVK/Commands/MVKCmdQueries.h
index ac0d848..e76d01e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdQueries.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdQueries.h
@@ -140,9 +140,9 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-    uint32_t _queryCount;
     MVKBuffer* _destBuffer;
     VkDeviceSize _destOffset;
     VkDeviceSize _destStride;
     VkQueryResultFlags _flags;
+	uint32_t _queryCount;
 };
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index a41b4b9..300b197 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -20,7 +20,7 @@
 
 #include "MVKCommand.h"
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 #import <Metal/Metal.h>
 
@@ -31,7 +31,11 @@
 #pragma mark -
 #pragma mark MVKCmdBeginRenderPass
 
-/** Vulkan command to begin a render pass. */
+/**
+ * Vulkan command to begin a render pass.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdBeginRenderPass : public MVKCommand, public MVKLoadStoreOverrideMixin {
 
 public:
@@ -44,13 +48,18 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-	VkRenderPassBeginInfo _info;
-	VkSubpassContents _contents;
+	MVKSmallVector<VkClearValue, N> _clearValues;
 	MVKRenderPass* _renderPass;
 	MVKFramebuffer* _framebuffer;
-	MVKVectorInline<VkClearValue, 8> _clearValues;
+	VkRect2D _renderArea;
+	VkSubpassContents _contents;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdBeginRenderPass<1> MVKCmdBeginRenderPass1;
+typedef MVKCmdBeginRenderPass<2> MVKCmdBeginRenderPass2;
+typedef MVKCmdBeginRenderPass<9> MVKCmdBeginRenderPassMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdNextSubpass
@@ -91,7 +100,11 @@
 #pragma mark -
 #pragma mark MVKCmdExecuteCommands
 
-/** Vulkan command to execute secondary command buffers. */
+/**
+ * Vulkan command to execute secondary command buffers.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdExecuteCommands : public MVKCommand {
 
 public:
@@ -104,18 +117,20 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
-	MVKVectorInline<MVKCommandBuffer*, 64> _secondaryCommandBuffers;
+	MVKSmallVector<MVKCommandBuffer*, N> _secondaryCommandBuffers;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdExecuteCommands<1> MVKCmdExecuteCommands1;
+typedef MVKCmdExecuteCommands<16> MVKCmdExecuteCommandsMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdSetViewport
 
 /**
  * Vulkan command to set the viewports.
- * This is a template class to support different vector pre-allocations, so we can balance
- * in-line memory allocation betweeen the very common case of a single viewport, and the
- * maximal number, by choosing which concrete implementation to use based on viewport count.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
  */
 template <size_t N>
 class MVKCmdSetViewport : public MVKCommand {
@@ -131,11 +146,11 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
+	MVKSmallVector<VkViewport, N> _viewports;
 	uint32_t _firstViewport;
-	MVKVectorInline<VkViewport, N> _viewports;
 };
 
-// Concrete template class implemenations.
+// Concrete template class implementations.
 typedef MVKCmdSetViewport<1> MVKCmdSetViewport1;
 typedef MVKCmdSetViewport<kMVKCachedViewportScissorCount> MVKCmdSetViewportMulti;
 
@@ -145,9 +160,7 @@
 
 /**
  * Vulkan command to set the scissor rectangles.
- * This is a template class to support different vector pre-allocations, so we can balance
- * in-line memory allocation betweeen the very common case of a single scissor, and the
- * maximal number, by choosing which concrete implementation to use based on scissor count.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
  */
 template <size_t N>
 class MVKCmdSetScissor : public MVKCommand {
@@ -163,11 +176,11 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
+	MVKSmallVector<VkRect2D, N> _scissors;
 	uint32_t _firstScissor;
-	MVKVectorInline<VkRect2D, N> _scissors;
 };
 
-// Concrete template class implemenations.
+// Concrete template class implementations.
 typedef MVKCmdSetScissor<1> MVKCmdSetScissor1;
 typedef MVKCmdSetScissor<kMVKCachedViewportScissorCount> MVKCmdSetScissorMulti;
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
index 393341f..6db1a8c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
@@ -28,21 +28,23 @@
 #pragma mark -
 #pragma mark MVKCmdBeginRenderPass
 
-VkResult MVKCmdBeginRenderPass::setContent(MVKCommandBuffer* cmdBuff,
-										   const VkRenderPassBeginInfo* pRenderPassBegin,
-										   VkSubpassContents contents) {
-	_info = *pRenderPassBegin;
+template <size_t N>
+VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
+											  const VkRenderPassBeginInfo* pRenderPassBegin,
+											  VkSubpassContents contents) {
 	_contents = contents;
-	_renderPass = (MVKRenderPass*)_info.renderPass;
-	_framebuffer = (MVKFramebuffer*)_info.framebuffer;
+	_renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
+	_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
+	_renderArea = pRenderPassBegin->renderArea;
     _loadOverride = false;
     _storeOverride = false;
 
 	// Add clear values
+	uint32_t cvCnt = pRenderPassBegin->clearValueCount;
 	_clearValues.clear();	// Clear for reuse
-	_clearValues.reserve(_info.clearValueCount);
-	for (uint32_t i = 0; i < _info.clearValueCount; i++) {
-		_clearValues.push_back(_info.pClearValues[i]);
+	_clearValues.reserve(cvCnt);
+	for (uint32_t i = 0; i < cvCnt; i++) {
+		_clearValues.push_back(pRenderPassBegin->pClearValues[i]);
 	}
 
 	cmdBuff->recordBeginRenderPass(this);
@@ -50,11 +52,16 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdBeginRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) {
 //	MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
-	cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _info.renderArea, &_clearValues, _loadOverride, _storeOverride);
+	cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents(), _loadOverride, _storeOverride);
 }
 
+template class MVKCmdBeginRenderPass<1>;
+template class MVKCmdBeginRenderPass<2>;
+template class MVKCmdBeginRenderPass<9>;
+
 
 #pragma mark -
 #pragma mark MVKCmdNextSubpass
@@ -75,7 +82,7 @@
 #pragma mark MVKCmdEndRenderPass
 
 VkResult MVKCmdEndRenderPass::setContent(MVKCommandBuffer* cmdBuff) {
-	cmdBuff->recordEndRenderPass(this);
+	cmdBuff->recordEndRenderPass();
 	return VK_SUCCESS;
 }
 
@@ -88,9 +95,10 @@
 #pragma mark -
 #pragma mark MVKCmdExecuteCommands
 
-VkResult MVKCmdExecuteCommands::setContent(MVKCommandBuffer* cmdBuff,
-										   uint32_t commandBuffersCount,
-										   const VkCommandBuffer* pCommandBuffers) {
+template <size_t N>
+VkResult MVKCmdExecuteCommands<N>::setContent(MVKCommandBuffer* cmdBuff,
+											  uint32_t commandBuffersCount,
+											  const VkCommandBuffer* pCommandBuffers) {
 	// Add clear values
 	_secondaryCommandBuffers.clear();	// Clear for reuse
 	_secondaryCommandBuffers.reserve(commandBuffersCount);
@@ -101,10 +109,14 @@
 	return VK_SUCCESS;
 }
 
-void MVKCmdExecuteCommands::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdExecuteCommands<N>::encode(MVKCommandEncoder* cmdEncoder) {
     for (auto& cb : _secondaryCommandBuffers) { cmdEncoder->encodeSecondary(cb); }
 }
 
+template class MVKCmdExecuteCommands<1>;
+template class MVKCmdExecuteCommands<16>;
+
 
 #pragma mark -
 #pragma mark MVKCmdSetViewport
@@ -126,7 +138,7 @@
 
 template <size_t N>
 void MVKCmdSetViewport<N>::encode(MVKCommandEncoder* cmdEncoder) {
-	cmdEncoder->_viewportState.setViewports(_viewports, _firstViewport, true);
+	cmdEncoder->_viewportState.setViewports(_viewports.contents(), _firstViewport, true);
 }
 
 template class MVKCmdSetViewport<1>;
@@ -153,7 +165,7 @@
 
 template <size_t N>
 void MVKCmdSetScissor<N>::encode(MVKCommandEncoder* cmdEncoder) {
-    cmdEncoder->_scissorState.setScissors(_scissors, _firstScissor, true);
+    cmdEncoder->_scissorState.setScissors(_scissors.contents(), _firstScissor, true);
 }
 
 template class MVKCmdSetScissor<1>;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 66e316a..cedf30b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -22,7 +22,7 @@
 #include "MVKMTLBufferAllocation.h"
 #include "MVKCommandResourceFactory.h"
 #include "MVKFoundation.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 #import <Metal/Metal.h>
 
@@ -33,7 +33,11 @@
 #pragma mark -
 #pragma mark MVKCmdCopyImage
 
-/** Vulkan command to copy image regions. */
+/**
+ * Vulkan command to copy image regions.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdCopyImage : public MVKCommand {
 
 public:
@@ -43,40 +47,26 @@
 						VkImage dstImage,
 						VkImageLayout dstImageLayout,
 						uint32_t regionCount,
-						const VkImageCopy* pRegions,
-						MVKCommandUse commandUse = kMVKCommandUseCopyImage);
+						const VkImageCopy* pRegions);
 
-	void encode(MVKCommandEncoder* cmdEncoder) override;
+	void encode(MVKCommandEncoder* cmdEncoder) override { encode(cmdEncoder, kMVKCommandUseCopyImage); }
+
+	void encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse commandUse);
 
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
-	VkResult setContent(MVKCommandBuffer* cmdBuff,
-						VkImage srcImage,
-						VkImageLayout srcImageLayout,
-						VkImage dstImage,
-						VkImageLayout dstImageLayout,
-						bool formatsMustMatch,
-						MVKCommandUse commandUse);
-	void addImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts);
-	void addTempBufferImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts);
 
+	MVKSmallVector<VkImageCopy, N> _vkImageCopies;
 	MVKImage* _srcImage;
-	VkImageLayout _srcLayout;
 	MVKImage* _dstImage;
+	VkImageLayout _srcLayout;
 	VkImageLayout _dstLayout;
-	uint32_t _srcSampleCount;
-	uint32_t _dstSampleCount;
-	bool _isSrcCompressed;
-	bool _isDstCompressed;
-	bool _canCopyFormats;
-	bool _useTempBuffer;
-	MVKVectorInline<VkImageCopy, 4> _imageCopyRegions;
-	MVKVectorInline<VkBufferImageCopy, 4> _srcTmpBuffImgCopies;
-	MVKVectorInline<VkBufferImageCopy, 4> _dstTmpBuffImgCopies;
-	size_t _tmpBuffSize;
-    MVKCommandUse _commandUse;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdCopyImage<1> MVKCmdCopyImage1;
+typedef MVKCmdCopyImage<4> MVKCmdCopyImageMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdBlitImage
@@ -90,8 +80,12 @@
 	MVKVertexPosTex vertices[kMVKBlitVertexCount];
 } MVKImageBlitRender;
 
-/** Vulkan command to BLIT image regions. */
-class MVKCmdBlitImage : public MVKCmdCopyImage {
+/**
+ * Vulkan command to BLIT image regions.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdBlitImage : public MVKCommand {
 
 public:
 	VkResult setContent(MVKCommandBuffer* cmdBuff,
@@ -101,39 +95,46 @@
 						VkImageLayout dstImageLayout,
 						uint32_t regionCount,
 						const VkImageBlit* pRegions,
-						VkFilter filter,
-						MVKCommandUse commandUse = kMVKCommandUseBlitImage);
+						VkFilter filter);
 
-	void encode(MVKCommandEncoder* cmdEncoder) override;
+	void encode(MVKCommandEncoder* cmdEncoder) override { encode(cmdEncoder, kMVKCommandUseBlitImage); }
 
-	MVKCmdBlitImage();
-
-	~MVKCmdBlitImage() override;
+	void encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse commandUse);
 
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	bool canCopyFormats(const VkImageBlit& region);
 	bool canCopy(const VkImageBlit& region);
-	void addImageBlitRegion(const VkImageBlit& region, MVKPixelFormats* pixFmts);
-	void addImageCopyRegionFromBlitRegion(const VkImageBlit& region, MVKPixelFormats* pixFmts);
 	void populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region);
-    void initMTLRenderPassDescriptor();
 
-	MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
-	MVKRPSKeyBlitImg _blitKey;
-	MVKVectorInline<MVKImageBlitRender, 4> _mvkImageBlitRenders;
+	MVKSmallVector<VkImageBlit, N> _vkImageBlits;
+	MVKImage* _srcImage;
+	MVKImage* _dstImage;
+	VkImageLayout _srcLayout;
+	VkImageLayout _dstLayout;
+	VkFilter _filter;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdBlitImage<1> MVKCmdBlitImage1;
+typedef MVKCmdBlitImage<4> MVKCmdBlitImageMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdResolveImage
 
 /** Describes Metal texture resolve parameters. */
 typedef struct {
-    uint32_t	level;
-    uint32_t	slice;
+    VkImageCopy* copyRegion;
+    uint32_t level;
+    uint32_t slice;
 } MVKMetalResolveSlice;
 
-/** Vulkan command to resolve image regions. */
+/**
+ * Vulkan command to resolve image regions.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdResolveImage : public MVKCommand {
 
 public:
@@ -147,33 +148,29 @@
 
     void encode(MVKCommandEncoder* cmdEncoder) override;
 
-    MVKCmdResolveImage();
-
-    ~MVKCmdResolveImage() override;
-
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
-	void addExpansionRegion(const VkImageResolve& resolveRegion);
-    void addCopyRegion(const VkImageResolve& resolveRegion);
-    void addResolveSlices(const VkImageResolve& resolveRegion);
-    void initMTLRenderPassDescriptor();
 
+	MVKSmallVector<VkImageResolve, N> _vkImageResolves;
     MVKImage* _srcImage;
+	MVKImage* _dstImage;
     VkImageLayout _srcLayout;
-    MVKImage* _dstImage;
     VkImageLayout _dstLayout;
-    MVKImageDescriptorData _transferImageData;
-    MTLRenderPassDescriptor* _mtlRenderPassDescriptor;
-	MVKVectorInline<VkImageBlit, 4> _expansionRegions;
-	MVKVectorInline<VkImageCopy, 4> _copyRegions;
-	MVKVectorInline<MVKMetalResolveSlice, 4> _mtlResolveSlices;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdResolveImage<1> MVKCmdResolveImage1;
+typedef MVKCmdResolveImage<4> MVKCmdResolveImageMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdCopyBuffer
 
-/** Vulkan command to copy buffer regions. */
+/**
+ * Vulkan command to copy buffer regions.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdCopyBuffer : public MVKCommand {
 
 public:
@@ -188,16 +185,24 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
+	MVKSmallVector<VkBufferCopy, N> _bufferCopyRegions;
 	MVKBuffer* _srcBuffer;
 	MVKBuffer* _dstBuffer;
-	MVKVectorInline<VkBufferCopy, 4> _mtlBuffCopyRegions;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdCopyBuffer<1> MVKCmdCopyBuffer1;
+typedef MVKCmdCopyBuffer<4> MVKCmdCopyBufferMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdBufferImageCopy
 
-/** Command to copy either from a buffer to an image, or from an image to a buffer. */
+/**
+ * Vulkan command to copy either from a buffer to an image, or from an image to a buffer.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdBufferImageCopy : public MVKCommand {
 
 public:
@@ -215,18 +220,28 @@
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 	bool isArrayTexture();
 
+	MVKSmallVector<VkBufferImageCopy, N> _bufferImageCopyRegions;
     MVKBuffer* _buffer;
     MVKImage* _image;
     VkImageLayout _imageLayout;
-	MVKVectorInline<VkBufferImageCopy, 4> _bufferImageCopyRegions;
     bool _toImage = false;
 };
 
+// Concrete template class implementations.
+typedef MVKCmdBufferImageCopy<1> MVKCmdBufferImageCopy1;
+typedef MVKCmdBufferImageCopy<4> MVKCmdBufferImageCopy4;	// To support MVKCmdCopyImage
+typedef MVKCmdBufferImageCopy<8> MVKCmdBufferImageCopy8;
+typedef MVKCmdBufferImageCopy<16> MVKCmdBufferImageCopyMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdClearAttachments
 
-/** Vulkan command to clear attachment regions. */
+/**
+ * Abstract Vulkan command to clear attachment regions.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdClearAttachments : public MVKCommand {
 
 public:
@@ -239,25 +254,73 @@
     void encode(MVKCommandEncoder* cmdEncoder) override;
 
 protected:
-	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
-    void populateVertices(float attWidth, float attHeight);
-    void populateVertices(VkClearRect& clearRect, float attWidth, float attHeight);
+    void populateVertices(simd::float4* vertices, float attWidth, float attHeight);
+	uint32_t populateVertices(simd::float4* vertices, uint32_t startVertex,
+							  VkClearRect& clearRect, float attWidth, float attHeight);
+	virtual VkClearValue& getClearValue(uint32_t attIdx) = 0;
+	virtual void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) = 0;
 
-	MVKVectorInline<VkClearRect, 4> _clearRects;
-	MVKVectorInline<simd::float4, (4 * 6)> _vertices;
-    simd::float4 _clearColors[kMVKClearAttachmentCount];
-    VkClearValue _vkClearValues[kMVKClearAttachmentCount];
+	MVKSmallVector<VkClearRect, N> _clearRects;
     MVKRPSKeyClearAtt _rpsKey;
+	bool _isClearingDepth;
+	bool _isClearingStencil;
+	float _mtlDepthVal;
     uint32_t _mtlStencilValue;
-    bool _isClearingDepth;
-    bool _isClearingStencil;
 };
 
 
 #pragma mark -
+#pragma mark MVKCmdClearSingleAttachment
+
+/**
+ * Vulkan command to clear regions in a single attachment.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdClearSingleAttachment : public MVKCmdClearAttachments<N> {
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	VkClearValue& getClearValue(uint32_t attIdx) override { return _vkClearValue; }
+	void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) override { _vkClearValue = clearValue; }
+
+	VkClearValue _vkClearValue;
+};
+
+typedef MVKCmdClearSingleAttachment<1> MVKCmdClearSingleAttachment1;
+typedef MVKCmdClearSingleAttachment<4> MVKCmdClearSingleAttachmentMulti;
+
+
+#pragma mark -
+#pragma mark MVKCmdClearMultiAttachments
+
+/**
+ * Vulkan command to clear regions multiple attachment.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdClearMultiAttachments : public MVKCmdClearAttachments<N> {
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	VkClearValue& getClearValue(uint32_t attIdx) override { return _vkClearValues[attIdx]; }
+	void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) override { _vkClearValues[attIdx] = clearValue; }
+
+	VkClearValue _vkClearValues[kMVKCachedColorAttachmentCount];
+};
+
+typedef MVKCmdClearMultiAttachments<1> MVKCmdClearMultiAttachments1;
+typedef MVKCmdClearMultiAttachments<4> MVKCmdClearMultiAttachmentsMulti;
+
+
+#pragma mark -
 #pragma mark MVKCmdClearImage
 
-/** Vulkan command to clear an image. */
+/**
+ * Abstract Vulkan command to clear an image.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
 class MVKCmdClearImage : public MVKCommand {
 
 public:
@@ -266,24 +329,58 @@
 						VkImageLayout imageLayout,
 						const VkClearValue& clearValue,
 						uint32_t rangeCount,
-						const VkImageSubresourceRange* pRanges,
-						bool isDepthStencilClear);
+						const VkImageSubresourceRange* pRanges);
 
     void encode(MVKCommandEncoder* cmdEncoder) override;
 
 protected:
-	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
     uint32_t populateMetalCopyRegions(const VkImageBlit* pRegion, uint32_t cpyRgnIdx);
     uint32_t populateMetalBlitRenders(const VkImageBlit* pRegion, uint32_t rendRgnIdx);
     void populateVertices(MVKVertexPosTex* vertices, const VkImageBlit* pRegion);
-    
-    MVKImage* _image;
-    VkImageLayout _imgLayout;
-	MVKVectorInline<VkImageSubresourceRange, 4> _subresourceRanges;
+	virtual bool isDepthStencilClear() = 0;
+
+	MVKSmallVector<VkImageSubresourceRange, N> _subresourceRanges;
+	MVKImage* _image;
 	VkClearValue _clearValue;
-    bool _isDepthStencilClear;
 };
 
+#pragma mark -
+#pragma mark MVKCmdClearColorImage
+
+/**
+ * Abstract Vulkan command to clear a color image.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdClearColorImage : public MVKCmdClearImage<N> {
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	bool isDepthStencilClear() override { return false; }
+};
+
+typedef MVKCmdClearColorImage<1> MVKCmdClearColorImage1;
+typedef MVKCmdClearColorImage<4> MVKCmdClearColorImageMulti;
+
+
+#pragma mark -
+#pragma mark MVKCmdClearDepthStencilImage
+
+/**
+ * Abstract Vulkan command to clear a depth stencil image.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKCmdClearDepthStencilImage : public MVKCmdClearImage<N> {
+
+protected:
+	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
+	bool isDepthStencilClear() override { return true; }
+};
+
+typedef MVKCmdClearDepthStencilImage<1> MVKCmdClearDepthStencilImage1;
+typedef MVKCmdClearDepthStencilImage<4> MVKCmdClearDepthStencilImageMulti;
+
 
 #pragma mark -
 #pragma mark MVKCmdFillBuffer
@@ -328,8 +425,8 @@
 protected:
 	MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
 
+	MVKSmallVector<uint8_t> _srcDataCache;
 	MVKBuffer* _dstBuffer;
     VkDeviceSize _dstOffset;
     VkDeviceSize _dataSize;
-    MVKVectorDefault<uint8_t> _srcDataCache;
 };
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index cb9f410..848aa94 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -47,278 +47,231 @@
 #pragma mark -
 #pragma mark MVKCmdCopyImage
 
-VkResult MVKCmdCopyImage::setContent(MVKCommandBuffer* cmdBuff,
-									 VkImage srcImage,
-									 VkImageLayout srcImageLayout,
-									 VkImage dstImage,
-									 VkImageLayout dstImageLayout,
-									 uint32_t regionCount,
-									 const VkImageCopy* pRegions,
-									 MVKCommandUse commandUse) {
-
-	setContent(cmdBuff, srcImage, srcImageLayout, dstImage, dstImageLayout, false, commandUse);
-
-	MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
-	for (uint32_t i = 0; i < regionCount; i++) {
-		addImageCopyRegion(pRegions[i], pixFmts);
-	}
-
-	// Validate
-	if ( !_canCopyFormats ) {
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Cannot copy between incompatible formats, such as formats of different pixel sizes.");
-	}
-	if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Metal does not support copying to or from slices of a 3D texture.");
-	}
-
-	return VK_SUCCESS;
-}
-
-// Sets common content for use by this class and subclasses
-VkResult MVKCmdCopyImage::setContent(MVKCommandBuffer* cmdBuff,
-									 VkImage srcImage,
-									 VkImageLayout srcImageLayout,
-									 VkImage dstImage,
-									 VkImageLayout dstImageLayout,
-									 bool formatsMustMatch,
-									 MVKCommandUse commandUse) {
-	MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
-
+template <size_t N>
+VkResult MVKCmdCopyImage<N>::setContent(MVKCommandBuffer* cmdBuff,
+										VkImage srcImage,
+										VkImageLayout srcImageLayout,
+										VkImage dstImage,
+										VkImageLayout dstImageLayout,
+										uint32_t regionCount,
+										const VkImageCopy* pRegions) {
 	_srcImage = (MVKImage*)srcImage;
 	_srcLayout = srcImageLayout;
-	_srcSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_srcImage->getSampleCount());
-	_isSrcCompressed = _srcImage->getIsCompressed();
-	MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
-	uint32_t srcBytesPerBlock = pixFmts->getBytesPerBlock(srcMTLPixFmt);
 
 	_dstImage = (MVKImage*)dstImage;
 	_dstLayout = dstImageLayout;
-	_dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
-	_isDstCompressed = _dstImage->getIsCompressed();
-	MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat();
-	uint32_t dstBytesPerBlock = pixFmts->getBytesPerBlock(dstMTLPixFmt);
 
-	_canCopyFormats = (_dstSampleCount == _srcSampleCount) && (formatsMustMatch
-																? (dstMTLPixFmt == srcMTLPixFmt)
-																: (dstBytesPerBlock == srcBytesPerBlock));
-
-	_useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (_isSrcCompressed || _isDstCompressed);	// Different formats and at least one is compressed
-
-	_commandUse = commandUse;
-	_tmpBuffSize = 0;
-
-	_imageCopyRegions.clear();		// Clear for reuse
-	_srcTmpBuffImgCopies.clear();	// Clear for reuse
-	_dstTmpBuffImgCopies.clear();	// Clear for reuse
+	_vkImageCopies.clear();		// Clear for reuse
+    for (uint32_t regionIdx = 0; regionIdx < regionCount; regionIdx++) {
+        auto& vkIR = pRegions[regionIdx];
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.srcSubresource.aspectMask);
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.dstSubresource.aspectMask);
+    
+        // Validate
+        MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
+        if ((_dstImage->getSampleCount() != _srcImage->getSampleCount()) ||
+            (pixFmts->getBytesPerBlock(_dstImage->getMTLPixelFormat(dstPlaneIndex)) != pixFmts->getBytesPerBlock(_srcImage->getMTLPixelFormat(srcPlaneIndex)))) {
+            return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Cannot copy between incompatible formats, such as formats of different pixel sizes, or between images with different sample counts.");
+        }
+        
+		_vkImageCopies.push_back(vkIR);
+	}
+    
+    // Validate
+    if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
+        return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Metal does not support copying to or from slices of a 3D texture.");
+    }
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdCopyImage::addImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts) {
-	if (_useTempBuffer) {
-		addTempBufferImageCopyRegion(region, pixFmts);	// Convert to image->buffer->image copies
-	} else {
-		_imageCopyRegions.push_back(region);
-	}
+template <size_t N>
+void MVKCmdCopyImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse commandUse) {
+    MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
+    uint32_t copyCnt = (uint32_t)_vkImageCopies.size();
+    VkBufferImageCopy vkSrcCopies[copyCnt];
+    VkBufferImageCopy vkDstCopies[copyCnt];
+    size_t tmpBuffSize = 0;
+
+    for (uint32_t copyIdx = 0; copyIdx < copyCnt; copyIdx++) {
+        auto& vkIC = _vkImageCopies[copyIdx];
+        
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIC.srcSubresource.aspectMask);
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIC.dstSubresource.aspectMask);
+        
+        MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat(srcPlaneIndex);
+        bool isSrcCompressed = _srcImage->getIsCompressed();
+
+        MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat(dstPlaneIndex);
+        bool isDstCompressed = _dstImage->getIsCompressed();
+
+        // If source and destination have different formats and at least one is compressed, use a temporary intermediary buffer
+        bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isSrcCompressed || isDstCompressed);
+
+        if (useTempBuffer) {
+            // Add copy from source image to temp buffer.
+            auto& srcCpy = vkSrcCopies[copyIdx];
+            srcCpy.bufferOffset = tmpBuffSize;
+            srcCpy.bufferRowLength = 0;
+            srcCpy.bufferImageHeight = 0;
+            srcCpy.imageSubresource = vkIC.srcSubresource;
+            srcCpy.imageOffset = vkIC.srcOffset;
+            srcCpy.imageExtent = vkIC.extent;
+
+            // Add copy from temp buffer to destination image.
+            // Extent is provided in source texels. If the source is compressed but the
+            // destination is not, each destination pixel will consume an entire source block,
+            // so we must downscale the destination extent by the size of the source block.
+            VkExtent3D dstExtent = vkIC.extent;
+            if (isSrcCompressed && !isDstCompressed) {
+                VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
+                dstExtent.width /= srcBlockExtent.width;
+                dstExtent.height /= srcBlockExtent.height;
+            }
+            auto& dstCpy = vkDstCopies[copyIdx];
+            dstCpy.bufferOffset = tmpBuffSize;
+            dstCpy.bufferRowLength = 0;
+            dstCpy.bufferImageHeight = 0;
+            dstCpy.imageSubresource = vkIC.dstSubresource;
+            dstCpy.imageOffset = vkIC.dstOffset;
+            dstCpy.imageExtent = dstExtent;
+
+            size_t bytesPerRow = pixFmts->getBytesPerRow(srcMTLPixFmt, vkIC.extent.width);
+            size_t bytesPerRegion = pixFmts->getBytesPerLayer(srcMTLPixFmt, bytesPerRow, vkIC.extent.height);
+            tmpBuffSize += bytesPerRegion;
+        } else {
+            // Map the source pixel format to the dest pixel format through a texture view on the source texture.
+            // If the source and dest pixel formats are the same, this will simply degenerate to the source texture itself.
+            id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex, _dstImage->getMTLPixelFormat(dstPlaneIndex));
+            id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex);
+            if ( !srcMTLTex || !dstMTLTex ) { return; }
+
+            id<MTLBlitCommandEncoder> mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(commandUse);
+
+            // If copies can be performed using direct texture-texture copying, do so
+            uint32_t srcLevel = vkIC.srcSubresource.mipLevel;
+            MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(vkIC.srcOffset);
+            MTLSize srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
+                                              srcOrigin,
+                                              mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
+            uint32_t dstLevel = vkIC.dstSubresource.mipLevel;
+            MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(vkIC.dstOffset);
+            uint32_t srcBaseLayer = vkIC.srcSubresource.baseArrayLayer;
+            uint32_t dstBaseLayer = vkIC.dstSubresource.baseArrayLayer;
+            uint32_t layCnt = vkIC.srcSubresource.layerCount;
+
+            for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
+                [mtlBlitEnc copyFromTexture: srcMTLTex
+                                sourceSlice: srcBaseLayer + layIdx
+                                sourceLevel: srcLevel
+                               sourceOrigin: srcOrigin
+                                 sourceSize: srcSize
+                                  toTexture: dstMTLTex
+                           destinationSlice: dstBaseLayer + layIdx
+                           destinationLevel: dstLevel
+                          destinationOrigin: dstOrigin];
+            }
+        }
+    }
+
+    if (tmpBuffSize > 0) {
+        MVKBufferDescriptorData tempBuffData;
+        tempBuffData.size = tmpBuffSize;
+        tempBuffData.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
+        VkBuffer tempBuff = (VkBuffer)cmdEncoder->getCommandEncodingPool()->getTransferMVKBuffer(tempBuffData);
+
+        MVKCmdBufferImageCopy<N> cpyCmd;
+
+        // Copy from source image to buffer
+        // Create and execute a temporary buffer image command.
+        // To be threadsafe...do NOT acquire and return the command from the pool.
+        cpyCmd.setContent(cmdEncoder->_cmdBuffer, tempBuff, (VkImage)_srcImage, _srcLayout, copyCnt, vkSrcCopies, false);
+        cpyCmd.encode(cmdEncoder);
+
+        // Copy from buffer to destination image
+        // Create and execute a temporary buffer image command.
+        // To be threadsafe...do NOT acquire and return the command from the pool.
+        cpyCmd.setContent(cmdEncoder->_cmdBuffer, tempBuff, (VkImage)_dstImage, _dstLayout, copyCnt, vkDstCopies, true);
+        cpyCmd.encode(cmdEncoder);
+    }
 }
 
-// Add an image->buffer copy and buffer->image copy to replace the image->image copy
-void MVKCmdCopyImage::addTempBufferImageCopyRegion(const VkImageCopy& region, MVKPixelFormats* pixFmts) {
-
-	// Add copy from source image to temp buffer.
-	VkBufferImageCopy buffImgCpy;
-	buffImgCpy.bufferOffset = _tmpBuffSize;
-	buffImgCpy.bufferRowLength = 0;
-	buffImgCpy.bufferImageHeight = 0;
-	buffImgCpy.imageSubresource = region.srcSubresource;
-	buffImgCpy.imageOffset = region.srcOffset;
-	buffImgCpy.imageExtent = region.extent;
-	_srcTmpBuffImgCopies.push_back(buffImgCpy);
-
-	// Add copy from temp buffer to destination image.
-	// Extent is provided in source texels. If the source is compressed but the
-	// destination is not, each destination pixel will consume an entire source block,
-	// so we must downscale the destination extent by the size of the source block.
-	MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
-	VkExtent3D dstExtent = region.extent;
-	if (_isSrcCompressed && !_isDstCompressed) {
-		VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
-		dstExtent.width /= srcBlockExtent.width;
-		dstExtent.height /= srcBlockExtent.height;
-	}
-	buffImgCpy.bufferOffset = _tmpBuffSize;
-	buffImgCpy.bufferRowLength = 0;
-	buffImgCpy.bufferImageHeight = 0;
-	buffImgCpy.imageSubresource = region.dstSubresource;
-	buffImgCpy.imageOffset = region.dstOffset;
-	buffImgCpy.imageExtent = dstExtent;
-	_dstTmpBuffImgCopies.push_back(buffImgCpy);
-
-	NSUInteger bytesPerRow = pixFmts->getBytesPerRow(srcMTLPixFmt, region.extent.width);
-	NSUInteger bytesPerRegion = pixFmts->getBytesPerLayer(srcMTLPixFmt, bytesPerRow, region.extent.height);
-	_tmpBuffSize += bytesPerRegion;
-}
-
-void MVKCmdCopyImage::encode(MVKCommandEncoder* cmdEncoder) {
-	// Unless we need to use an intermediary buffer copy, map the source pixel format to the
-	// dest pixel format through a texture view on the source texture. If the source and dest
-	// pixel formats are the same, this will simply degenerate to the source texture itself.
-	MTLPixelFormat mapSrcMTLPixFmt = (_useTempBuffer ? _srcImage : _dstImage)->getMTLPixelFormat();
-	id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(mapSrcMTLPixFmt);
-	id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
-	if ( !srcMTLTex || !dstMTLTex ) { return; }
-
-	id<MTLBlitCommandEncoder> mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(_commandUse);
-
-	// If copies can be performed using direct texture-texture copying, do so
-	for (auto& cpyRgn : _imageCopyRegions) {
-		uint32_t  srcLevel = cpyRgn.srcSubresource.mipLevel;
-		MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.srcOffset);
-		MTLSize   srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(cpyRgn.extent),
-											srcOrigin,
-											mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcLevel)));
-		uint32_t  dstLevel = cpyRgn.dstSubresource.mipLevel;
-		MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.dstOffset);
-		uint32_t  srcBaseLayer = cpyRgn.srcSubresource.baseArrayLayer;
-		uint32_t  dstBaseLayer = cpyRgn.dstSubresource.baseArrayLayer;
-		uint32_t  layCnt = cpyRgn.srcSubresource.layerCount;
-
-		for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
-			[mtlBlitEnc copyFromTexture: srcMTLTex
-							sourceSlice: srcBaseLayer + layIdx
-							sourceLevel: srcLevel
-						   sourceOrigin: srcOrigin
-							 sourceSize: srcSize
-							  toTexture: dstMTLTex
-					   destinationSlice: dstBaseLayer + layIdx
-					   destinationLevel: dstLevel
-					  destinationOrigin: dstOrigin];
-		}
-	}
-
-	// If copies could not be performed directly between images,
-	// use a temporary buffer acting as a waystation between the images.
-	if ( !_srcTmpBuffImgCopies.empty() ) {
-		MVKBufferDescriptorData tempBuffData;
-		tempBuffData.size = _tmpBuffSize;
-		tempBuffData.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
-		MVKBuffer* tempBuff = cmdEncoder->getCommandEncodingPool()->getTransferMVKBuffer(tempBuffData);
-
-		MVKCmdBufferImageCopy cpyCmd;
-
-		// Copy from source image to buffer
-		// Create and execute a temporary buffer image command.
-		// To be threadsafe...do NOT acquire and return the command from the pool.
-		cpyCmd.setContent(cmdEncoder->_cmdBuffer,
-						  (VkBuffer) tempBuff,
-						  (VkImage) _srcImage,
-						  _srcLayout,
-						  (uint32_t)_srcTmpBuffImgCopies.size(),
-						  _srcTmpBuffImgCopies.data(),
-						  false);
-		cpyCmd.encode(cmdEncoder);
-
-		// Copy from buffer to destination image
-		// Create and execute a temporary buffer image command.
-		// To be threadsafe...do NOT acquire and return the command from the pool.
-		cpyCmd.setContent(cmdEncoder->_cmdBuffer,
-						  (VkBuffer) tempBuff,
-						  (VkImage) _dstImage,
-						  _dstLayout,
-						  (uint32_t)_dstTmpBuffImgCopies.size(),
-						  _dstTmpBuffImgCopies.data(),
-						  true);
-		cpyCmd.encode(cmdEncoder);
-	}
-}
+template class MVKCmdCopyImage<1>;
+template class MVKCmdCopyImage<4>;
 
 
 #pragma mark -
 #pragma mark MVKCmdBlitImage
 
-VkResult MVKCmdBlitImage::setContent(MVKCommandBuffer* cmdBuff,
-									 VkImage srcImage,
-									 VkImageLayout srcImageLayout,
-									 VkImage dstImage,
-									 VkImageLayout dstImageLayout,
-									 uint32_t regionCount,
-									 const VkImageBlit* pRegions,
-									 VkFilter filter,
-									 MVKCommandUse commandUse) {
-
-	VkResult rslt = MVKCmdCopyImage::setContent(cmdBuff, srcImage, srcImageLayout, dstImage, dstImageLayout, true, commandUse);
-
-	_blitKey.srcMTLPixelFormat = _srcImage->getMTLPixelFormat();
-	_blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
-	_blitKey.dstMTLPixelFormat = _dstImage->getMTLPixelFormat();
-	_blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(filter);
-	_blitKey.dstSampleCount = _dstSampleCount;
+template <size_t N>
+VkResult MVKCmdBlitImage<N>::setContent(MVKCommandBuffer* cmdBuff,
+										VkImage srcImage,
+										VkImageLayout srcImageLayout,
+										VkImage dstImage,
+										VkImageLayout dstImageLayout,
+										uint32_t regionCount,
+										const VkImageBlit* pRegions,
+										VkFilter filter) {
 
 	MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
 
-	_mvkImageBlitRenders.clear();		// Clear for reuse
-	for (uint32_t i = 0; i < regionCount; i++) {
-		addImageBlitRegion(pRegions[i], pixFmts);
+	_srcImage = (MVKImage*)srcImage;
+	_srcLayout = srcImageLayout;
+	_dstImage = (MVKImage*)dstImage;
+	_dstLayout = dstImageLayout;
+
+	_filter = filter;
+
+	_vkImageBlits.clear();		// Clear for reuse
+    for (uint32_t regionIdx = 0; regionIdx < regionCount; regionIdx++) {
+        auto& vkIR = pRegions[regionIdx];
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.srcSubresource.aspectMask);
+
+        // Validate - depth stencil formats cannot be scaled or inverted
+        MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat(srcPlaneIndex);
+        if (pixFmts->isDepthFormat(srcMTLPixFmt) || pixFmts->isStencilFormat(srcMTLPixFmt)) {
+            for (auto& vkIB : _vkImageBlits) {
+                if ( !(canCopyFormats(vkIB) && canCopy(vkIB)) ) {
+                    return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdBlitImage(): Scaling or inverting depth/stencil images is not supported.");
+                }
+            }
+        }
+
+		_vkImageBlits.push_back(vkIR);
 	}
 
-	// Validate
-	MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat();
-	if ( !_mvkImageBlitRenders.empty() &&
-		(pixFmts->isDepthFormat(srcMTLPixFmt) || pixFmts->isStencilFormat(srcMTLPixFmt)) ) {
-
-		_mvkImageBlitRenders.clear();
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdBlitImage(): Scaling or inverting depth/stencil images is not supported.");
-	}
-
-	return rslt;
+	return VK_SUCCESS;
 }
 
-void MVKCmdBlitImage::addImageBlitRegion(const VkImageBlit& region,
-										 MVKPixelFormats* pixFmts) {
-	if (_canCopyFormats && canCopy(region)) {
-		addImageCopyRegionFromBlitRegion(region, pixFmts);	// Convert to image copy
-	} else {
-		MVKImageBlitRender blitRender;
-		blitRender.region = region;
-		populateVertices(blitRender.vertices, region);
-		_mvkImageBlitRenders.push_back(blitRender);
-	}
+template <size_t N>
+bool MVKCmdBlitImage<N>::canCopyFormats(const VkImageBlit& region) {
+    uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.srcSubresource.aspectMask);
+    uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.dstSubresource.aspectMask);
+	return ((_srcImage->getMTLPixelFormat(srcPlaneIndex) == _dstImage->getMTLPixelFormat(dstPlaneIndex)) &&
+			(_dstImage->getSampleCount() == _srcImage->getSampleCount()));
 }
 
 // The source and destination sizes must be equal and not be negative in any direction
-bool MVKCmdBlitImage::canCopy(const VkImageBlit& region) {
+template <size_t N>
+bool MVKCmdBlitImage<N>::canCopy(const VkImageBlit& region) {
 	VkOffset3D srcSize = mvkVkOffset3DDifference(region.srcOffsets[1], region.srcOffsets[0]);
 	VkOffset3D dstSize = mvkVkOffset3DDifference(region.dstOffsets[1], region.dstOffsets[0]);
 	return (mvkVkOffset3DsAreEqual(srcSize, dstSize) &&
 			(srcSize.x >= 0) && (srcSize.y >= 0) && (srcSize.z >= 0));
 }
 
-void MVKCmdBlitImage::addImageCopyRegionFromBlitRegion(const VkImageBlit& region,
-													   MVKPixelFormats* pixFmts) {
-	const VkOffset3D& so0 = region.srcOffsets[0];
-	const VkOffset3D& so1 = region.srcOffsets[1];
-
-	VkImageCopy cpyRgn;
-	cpyRgn.srcSubresource = region.srcSubresource;
-	cpyRgn.srcOffset = region.srcOffsets[0];
-	cpyRgn.dstSubresource = region.dstSubresource;
-	cpyRgn.dstOffset = region.dstOffsets[0];
-	cpyRgn.extent.width = so1.x - so0.x;
-	cpyRgn.extent.height = so1.y - so0.y;
-	cpyRgn.extent.depth = so1.z - so0.z;
-
-	MVKCmdCopyImage::addImageCopyRegion(cpyRgn, pixFmts);
-}
-
-void MVKCmdBlitImage::populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region) {
+template <size_t N>
+void MVKCmdBlitImage<N>::populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region) {
     const VkOffset3D& so0 = region.srcOffsets[0];
     const VkOffset3D& so1 = region.srcOffsets[1];
     const VkOffset3D& do0 = region.dstOffsets[0];
     const VkOffset3D& do1 = region.dstOffsets[1];
 
     // Get the extents of the source and destination textures.
-    VkExtent3D srcExtent = _srcImage->getExtent3D(region.srcSubresource.mipLevel);
-    VkExtent3D dstExtent = _dstImage->getExtent3D(region.dstSubresource.mipLevel);
+    uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.srcSubresource.aspectMask);
+    uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(region.dstSubresource.aspectMask);
+    VkExtent3D srcExtent = _srcImage->getExtent3D(srcPlaneIndex, region.srcSubresource.mipLevel);
+    VkExtent3D dstExtent = _dstImage->getExtent3D(dstPlaneIndex, region.dstSubresource.mipLevel);
 
     // Determine the bottom-left and top-right corners of the source and destination
     // texture regions, each as a fraction of the corresponding texture size.
@@ -368,270 +321,267 @@
     pVtx->texCoord.y = (1.0 - srcTR.y);
 }
 
-void MVKCmdBlitImage::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdBlitImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse commandUse) {
+
+	size_t vkIBCnt = _vkImageBlits.size();
+	VkImageCopy vkImageCopies[vkIBCnt];
+	MVKImageBlitRender mvkBlitRenders[vkIBCnt];
+	uint32_t copyCnt = 0;
+	uint32_t blitCnt = 0;
+
+	// Separate BLITs into those that are really just simple texure region copies,
+	// and those that require rendering
+	for (auto& vkIB : _vkImageBlits) {
+		if (canCopyFormats(vkIB) && canCopy(vkIB)) {
+
+			const VkOffset3D& so0 = vkIB.srcOffsets[0];
+			const VkOffset3D& so1 = vkIB.srcOffsets[1];
+
+			auto& vkIC = vkImageCopies[copyCnt++];
+			vkIC.srcSubresource = vkIB.srcSubresource;
+			vkIC.srcOffset = vkIB.srcOffsets[0];
+			vkIC.dstSubresource = vkIB.dstSubresource;
+			vkIC.dstOffset = vkIB.dstOffsets[0];
+			vkIC.extent.width = so1.x - so0.x;
+			vkIC.extent.height = so1.y - so0.y;
+			vkIC.extent.depth = so1.z - so0.z;
+
+		} else {
+			auto& mvkIBR = mvkBlitRenders[blitCnt++];
+			mvkIBR.region = vkIB;
+			populateVertices(mvkIBR.vertices, vkIB);
+		}
+	}
 
 	// Perform those BLITs that can be covered by simple texture copying.
-	if ( !_imageCopyRegions.empty() ) {
-		MVKCmdCopyImage::encode(cmdEncoder);
+	if (copyCnt) {
+		MVKCmdCopyImage<N> copyCmd;
+		copyCmd.setContent(cmdEncoder->_cmdBuffer,
+						   (VkImage)_srcImage, _srcLayout,
+						   (VkImage)_dstImage, _dstLayout,
+						   copyCnt, vkImageCopies);
+		copyCmd.encode(cmdEncoder, kMVKCommandUseBlitImage);
 	}
 
 	// Perform those BLITs that require rendering to destination texture.
-	if ( !_mvkImageBlitRenders.empty() ) {
+    for (uint32_t blitIdx = 0; blitIdx < blitCnt; blitIdx++) {
+        auto& mvkIBR = mvkBlitRenders[blitIdx];
 
-		cmdEncoder->endCurrentMetalEncoding();
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(mvkIBR.region.srcSubresource.aspectMask);
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(mvkIBR.region.dstSubresource.aspectMask);
 
-		id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture();
-		id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
-		if ( !srcMTLTex || !dstMTLTex ) { return; }
+        id<MTLTexture> srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex);
+        id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex);
+        if (blitCnt && srcMTLTex && dstMTLTex) {
+            cmdEncoder->endCurrentMetalEncoding();
 
-		MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
-		mtlColorAttDesc.texture = dstMTLTex;
+            MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor];
+            MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPD.colorAttachments[0];
+            mtlColorAttDesc.loadAction = MTLLoadActionLoad;
+            mtlColorAttDesc.storeAction = MTLStoreActionStore;
+            mtlColorAttDesc.texture = dstMTLTex;
 
-		uint32_t vtxBuffIdx = cmdEncoder->getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
-		id<MTLRenderPipelineState> mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(_blitKey);
+            MVKRPSKeyBlitImg blitKey;
+            blitKey.srcMTLPixelFormat = _srcImage->getMTLPixelFormat(srcPlaneIndex);
+            blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
+            blitKey.dstMTLPixelFormat = _dstImage->getMTLPixelFormat(dstPlaneIndex);
+            blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter);
+            blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
+            id<MTLRenderPipelineState> mtlRPS = cmdEncoder->getCommandEncodingPool()->getCmdBlitImageMTLRenderPipelineState(blitKey);
 
-		for (auto& bltRend : _mvkImageBlitRenders) {
+            uint32_t vtxBuffIdx = cmdEncoder->getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
+            
+            mtlColorAttDesc.level = mvkIBR.region.dstSubresource.mipLevel;
 
-			mtlColorAttDesc.level = bltRend.region.dstSubresource.mipLevel;
+            uint32_t layCnt = mvkIBR.region.srcSubresource.layerCount;
+            for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
+                // Update the render pass descriptor for the texture level and slice, and create a render encoder.
+                mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+                id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
+                setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(commandUse));
 
-			uint32_t layCnt = bltRend.region.srcSubresource.layerCount;
-			for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
-				// Update the render pass descriptor for the texture level and slice, and create a render encoder.
-				mtlColorAttDesc.slice = bltRend.region.dstSubresource.baseArrayLayer + layIdx;
-				id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: _mtlRenderPassDescriptor];
-				setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(_commandUse));
+                [mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
+                [mtlRendEnc setRenderPipelineState: mtlRPS];
+                cmdEncoder->setVertexBytes(mtlRendEnc, mvkIBR.vertices, sizeof(mvkIBR.vertices), vtxBuffIdx);
+                [mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0];
 
-				[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
-				[mtlRendEnc setRenderPipelineState: mtlRPS];
-				cmdEncoder->setVertexBytes(mtlRendEnc, bltRend.vertices, sizeof(bltRend.vertices), vtxBuffIdx);
-				[mtlRendEnc setFragmentTexture: srcMTLTex atIndex: 0];
+                struct {
+                    uint slice;
+                    float lod;
+                } texSubRez;
+                texSubRez.slice = mvkIBR.region.srcSubresource.baseArrayLayer + layIdx;
+                texSubRez.lod = mvkIBR.region.srcSubresource.mipLevel;
+                cmdEncoder->setFragmentBytes(mtlRendEnc, &texSubRez, sizeof(texSubRez), 0);
 
-				struct {
-					uint slice;
-					float lod;
-				} texSubRez;
-				texSubRez.slice = bltRend.region.srcSubresource.baseArrayLayer + layIdx;
-				texSubRez.lod = bltRend.region.srcSubresource.mipLevel;
-				cmdEncoder->setFragmentBytes(mtlRendEnc, &texSubRez, sizeof(texSubRez), 0);
-
-				[mtlRendEnc drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: kMVKBlitVertexCount];
-				[mtlRendEnc popDebugGroup];
-				[mtlRendEnc endEncoding];
-			}
-		}
-	}
+                [mtlRendEnc drawPrimitives: MTLPrimitiveTypeTriangleStrip vertexStart: 0 vertexCount: kMVKBlitVertexCount];
+                [mtlRendEnc popDebugGroup];
+                [mtlRendEnc endEncoding];
+            }
+        }
+    }
 }
 
-
-#pragma mark Construction
-
-MVKCmdBlitImage::MVKCmdBlitImage() {
-    initMTLRenderPassDescriptor();
-}
-
-// Create and configure the render pass descriptor
-void MVKCmdBlitImage::initMTLRenderPassDescriptor() {
-    _mtlRenderPassDescriptor = [[MTLRenderPassDescriptor renderPassDescriptor] retain];		// retained
-    MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
-    mtlColorAttDesc.loadAction = MTLLoadActionLoad;
-    mtlColorAttDesc.storeAction = MTLStoreActionStore;
-}
-
-MVKCmdBlitImage::~MVKCmdBlitImage() {
-	[_mtlRenderPassDescriptor release];
-}
+template class MVKCmdBlitImage<1>;
+template class MVKCmdBlitImage<4>;
 
 
 #pragma mark -
 #pragma mark MVKCmdResolveImage
 
-VkResult MVKCmdResolveImage::setContent(MVKCommandBuffer* cmdBuff,
-										VkImage srcImage,
-										VkImageLayout srcImageLayout,
-										VkImage dstImage,
-										VkImageLayout dstImageLayout,
-										uint32_t regionCount,
-										const VkImageResolve* pRegions) {
+template <size_t N>
+VkResult MVKCmdResolveImage<N>::setContent(MVKCommandBuffer* cmdBuff,
+										   VkImage srcImage,
+										   VkImageLayout srcImageLayout,
+										   VkImage dstImage,
+										   VkImageLayout dstImageLayout,
+										   uint32_t regionCount,
+										   const VkImageResolve* pRegions) {
     _srcImage = (MVKImage*)srcImage;
     _srcLayout = srcImageLayout;
     _dstImage = (MVKImage*)dstImage;
     _dstLayout = dstImageLayout;
 
-    // Deterine the total number of texture layers being affected
-    uint32_t layerCnt = 0;
-    for (uint32_t i = 0; i < regionCount; i++) {
-        layerCnt += pRegions[i].dstSubresource.layerCount;
+	_vkImageResolves.clear();	// Clear for reuse
+	_vkImageResolves.reserve(regionCount);
+    for (uint32_t regionIdx = 0; regionIdx < regionCount; regionIdx++) {
+        auto& vkIR = pRegions[regionIdx];
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.dstSubresource.aspectMask);
+
+        // Validate
+        MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
+        if ( !mvkAreAllFlagsEnabled(pixFmts->getCapabilities(_dstImage->getMTLPixelFormat(dstPlaneIndex)), kMVKMTLFmtCapsResolve) ) {
+            return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", pixFmts->getName(_dstImage->getVkFormat()));
+        }
+
+		_vkImageResolves.push_back(vkIR);
     }
 
-    // Resize the region arrays accordingly
-    _expansionRegions.clear();              // Clear for reuse
-    _expansionRegions.reserve(regionCount);
-    _copyRegions.clear();                   // Clear for reuse
-    _copyRegions.reserve(regionCount);
-    _mtlResolveSlices.clear();              // Clear for reuse
-    _mtlResolveSlices.reserve(layerCnt);
-
-    // Add image regions
-    for (uint32_t i = 0; i < regionCount; i++) {
-        const VkImageResolve& rslvRgn = pRegions[i];
-        addExpansionRegion(rslvRgn);
-        addCopyRegion(rslvRgn);
-        addResolveSlices(rslvRgn);
-    }
-
-    _dstImage->getTransferDescriptorData(_transferImageData);
-	_transferImageData.samples = _srcImage->getSampleCount();
-
-	// Validate
-	if ( !mvkAreAllFlagsEnabled(cmdBuff->getPixelFormats()->getCapabilities(_dstImage->getMTLPixelFormat()), kMVKMTLFmtCapsResolve) ) {
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdResolveImage(): %s cannot be used as a resolve destination on this device.", cmdBuff->getPixelFormats()->getName(_dstImage->getVkFormat()));
-	}
-
 	return VK_SUCCESS;
 }
 
-/**
- * Adds a VkImageBlit region, constructed from the resolve region, to the internal collection
- * of expansion regions, unless the entire content of the destination texture of this command 
- * is to be resolved, an expansion region will not be added.
- *
- * The purpose of an expansion regions is to render the existing content of the destination
- * image of this command to the temporary transfer multisample image, so that regions of that 
- * temporary transfer image can then be overwritten with content from the source image of this
- * command, prior to resolving it back to the destination image of this command.
- *
- * As such, the source of this expansion stage is the destination image of this command,
- * and the destination of this expansion stage is a temp image that has the same shape
- * as the source image of this command.
- */
-void MVKCmdResolveImage::addExpansionRegion(const VkImageResolve& resolveRegion) {
-    uint32_t mipLvl = resolveRegion.dstSubresource.mipLevel;
-    VkExtent3D srcImgExt = _srcImage->getExtent3D(mipLvl);
-    VkExtent3D dstImgExt = _dstImage->getExtent3D(mipLvl);
+template <size_t N>
+void MVKCmdResolveImage<N>::encode(MVKCommandEncoder* cmdEncoder) {
 
-    // No need to add an expansion region if the entire content of
-    // the source image is being resolved to the destination image.
-    if (mvkVkExtent3DsAreEqual(srcImgExt, resolveRegion.extent)) { return; }
+	size_t vkIRCnt = _vkImageResolves.size();
+	VkImageBlit expansionRegions[vkIRCnt];
+	VkImageCopy copyRegions[vkIRCnt];
 
-    // The source of this temporary content move is the full extent of the DESTINATION
-    // image of the resolve command, and the destination of this temporary content move
-    // is the full extent of the SOURCE image of the resolve command.
-    VkImageBlit expRgn = {
-        .srcSubresource = resolveRegion.dstSubresource,
-        .srcOffsets[0] = { 0, 0, 0 },
-        .srcOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) },
-        .dstSubresource = resolveRegion.dstSubresource,
-        .dstOffsets[0] = { 0, 0, 0 },
-        .dstOffsets[1] = { int32_t(srcImgExt.width), int32_t(srcImgExt.height), int32_t(srcImgExt.depth) },
-    };
-    _expansionRegions.push_back(expRgn);
-}
+	uint32_t layerCnt = 0;
+	for (VkImageResolve& vkIR : _vkImageResolves) { layerCnt += vkIR.dstSubresource.layerCount; }
+	MVKMetalResolveSlice mtlResolveSlices[layerCnt];
 
-/**
- * Adds a VkImageCopy region, constructed from the resolve region,
- * to the internal collection of copy regions.
- *
- * The purpose of a copy region is to copy regions from the source image of this command to
- * the temporary image, prior to the temporary image being resolved back to the destination
- * image of this command.
- *
- * As such, the source of this copy stage is the source image of this command, and the
- * destination of this copy stage is the temporary transfer image that has the same shape 
- * as the source image of this command.
- */
-void MVKCmdResolveImage::addCopyRegion(const VkImageResolve& resolveRegion) {
-    VkImageCopy cpyRgn = {
-        .srcSubresource = resolveRegion.srcSubresource,
-        .srcOffset = resolveRegion.srcOffset,
-        .dstSubresource = resolveRegion.srcSubresource,
-        .dstOffset = resolveRegion.srcOffset,
-        .extent = resolveRegion.extent,
-    };
-    _copyRegions.push_back(cpyRgn);
-}
+	uint32_t expCnt = 0;
+	uint32_t copyCnt = 0;
+	uint32_t sliceCnt = 0;
 
-/** Adds a resolve slice struct for each destination layer in the resolve region. */
-void MVKCmdResolveImage::addResolveSlices(const VkImageResolve& resolveRegion) {
-    MVKMetalResolveSlice rslvSlice;
-    rslvSlice.level = resolveRegion.dstSubresource.mipLevel;
+	for (VkImageResolve& vkIR : _vkImageResolves) {
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.srcSubresource.aspectMask);
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.dstSubresource.aspectMask);
 
-    uint32_t baseLayer = resolveRegion.dstSubresource.baseArrayLayer;
-    uint32_t layCnt = resolveRegion.dstSubresource.layerCount;
-    for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
-        rslvSlice.slice = baseLayer + layIdx;
-        _mtlResolveSlices.push_back(rslvSlice);
-    }
-}
+		uint32_t mipLvl = vkIR.dstSubresource.mipLevel;
+		VkExtent3D srcImgExt = _srcImage->getExtent3D(srcPlaneIndex, mipLvl);
+		VkExtent3D dstImgExt = _dstImage->getExtent3D(dstPlaneIndex, mipLvl);
 
-void MVKCmdResolveImage::encode(MVKCommandEncoder* cmdEncoder) {
-    MVKImage* xfrImage = cmdEncoder->getCommandEncodingPool()->getTransferMVKImage(_transferImageData);
+		// If the region does not cover the entire content of the source level, expand the
+		// destination content in the region to the temporary image. The purpose of this
+		// expansion is to render the existing content of the destination image to the
+		// temporary transfer multisample image, so that regions of that temporary transfer
+		// image can then be overwritten with content from the source image, prior to
+		// resolving it back to the destination image. The source of this temporary content
+		// move is the full extent of the DESTINATION image of the resolve command, and the
+		// destination of this temporary content move is the full extent of the SOURCE image.
+		if ( !mvkVkExtent3DsAreEqual(srcImgExt, vkIR.extent) ) {
+			VkImageBlit& expRgn = expansionRegions[expCnt++];
+			expRgn.srcSubresource = vkIR.dstSubresource;
+			expRgn.srcOffsets[0] = { 0, 0, 0 };
+			expRgn.srcOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) };
+			expRgn.dstSubresource = vkIR.dstSubresource;
+			expRgn.dstOffsets[0] = { 0, 0, 0 };
+			expRgn.dstOffsets[1] = { int32_t(srcImgExt.width), int32_t(srcImgExt.height), int32_t(srcImgExt.depth) };
+		}
 
-    id<MTLTexture> xfrMTLTex = xfrImage->getMTLTexture();
-    id<MTLTexture> dstMTLTex = _dstImage->getMTLTexture();
-    if ( !xfrMTLTex || !dstMTLTex ) { return; }
+		// Copy the region from the source image to the temporary multisample image,
+		// prior to the temporary image being resolved back to the destination image.
+		// The source of this copy stage is the source image, and the destination of
+		// this copy stage is the temporary transfer image.
+		VkImageCopy& cpyRgn = copyRegions[copyCnt++];
+		cpyRgn.srcSubresource = vkIR.srcSubresource;
+		cpyRgn.srcOffset = vkIR.srcOffset;
+		cpyRgn.dstSubresource = vkIR.srcSubresource;
+		cpyRgn.dstOffset = vkIR.srcOffset;
+		cpyRgn.extent = vkIR.extent;
 
-    // Expand the current content of the destination image to the temporary transfer image.
-    // Create and execute a temporary BLIT image command.
-    // To be threadsafe...do NOT acquire and return the command from the pool.
-    uint32_t expRgnCnt = uint32_t(_expansionRegions.size());
-    if (expRgnCnt > 0) {
-        MVKCmdBlitImage expandCmd;
-        expandCmd.setContent(cmdEncoder->_cmdBuffer,
-							 (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
-                             expRgnCnt, _expansionRegions.data(),
-                             VK_FILTER_LINEAR, kMVKCommandUseResolveExpandImage);
-        expandCmd.encode(cmdEncoder);
-    }
+		// Adds a resolve slice struct for each destination layer in the resolve region.
+		uint32_t baseLayer = vkIR.dstSubresource.baseArrayLayer;
+		uint32_t layCnt = vkIR.dstSubresource.layerCount;
+		for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
+			MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sliceCnt++];
+            rslvSlice.copyRegion = &cpyRgn;
+			rslvSlice.level = vkIR.dstSubresource.mipLevel;
+			rslvSlice.slice = baseLayer + layIdx;
+		}
+	}
 
-    // Copy the resolve regions of the source image to the temporary transfer image.
-    // Create and execute a temporary copy image command.
-    // To be threadsafe...do NOT acquire and return the command from the pool.
-    uint32_t cpyRgnCnt = uint32_t(_copyRegions.size());
-    if (cpyRgnCnt > 0) {
-        MVKCmdCopyImage copyCmd;
-        copyCmd.setContent(cmdEncoder->_cmdBuffer,
-						   (VkImage)_srcImage, _srcLayout, (VkImage)xfrImage, _dstLayout,
-                           cpyRgnCnt, _copyRegions.data(), kMVKCommandUseResolveCopyImage);
-        copyCmd.encode(cmdEncoder);
-    }
+    // Expansion and copying is not required. Each mip level of the source image
+    // is being resolved entirely. Resolve directly from the source image.
+    MVKImage* xfrImage = _srcImage;
+	if (expCnt) {
+		// Expansion and copying is required. Acquire a temporary transfer image, expand
+		// the destination image into it, copy from the source image to the temporary image,
+		// and then resolve from the temporary image to the destination image.
+		MVKImageDescriptorData xferImageData;
+		_dstImage->getTransferDescriptorData(xferImageData);
+		xferImageData.samples = _srcImage->getSampleCount();
+		xfrImage = cmdEncoder->getCommandEncodingPool()->getTransferMVKImage(xferImageData);
 
-    cmdEncoder->endCurrentMetalEncoding();
+		// Expand the current content of the destination image to the temporary transfer image.
+		MVKCmdBlitImage<N> expCmd;
+		expCmd.setContent(cmdEncoder->_cmdBuffer,
+						  (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
+						  expCnt, expansionRegions, VK_FILTER_LINEAR);
+		expCmd.encode(cmdEncoder, kMVKCommandUseResolveExpandImage);
 
-    MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
-    mtlColorAttDesc.texture = xfrMTLTex;
-    mtlColorAttDesc.resolveTexture = dstMTLTex;
+		// Copy the resolve regions of the source image to the temporary transfer image.
+		MVKCmdCopyImage<N> copyCmd;
+		copyCmd.setContent(cmdEncoder->_cmdBuffer,
+						   (VkImage)_srcImage, _srcLayout,
+						   (VkImage)xfrImage, _dstLayout,
+						   copyCnt, copyRegions);
+		copyCmd.encode(cmdEncoder, kMVKCommandUseResolveCopyImage);
+	}
 
-    for (auto& rslvSlice : _mtlResolveSlices) {
+	cmdEncoder->endCurrentMetalEncoding();
 
-        // Update the render pass descriptor for the texture level and slice, and create a render encoder.
-        mtlColorAttDesc.level = rslvSlice.level;
-        mtlColorAttDesc.slice = rslvSlice.slice;
-        mtlColorAttDesc.resolveLevel = rslvSlice.level;
-        mtlColorAttDesc.resolveSlice = rslvSlice.slice;
-        id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: _mtlRenderPassDescriptor];
-		setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(kMVKCommandUseResolveImage));
-
-        [mtlRendEnc pushDebugGroup: @"vkCmdResolveImage"];
-        [mtlRendEnc popDebugGroup];
-        [mtlRendEnc endEncoding];
-    }
-}
-
-MVKCmdResolveImage::MVKCmdResolveImage() {
-    initMTLRenderPassDescriptor();
-}
-
-// Create and configure the render pass descriptor
-void MVKCmdResolveImage::initMTLRenderPassDescriptor() {
-    _mtlRenderPassDescriptor = [[MTLRenderPassDescriptor renderPassDescriptor] retain];		// retained
-    MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = _mtlRenderPassDescriptor.colorAttachments[0];
+	MTLRenderPassDescriptor* mtlRPD = [MTLRenderPassDescriptor renderPassDescriptor];
+    MTLRenderPassColorAttachmentDescriptor* mtlColorAttDesc = mtlRPD.colorAttachments[0];
     mtlColorAttDesc.loadAction = MTLLoadActionLoad;
     mtlColorAttDesc.storeAction = MTLStoreActionMultisampleResolve;
+
+	// For each resolve slice, update the render pass descriptor for
+	// the texture level and slice and create a render encoder.
+	for (uint32_t sIdx = 0; sIdx < sliceCnt; sIdx++) {
+		MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sIdx];
+        uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->srcSubresource.aspectMask);
+        uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->dstSubresource.aspectMask);
+
+        mtlColorAttDesc.texture = xfrImage->getMTLTexture(srcPlaneIndex);
+        mtlColorAttDesc.resolveTexture = _dstImage->getMTLTexture(dstPlaneIndex);
+		mtlColorAttDesc.level = rslvSlice.level;
+		mtlColorAttDesc.slice = rslvSlice.slice;
+		mtlColorAttDesc.resolveLevel = rslvSlice.level;
+		mtlColorAttDesc.resolveSlice = rslvSlice.slice;
+		id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
+		setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(kMVKCommandUseResolveImage));
+
+		[mtlRendEnc pushDebugGroup: @"vkCmdResolveImage"];
+		[mtlRendEnc popDebugGroup];
+		[mtlRendEnc endEncoding];
+	}
 }
 
-MVKCmdResolveImage::~MVKCmdResolveImage() {
-    [_mtlRenderPassDescriptor release];
-}
+template class MVKCmdResolveImage<1>;
+template class MVKCmdResolveImage<4>;
 
 
 #pragma mark -
@@ -644,25 +594,27 @@
 	uint32_t size;
 } MVKCmdCopyBufferInfo;
 
-VkResult MVKCmdCopyBuffer::setContent(MVKCommandBuffer* cmdBuff,
-									  VkBuffer srcBuffer,
-									  VkBuffer destBuffer,
-									  uint32_t regionCount,
-									  const VkBufferCopy* pRegions) {
+template <size_t N>
+VkResult MVKCmdCopyBuffer<N>::setContent(MVKCommandBuffer* cmdBuff,
+										 VkBuffer srcBuffer,
+										 VkBuffer destBuffer,
+										 uint32_t regionCount,
+										 const VkBufferCopy* pRegions) {
 	_srcBuffer = (MVKBuffer*)srcBuffer;
 	_dstBuffer = (MVKBuffer*)destBuffer;
 
 	// Add buffer regions
-	_mtlBuffCopyRegions.clear();	// Clear for reuse
-	_mtlBuffCopyRegions.reserve(regionCount);
+	_bufferCopyRegions.clear();	// Clear for reuse
+	_bufferCopyRegions.reserve(regionCount);
 	for (uint32_t i = 0; i < regionCount; i++) {
-		_mtlBuffCopyRegions.push_back(pRegions[i]);
+		_bufferCopyRegions.push_back(pRegions[i]);
 	}
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdCopyBuffer::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdCopyBuffer<N>::encode(MVKCommandEncoder* cmdEncoder) {
 	id<MTLBuffer> srcMTLBuff = _srcBuffer->getMTLBuffer();
 	NSUInteger srcMTLBuffOffset = _srcBuffer->getMTLBufferOffset();
 
@@ -671,7 +623,7 @@
 
 	VkDeviceSize buffAlign = cmdEncoder->getDevice()->_pMetalFeatures->mtlCopyBufferAlignment;
 
-	for (auto& cpyRgn : _mtlBuffCopyRegions) {
+	for (auto& cpyRgn : _bufferCopyRegions) {
 		const bool useComputeCopy = buffAlign > 1 && (cpyRgn.srcOffset % buffAlign != 0 ||
 													  cpyRgn.dstOffset % buffAlign != 0 ||
 													  cpyRgn.size      % buffAlign != 0);
@@ -703,6 +655,9 @@
 	}
 }
 
+template class MVKCmdCopyBuffer<1>;
+template class MVKCmdCopyBuffer<4>;
+
 
 #pragma mark -
 #pragma mark MVKCmdBufferImageCopy
@@ -722,13 +677,14 @@
     VkExtent3D extent;
 } MVKCmdCopyBufferToImageInfo;
 
-VkResult MVKCmdBufferImageCopy::setContent(MVKCommandBuffer* cmdBuff,
-										   VkBuffer buffer,
-										   VkImage image,
-										   VkImageLayout imageLayout,
-										   uint32_t regionCount,
-										   const VkBufferImageCopy* pRegions,
-										   bool toImage) {
+template <size_t N>
+VkResult MVKCmdBufferImageCopy<N>::setContent(MVKCommandBuffer* cmdBuff,
+											  VkBuffer buffer,
+											  VkImage image,
+											  VkImageLayout imageLayout,
+											  uint32_t regionCount,
+											  const VkBufferImageCopy* pRegions,
+											  bool toImage) {
     _buffer = (MVKBuffer*)buffer;
     _image = (MVKImage*)image;
     _imageLayout = imageLayout;
@@ -739,34 +695,38 @@
     _bufferImageCopyRegions.reserve(regionCount);
     for (uint32_t i = 0; i < regionCount; i++) {
         _bufferImageCopyRegions.push_back(pRegions[i]);
-    }
-
-    // Validate
-    if ( !_image->hasExpectedTexelSize() ) {
-        const char* cmdName = _toImage ? "vkCmdCopyBufferToImage" : "vkCmdCopyImageToBuffer";
-        return reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "%s(): The image is using Metal format %s as a substitute for Vulkan format %s. Since the pixel size is different, content for the image cannot be copied to or from a buffer.", cmdName, cmdBuff->getPixelFormats()->getName(_image->getMTLPixelFormat()), cmdBuff->getPixelFormats()->getName(_image->getVkFormat()));
+        
+        // Validate
+        if ( !_image->hasExpectedTexelSize() ) {
+            MTLPixelFormat mtlPixFmt = _image->getMTLPixelFormat(MVKImage::getPlaneFromVkImageAspectFlags(pRegions[i].imageSubresource.aspectMask));
+            const char* cmdName = _toImage ? "vkCmdCopyBufferToImage" : "vkCmdCopyImageToBuffer";
+            return reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "%s(): The image is using Metal format %s as a substitute for Vulkan format %s. Since the pixel size is different, content for the image cannot be copied to or from a buffer.", cmdName, cmdBuff->getPixelFormats()->getName(mtlPixFmt), cmdBuff->getPixelFormats()->getName(_image->getVkFormat()));
+        }
     }
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdBufferImageCopy::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdBufferImageCopy<N>::encode(MVKCommandEncoder* cmdEncoder) {
     id<MTLBuffer> mtlBuffer = _buffer->getMTLBuffer();
-    id<MTLTexture> mtlTexture = _image->getMTLTexture();
-    if ( !mtlBuffer || !mtlTexture ) { return; }
+    if ( !mtlBuffer ) { return; }
 
 	NSUInteger mtlBuffOffsetBase = _buffer->getMTLBufferOffset();
-    MTLPixelFormat mtlPixFmt = _image->getMTLPixelFormat();
     MVKCommandUse cmdUse = _toImage ? kMVKCommandUseCopyBufferToImage : kMVKCommandUseCopyImageToBuffer;
 	MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
 
     for (auto& cpyRgn : _bufferImageCopyRegions) {
+        uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(cpyRgn.imageSubresource.aspectMask);
+        MTLPixelFormat mtlPixFmt = _image->getMTLPixelFormat(planeIndex);
+        id<MTLTexture> mtlTexture = _image->getMTLTexture(planeIndex);
+        if ( !mtlTexture ) { continue; }
 
 		uint32_t mipLevel = cpyRgn.imageSubresource.mipLevel;
         MTLOrigin mtlTxtOrigin = mvkMTLOriginFromVkOffset3D(cpyRgn.imageOffset);
 		MTLSize mtlTxtSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(cpyRgn.imageExtent),
 											 mtlTxtOrigin,
-											 mvkMTLSizeFromVkExtent3D(_image->getExtent3D(mipLevel)));
+											 mvkMTLSizeFromVkExtent3D(_image->getExtent3D(planeIndex, mipLevel)));
 		NSUInteger mtlBuffOffset = mtlBuffOffsetBase + cpyRgn.bufferOffset;
 
         uint32_t buffImgWd = cpyRgn.bufferRowLength;
@@ -913,7 +873,8 @@
     }
 }
 
-bool MVKCmdBufferImageCopy::isArrayTexture() {
+template <size_t N>
+bool MVKCmdBufferImageCopy<N>::isArrayTexture() {
 	MTLTextureType mtlTexType = _image->getMTLTextureType();
 	return (mtlTexType == MTLTextureType3D ||
 			mtlTexType == MTLTextureType2DArray ||
@@ -923,20 +884,26 @@
 			mtlTexType == MTLTextureType1DArray);
 }
 
+template class MVKCmdBufferImageCopy<1>;
+template class MVKCmdBufferImageCopy<4>;	// To support MVKCmdCopyImage
+template class MVKCmdBufferImageCopy<8>;
+template class MVKCmdBufferImageCopy<16>;
+
 
 #pragma mark -
 #pragma mark MVKCmdClearAttachments
 
-VkResult MVKCmdClearAttachments::setContent(MVKCommandBuffer* cmdBuff,
-											uint32_t attachmentCount,
-											const VkClearAttachment* pAttachments,
-											uint32_t rectCount,
-											const VkClearRect* pRects) {
+template <size_t N>
+VkResult MVKCmdClearAttachments<N>::setContent(MVKCommandBuffer* cmdBuff,
+											   uint32_t attachmentCount,
+											   const VkClearAttachment* pAttachments,
+											   uint32_t rectCount,
+											   const VkClearRect* pRects) {
 	_rpsKey.reset();
+	_mtlDepthVal = 0.0;
     _mtlStencilValue = 0;
     _isClearingDepth = false;
     _isClearingStencil = false;
-    float mtlDepthVal = 0.0;
 	MVKPixelFormats* pixFmts = cmdBuff->getPixelFormats();
 
     // For each attachment to be cleared, mark it so in the render pipeline state
@@ -949,14 +916,14 @@
             uint32_t caIdx = clrAtt.colorAttachment;        // Might be VK_ATTACHMENT_UNUSED
             if (caIdx != VK_ATTACHMENT_UNUSED) {
                 _rpsKey.enableAttachment(caIdx);
-                _vkClearValues[caIdx] = clrAtt.clearValue;
+                setClearValue(caIdx, clrAtt.clearValue);
             }
         }
 
         if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT)) {
             _isClearingDepth = true;
             _rpsKey.enableAttachment(kMVKClearAttachmentDepthStencilIndex);
-            mtlDepthVal = pixFmts->getMTLClearDepthValue(clrAtt.clearValue);
+            _mtlDepthVal = pixFmts->getMTLClearDepthValue(clrAtt.clearValue);
         }
 
         if (mvkIsAnyFlagEnabled(clrAtt.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT)) {
@@ -966,30 +933,33 @@
         }
     }
 
-    // The depth value (including vertex position Z value) is held in the last index.
-    _clearColors[kMVKClearAttachmentDepthStencilIndex] = { mtlDepthVal, mtlDepthVal, mtlDepthVal, mtlDepthVal };
-
     _clearRects.clear();		// Clear for reuse
     _clearRects.reserve(rectCount);
     for (uint32_t i = 0; i < rectCount; i++) {
         _clearRects.push_back(pRects[i]);
     }
 
-	_vertices.clear();			// Clear for reuse
-    _vertices.reserve(rectCount * 6);
-
 	return VK_SUCCESS;
 }
 
 // Populates the vertices for all clear rectangles within an attachment of the specified size.
-void MVKCmdClearAttachments::populateVertices(float attWidth, float attHeight) {
-    for (auto& rect : _clearRects) { populateVertices(rect, attWidth, attHeight); }
+template <size_t N>
+void MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices, float attWidth, float attHeight) {
+	uint32_t vtxIdx = 0;
+    for (auto& rect : _clearRects) {
+		vtxIdx = populateVertices(vertices, vtxIdx, rect, attWidth, attHeight);
+	}
 }
 
-// Populates the vertices from the specified rectangle within an attachment of the specified size.
-void MVKCmdClearAttachments::populateVertices(VkClearRect& clearRect, float attWidth, float attHeight) {
-
-    // Determine the positions of the four edges of the
+// Populates the vertices, starting at the vertex, from the specified rectangle within
+// an attachment of the specified size. Returns the next vertex that needs to be populated.
+template <size_t N>
+uint32_t MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices,
+													 uint32_t startVertex,
+													 VkClearRect& clearRect,
+													 float attWidth,
+													 float attHeight) {
+	// Determine the positions of the four edges of the
     // clear rectangle as a fraction of the attachment size.
     float leftPos = (float)(clearRect.rect.offset.x) / attWidth;
     float rightPos = (float)(clearRect.rect.extent.width) / attWidth + leftPos;
@@ -1005,6 +975,7 @@
 
     simd::float4 vtx;
 
+	uint32_t vtxIdx = startVertex;
 	uint32_t startLayer = clearRect.baseArrayLayer;
 	uint32_t endLayer = startLayer + clearRect.layerCount;
 	for (uint32_t layer = startLayer; layer < endLayer; layer++) {
@@ -1015,40 +986,47 @@
 		// Top left vertex	- First triangle
 		vtx.y = topPos;
 		vtx.x = leftPos;
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 
 		// Bottom left vertex
 		vtx.y = bottomPos;
 		vtx.x = leftPos;
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 
 		// Bottom right vertex
 		vtx.y = bottomPos;
 		vtx.x = rightPos;
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 
 		// Bottom right vertex	- Second triangle
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 
 		// Top right vertex
 		vtx.y = topPos;
 		vtx.x = rightPos;
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 
 		// Top left vertex
 		vtx.y = topPos;
 		vtx.x = leftPos;
-		_vertices.push_back(vtx);
+		vertices[vtxIdx++] = vtx;
 	}
+
+	return vtxIdx;
 }
 
-void MVKCmdClearAttachments::encode(MVKCommandEncoder* cmdEncoder) {
+template <size_t N>
+void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
+
+	uint32_t vtxCnt = (uint32_t)_clearRects.size() * 6;
+	simd::float4 vertices[vtxCnt];
+	simd::float4 clearColors[kMVKClearAttachmentCount];
+
+	VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D();
+	populateVertices(vertices, fbExtent.width, fbExtent.height);
 
 	MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
     MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
-    VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D();
-    populateVertices(fbExtent.width, fbExtent.height);
-    uint32_t vtxCnt = (uint32_t)_vertices.size();
     uint32_t vtxBuffIdx = cmdEncoder->getDevice()->getMetalBufferIndexForVertexAttributeBinding(kMVKVertexContentBufferIndex);
 
     // Populate the render pipeline state attachment key with info from the subpass and framebuffer.
@@ -1059,10 +1037,13 @@
     for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
         VkFormat vkAttFmt = subpass->getColorAttachmentFormat(caIdx);
 		_rpsKey.attachmentMTLPixelFormats[caIdx] = pixFmts->getMTLPixelFormat(vkAttFmt);
-		MTLClearColor mtlCC = pixFmts->getMTLClearColor(_vkClearValues[caIdx], vkAttFmt);
-		_clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha};
+		MTLClearColor mtlCC = pixFmts->getMTLClearColor(getClearValue(caIdx), vkAttFmt);
+		clearColors[caIdx] = { (float)mtlCC.red, (float)mtlCC.green, (float)mtlCC.blue, (float)mtlCC.alpha};
     }
 
+    // The depth value (including vertex position Z value) is held in the last index.
+    clearColors[kMVKClearAttachmentDepthStencilIndex] = { _mtlDepthVal, _mtlDepthVal, _mtlDepthVal, _mtlDepthVal };
+
     VkFormat vkAttFmt = subpass->getDepthStencilFormat();
 	MTLPixelFormat mtlAttFmt = pixFmts->getMTLPixelFormat(vkAttFmt);
     _rpsKey.attachmentMTLPixelFormats[kMVKClearAttachmentDepthStencilIndex] = mtlAttFmt;
@@ -1078,9 +1059,9 @@
     [mtlRendEnc setDepthStencilState: cmdEncPool->getMTLDepthStencilState(isClearingDepth, isClearingStencil)];
     [mtlRendEnc setStencilReferenceValue: _mtlStencilValue];
 
-    cmdEncoder->setVertexBytes(mtlRendEnc, _clearColors, sizeof(_clearColors), 0);
-    cmdEncoder->setFragmentBytes(mtlRendEnc, _clearColors, sizeof(_clearColors), 0);
-    cmdEncoder->setVertexBytes(mtlRendEnc, _vertices.data(), vtxCnt * sizeof(_vertices[0]), vtxBuffIdx);
+    cmdEncoder->setVertexBytes(mtlRendEnc, clearColors, sizeof(clearColors), 0);
+    cmdEncoder->setFragmentBytes(mtlRendEnc, clearColors, sizeof(clearColors), 0);
+    cmdEncoder->setVertexBytes(mtlRendEnc, vertices, vtxCnt * sizeof(vertices[0]), vtxBuffIdx);
     [mtlRendEnc drawPrimitives: MTLPrimitiveTypeTriangle vertexStart: 0 vertexCount: vtxCnt];
     [mtlRendEnc popDebugGroup];
 
@@ -1091,47 +1072,59 @@
 	cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
 }
 
+template class MVKCmdClearAttachments<1>;
+template class MVKCmdClearAttachments<4>;
+
+template class MVKCmdClearSingleAttachment<1>;
+template class MVKCmdClearSingleAttachment<4>;
+
+template class MVKCmdClearMultiAttachments<1>;
+template class MVKCmdClearMultiAttachments<4>;
+
 
 #pragma mark -
 #pragma mark MVKCmdClearImage
 
-VkResult MVKCmdClearImage::setContent(MVKCommandBuffer* cmdBuff,
-									  VkImage image,
-									  VkImageLayout imageLayout,
-									  const VkClearValue& clearValue,
-									  uint32_t rangeCount,
-									  const VkImageSubresourceRange* pRanges,
-									  bool isDepthStencilClear) {
+template <size_t N>
+VkResult MVKCmdClearImage<N>::setContent(MVKCommandBuffer* cmdBuff,
+										 VkImage image,
+										 VkImageLayout imageLayout,
+										 const VkClearValue& clearValue,
+										 uint32_t rangeCount,
+										 const VkImageSubresourceRange* pRanges) {
     _image = (MVKImage*)image;
-    _imgLayout = imageLayout;
 	_clearValue = clearValue;
-    _isDepthStencilClear = isDepthStencilClear;
 
     // Add subresource ranges
     _subresourceRanges.clear();		// Clear for reuse
     _subresourceRanges.reserve(rangeCount);
-    for (uint32_t i = 0; i < rangeCount; i++) {
-        _subresourceRanges.push_back(pRanges[i]);
-    }
+    bool isDS = isDepthStencilClear();
+    for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; rangeIdx++) {
+        auto& vkIR = pRanges[rangeIdx];
+        uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.aspectMask);
 
-	// Validate
-	if (_image->getImageType() == VK_IMAGE_TYPE_1D) {
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClearImage(): Native 1D images cannot be cleared on this device. Consider enabling MVK_CONFIG_TEXTURE_1D_AS_2D.");
-	}
-	MVKMTLFmtCaps mtlFmtCaps = cmdBuff->getPixelFormats()->getCapabilities(_image->getMTLPixelFormat());
-	if ((_isDepthStencilClear && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsDSAtt)) ||
-		( !_isDepthStencilClear && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsColorAtt))) {
-		return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClearImage(): Format %s cannot be cleared on this device.", cmdBuff->getPixelFormats()->getName(_image->getVkFormat()));
-	}
+        // Validate
+        MVKMTLFmtCaps mtlFmtCaps = cmdBuff->getPixelFormats()->getCapabilities(_image->getMTLPixelFormat(planeIndex));
+        if ((isDS && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsDSAtt)) ||
+            ( !isDS && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsColorAtt))) {
+            return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClear%sImage(): Format %s cannot be cleared on this device.", (isDS ? "DepthStencil" : "Color"), cmdBuff->getPixelFormats()->getName(_image->getVkFormat()));
+        }
+        
+        _subresourceRanges.push_back(vkIR);
+    }
+    
+    // Validate
+    if (_image->getImageType() == VK_IMAGE_TYPE_1D) {
+        return reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClear%sImage(): Native 1D images cannot be cleared on this device. Consider enabling MVK_CONFIG_TEXTURE_1D_AS_2D.", (isDS ? "DepthStencil" : "Color"));
+    }
 
 	return VK_SUCCESS;
 }
 
-void MVKCmdClearImage::encode(MVKCommandEncoder* cmdEncoder) {
-	id<MTLTexture> imgMTLTex = _image->getMTLTexture();
-    if ( !imgMTLTex ) { return; }
-
-	NSString* mtlRendEncName = (_isDepthStencilClear
+template <size_t N>
+void MVKCmdClearImage<N>::encode(MVKCommandEncoder* cmdEncoder) {
+	bool isDS = isDepthStencilClear();
+	NSString* mtlRendEncName = (isDS
 								? mvkMTLRenderCommandEncoderLabel(kMVKCommandUseClearDepthStencilImage)
 								: mvkMTLRenderCommandEncoderLabel(kMVKCommandUseClearColorImage));
 
@@ -1139,15 +1132,17 @@
 
 	MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
 	for (auto& srRange : _subresourceRanges) {
+        id<MTLTexture> imgMTLTex = _image->getMTLTexture(MVKImage::getPlaneFromVkImageAspectFlags(srRange.aspectMask));
+        if ( !imgMTLTex ) { continue; }
 
 		MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
 		MTLRenderPassColorAttachmentDescriptor* mtlRPCADesc = nil;
 		MTLRenderPassDepthAttachmentDescriptor* mtlRPDADesc = nil;
 		MTLRenderPassStencilAttachmentDescriptor* mtlRPSADesc = nil;
 
-		bool isClearingColor = !_isDepthStencilClear && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
-        bool isClearingDepth = _isDepthStencilClear && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
-        bool isClearingStencil = _isDepthStencilClear && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
+		bool isClearingColor = !isDS && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
+		bool isClearingDepth = isDS && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
+		bool isClearingStencil = isDS && mvkIsAnyFlagEnabled(srRange.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
 
 		if (isClearingColor) {
 			mtlRPCADesc = mtlRPDesc.colorAttachments[0];
@@ -1206,6 +1201,15 @@
     }
 }
 
+template class MVKCmdClearImage<1>;
+template class MVKCmdClearImage<4>;
+
+template class MVKCmdClearColorImage<1>;
+template class MVKCmdClearColorImage<4>;
+
+template class MVKCmdClearDepthStencilImage<1>;
+template class MVKCmdClearDepthStencilImage<4>;
+
 
 #pragma mark -
 #pragma mark MVKCmdFillBuffer
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index 8b12e05..54f6c9b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -22,9 +22,10 @@
 #include "MVKCommand.h"
 #include "MVKCommandEncoderState.h"
 #include "MVKMTLBufferAllocation.h"
+#include "MVKRenderPass.h"
 #include "MVKCmdPipeline.h"
 #include "MVKQueryPool.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <unordered_map>
 
 class MVKCommandPool;
@@ -39,8 +40,6 @@
 class MVKPipeline;
 class MVKGraphicsPipeline;
 class MVKComputePipeline;
-class MVKCmdBeginRenderPass;
-class MVKCmdEndRenderPass;
 class MVKLoadStoreOverrideMixin;
 
 typedef uint64_t MVKMTLCommandBufferID;
@@ -92,18 +91,19 @@
      * Metal requires that a visibility buffer is established when a render pass is created, 
      * but Vulkan permits it to be set during a render pass. When the first occlusion query
      * command is added, it sets this value so that it can be applied when the first renderpass
-     * is begun. The execution of subsequent occlusion query commmands may change the visibility
+     * is begun. The execution of subsequent occlusion query commands may change the visibility
      * buffer during command execution, and begin a new Metal renderpass.
      */
     id<MTLBuffer> _initialVisibilityResultMTLBuffer;
 
 
 #pragma mark Tessellation constituent command management
+
     /** Preps metadata for recording render pass */
-	void recordBeginRenderPass(MVKCmdBeginRenderPass* mvkBeginRenderPass);
+	void recordBeginRenderPass(MVKLoadStoreOverrideMixin* mvkBeginRenderPass);
 	
 	/** Finishes metadata for recording render pass */
-	void recordEndRenderPass(MVKCmdEndRenderPass* mvkEndRenderPass);
+	void recordEndRenderPass();
 	
 	/** Update the last recorded pipeline if it will end and start a new Metal render pass (ie, in tessellation) */
 	void recordBindPipeline(MVKCmdBindPipeline* mvkBindPipeline);
@@ -112,7 +112,7 @@
 	void recordDraw(MVKLoadStoreOverrideMixin* mvkDraw);
 	
 	/** The most recent recorded begin renderpass */
-	MVKCmdBeginRenderPass* _lastBeginRenderPass;
+	MVKLoadStoreOverrideMixin* _lastBeginRenderPass;
 	
 	/** The most recent recorded multi-pass (ie, tessellation) pipeline */
 	MVKCmdBindPipeline* _lastTessellationPipeline;
@@ -146,7 +146,7 @@
 	friend class MVKCommandPool;
 
 	MVKBaseObject* getBaseObject() override { return this; };
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	void init(const VkCommandBufferAllocateInfo* pAllocateInfo);
 	bool canExecute();
 	bool canPrefill();
@@ -242,7 +242,7 @@
 
 
 /*** Holds a collection of active queries for each query pool. */
-typedef std::unordered_map<MVKQueryPool*, MVKVectorInline<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
+typedef std::unordered_map<MVKQueryPool*, MVKSmallVector<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
 
 /** 
  * MVKCommandEncoder uses a visitor design pattern iterate the commands in a MVKCommandBuffer, 
@@ -269,7 +269,7 @@
 						 MVKRenderPass* renderPass,
 						 MVKFramebuffer* framebuffer,
 						 VkRect2D& renderArea,
-						 MVKVector<VkClearValue>* clearValues,
+						 MVKArrayRef<VkClearValue> clearValues,
 						 bool loadOverride = false,
 						 bool storeOverride = false);
 
@@ -318,7 +318,7 @@
 	void endMetalRenderEncoding();
 
 	/** 
-	 * Returns trhe current Metal compute encoder for the specified use,
+	 * Returns the current Metal compute encoder for the specified use,
 	 * which determines the label assigned to the returned encoder.
 	 *
 	 * If the current encoder is not a compute encoder, this function ends current before 
@@ -337,7 +337,7 @@
 
 	/**
 	 * Returns the current Metal encoder, which may be any of the Metal render,
-	 * comupte, or Blit encoders, or nil if no encoding is currently occurring.
+	 * compute, or Blit encoders, or nil if no encoding is currently occurring.
 	 */
 	id<MTLCommandEncoder> getMTLEncoder();
 
@@ -361,10 +361,10 @@
 
 #pragma mark Queries
 
-    /** Begins an occulusion query. */
+    /** Begins an occlusion query. */
     void beginOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query, VkQueryControlFlags flags);
 
-    /** Ends the current occulusion query. */
+    /** Ends the current occlusion query. */
     void endOcclusionQuery(MVKOcclusionQueryPool* pQueryPool, uint32_t query);
 
     /** Marks a timestamp for the specified query. */
@@ -453,7 +453,7 @@
 	uint32_t _renderSubpassIndex;
 	VkRect2D _renderArea;
     MVKActivatedQueries* _pActivatedQueries;
-	MVKVectorInline<VkClearValue, 8> _clearValues;
+	MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
 	id<MTLComputeCommandEncoder> _mtlComputeEncoder;
 	MVKCommandUse _mtlComputeEncoderUse;
 	id<MTLBlitCommandEncoder> _mtlBlitEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 27af9e8..ad8396c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -20,7 +20,6 @@
 #include "MVKCommandPool.h"
 #include "MVKQueue.h"
 #include "MVKPipeline.h"
-#include "MVKRenderPass.h"
 #include "MVKFramebuffer.h"
 #include "MVKQueryPool.h"
 #include "MVKFoundation.h"
@@ -197,13 +196,13 @@
 #pragma mark -
 #pragma mark Tessellation constituent command management
 
-void MVKCommandBuffer::recordBeginRenderPass(MVKCmdBeginRenderPass* mvkBeginRenderPass) {
+void MVKCommandBuffer::recordBeginRenderPass(MVKLoadStoreOverrideMixin* mvkBeginRenderPass) {
 	_lastBeginRenderPass = mvkBeginRenderPass;
 	_lastTessellationPipeline = nullptr;
 	_lastTessellationDraw = nullptr;
 }
 
-void MVKCommandBuffer::recordEndRenderPass(MVKCmdEndRenderPass* /*mvkEndRenderPass*/) {
+void MVKCommandBuffer::recordEndRenderPass() {
 	// Unset the store override for the last draw call
 	if (_lastTessellationDraw != nullptr)
 	{
@@ -266,7 +265,7 @@
 										MVKRenderPass* renderPass,
 										MVKFramebuffer* framebuffer,
 										VkRect2D& renderArea,
-										MVKVector<VkClearValue>* clearValues,
+										MVKArrayRef<VkClearValue> clearValues,
 										bool loadOverride,
 										bool storeOverride) {
 	_renderPass = renderPass;
@@ -274,7 +273,7 @@
 	_renderArea = renderArea;
 	_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
 									mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
-	_clearValues.assign(clearValues->begin(), clearValues->end());
+	_clearValues.assign(clearValues.begin(), clearValues.end());
 	setSubpass(subpassContents, 0, loadOverride, storeOverride);
 }
 
@@ -301,7 +300,7 @@
     endCurrentMetalEncoding();
 
     MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
-    getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment, loadOverride, storeOverride);
+    getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues.contents(), _isRenderingEntireAttachment, loadOverride, storeOverride);
     mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer();
 
 	// Only set the layered rendering properties if layered rendering is supported and the framebuffer really has multiple layers
@@ -407,8 +406,8 @@
 // Clears the render area of the framebuffer attachments.
 void MVKCommandEncoder::clearRenderArea() {
 
-	MVKVectorInline<VkClearAttachment, kMVKDefaultAttachmentCount> clearAtts;
-	getSubpass()->populateClearAttachments(clearAtts, _clearValues);
+	MVKClearAttachments clearAtts;
+	getSubpass()->populateClearAttachments(clearAtts, _clearValues.contents());
 
 	uint32_t clearAttCnt = (uint32_t)clearAtts.size();
 
@@ -421,7 +420,7 @@
 
     // Create and execute a temporary clear attachments command.
     // To be threadsafe...do NOT acquire and return the command from the pool.
-    MVKCmdClearAttachments cmd;
+    MVKCmdClearMultiAttachments<1> cmd;
     cmd.setContent(_cmdBuffer, clearAttCnt, clearAtts.data(), 1, &clearRect);
     cmd.encode(this);
 }
@@ -449,6 +448,10 @@
 void MVKCommandEncoder::endCurrentMetalEncoding() {
 	endMetalRenderEncoding();
 
+	_computePipelineState.markDirty();
+	_computeResourcesState.markDirty();
+	_computePushConstants.markDirty();
+
 	[_mtlComputeEncoder endEncoding];
 	_mtlComputeEncoder = nil;       // not retained
 	_mtlComputeEncoderUse = kMVKCommandUseNone;
@@ -593,7 +596,7 @@
     MVKActivatedQueries* pAQs = _pActivatedQueries;
     [_mtlCmdBuffer addCompletedHandler: ^(id<MTLCommandBuffer> mtlCmdBuff) {
         for (auto& qryPair : *pAQs) {
-            qryPair.first->finishQueries(qryPair.second);
+            qryPair.first->finishQueries(qryPair.second.contents());
         }
         delete pAQs;
     }];
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 0464e7f..660c74e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -21,7 +21,7 @@
 #include "MVKMTLResourceBindings.h"
 #include "MVKCommandResourceFactory.h"
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <unordered_map>
 
 class MVKCommandEncoder;
@@ -140,7 +140,7 @@
 	 * The isSettingDynamically indicates that the scissor is being changed dynamically,
 	 * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
 	 */
-	void setViewports(const MVKVector<VkViewport> &viewports,
+	void setViewports(const MVKArrayRef<VkViewport> viewports,
 					  uint32_t firstViewport,
 					  bool isSettingDynamically);
 
@@ -152,7 +152,7 @@
     void encodeImpl(uint32_t stage) override;
     void resetImpl() override;
 
-    MVKVectorInline<VkViewport, kMVKCachedViewportScissorCount> _viewports, _dynamicViewports;
+    MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports, _dynamicViewports;
 };
 
 
@@ -169,7 +169,7 @@
 	 * The isSettingDynamically indicates that the scissor is being changed dynamically,
 	 * which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
 	 */
-	void setScissors(const MVKVector<VkRect2D> &scissors,
+	void setScissors(const MVKArrayRef<VkRect2D> scissors,
 					 uint32_t firstScissor,
 					 bool isSettingDynamically);
 
@@ -181,7 +181,7 @@
     void encodeImpl(uint32_t stage) override;
     void resetImpl() override;
 
-    MVKVectorInline<VkRect2D, kMVKCachedViewportScissorCount> _scissors, _dynamicScissors;
+    MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors, _dynamicScissors;
 };
 
 
@@ -194,7 +194,7 @@
 public:
 
     /** Sets the specified push constants. */
-    void setPushConstants(uint32_t offset, MVKVector<char>& pushConstants);
+    void setPushConstants(uint32_t offset, MVKArrayRef<char> pushConstants);
 
     /** Sets the index of the Metal buffer used to hold the push constants. */
     void setMTLBufferIndex(uint32_t mtlBufferIndex);
@@ -209,7 +209,7 @@
     void resetImpl() override;
 	bool isTessellating();
 
-    MVKVectorInline<char, 128> _pushConstants;
+    MVKSmallVector<char, 128> _pushConstants;
     VkShaderStageFlagBits _shaderStage;
     uint32_t _mtlBufferIndex = 0;
 };
@@ -365,8 +365,8 @@
 
     // Template function that updates an existing binding or adds a new binding to a vector
     // of bindings, and marks the binding, the vector, and this instance as dirty
-    template<class T, class U>
-    void bind(const T& b, U& bindings, bool& bindingsDirtyFlag) {
+    template<class T, class V>
+    void bind(const T& b, V& bindings, bool& bindingsDirtyFlag) {
 
         if ( !b.mtlResource ) { return; }
 
@@ -385,31 +385,71 @@
     }
 
 	// For texture bindings, we also keep track of whether any bindings need a texture swizzle
-	void bind(const MVKMTLTextureBinding& tb, MVKVector<MVKMTLTextureBinding>& texBindings,
-			  bool& bindingsDirtyFlag, bool& needsSwizzleFlag) {
+	template<class V>
+	void bind(const MVKMTLTextureBinding& tb, V& texBindings, bool& bindingsDirtyFlag, bool& needsSwizzleFlag) {
 		bind(tb, texBindings, bindingsDirtyFlag);
 		if (tb.swizzle != 0) { needsSwizzleFlag = true; }
 	}
 
     // Template function that executes a lambda expression on each dirty element of
     // a vector of bindings, and marks the bindings and the vector as no longer dirty.
-    template<class T>
-    void encodeBinding(MVKVector<T>& bindings,
-                       bool& bindingsDirtyFlag,
-                       std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
-        if (bindingsDirtyFlag) {
-            bindingsDirtyFlag = false;
-            for (auto& b : bindings) {
-                if (b.isDirty) {
-                    mtlOperation(_cmdEncoder, b);
-                    b.isDirty = false;
-                }
-            }
-        }
-    }
+	template<class T, class V>
+	void encodeBinding(V& bindings,
+					   bool& bindingsDirtyFlag,
+					   std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
+		if (bindingsDirtyFlag) {
+			bindingsDirtyFlag = false;
+			for (auto& b : bindings) {
+				if (b.isDirty) {
+					mtlOperation(_cmdEncoder, b);
+					b.isDirty = false;
+				}
+			}
+		}
+	}
 
-	void updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value);
-	void assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings);
+	// Updates a value at the given index in the given vector, resizing if needed.
+	template<class V>
+	void updateImplicitBuffer(V &contents, uint32_t index, uint32_t value) {
+		if (index >= contents.size()) { contents.resize(index + 1); }
+		contents[index] = value;
+	}
+
+	void assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings);
+
+	template<size_t N>
+	struct ResourceBindings {
+		MVKSmallVector<MVKMTLBufferBinding, N> bufferBindings;
+		MVKSmallVector<MVKMTLTextureBinding, N> textureBindings;
+		MVKSmallVector<MVKMTLSamplerStateBinding, N> samplerStateBindings;
+		MVKSmallVector<uint32_t, N> swizzleConstants;
+		MVKSmallVector<uint32_t, N> bufferSizes;
+
+		MVKMTLBufferBinding swizzleBufferBinding;
+		MVKMTLBufferBinding bufferSizeBufferBinding;
+
+		bool areBufferBindingsDirty = false;
+		bool areTextureBindingsDirty = false;
+		bool areSamplerStateBindingsDirty = false;
+
+		bool needsSwizzle = false;
+
+		void reset() {
+			bufferBindings.clear();
+			textureBindings.clear();
+			samplerStateBindings.clear();
+			swizzleConstants.clear();
+			bufferSizes.clear();
+
+			areBufferBindingsDirty = false;
+			areTextureBindingsDirty = false;
+			areSamplerStateBindingsDirty = false;
+			swizzleBufferBinding.isDirty = false;
+			bufferSizeBufferBinding.isDirty = false;
+
+			needsSwizzle = false;
+		}
+	};
 
 };
 
@@ -457,7 +497,7 @@
                         const char* pStageName,
                         bool fullImageViewSwizzle,
                         std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
-                        std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
+                        std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, const MVKArrayRef<uint32_t>&)> bindImplicitBuffer,
                         std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
                         std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler);
 
@@ -471,23 +511,7 @@
     void resetImpl() override;
     void markDirty() override;
 
-    struct ShaderStage {
-        MVKVectorInline<MVKMTLBufferBinding, 8> bufferBindings;
-        MVKVectorInline<MVKMTLTextureBinding, 8> textureBindings;
-        MVKVectorInline<MVKMTLSamplerStateBinding, 8> samplerStateBindings;
-        MVKVectorInline<uint32_t, 8> swizzleConstants;
-        MVKVectorInline<uint32_t, 8> bufferSizes;
-        MVKMTLBufferBinding swizzleBufferBinding;
-        MVKMTLBufferBinding bufferSizeBufferBinding;
-
-        bool areBufferBindingsDirty = false;
-        bool areTextureBindingsDirty = false;
-        bool areSamplerStateBindingsDirty = false;
-
-        bool needsSwizzle = false;
-    };
-
-    ShaderStage _shaderStages[4];
+    ResourceBindings<8> _shaderStageResourceBindings[4];
 };
 
 
@@ -514,6 +538,8 @@
     /** Sets the current buffer size buffer state. */
     void bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding, bool needSizeBuffer);
 
+    void markDirty() override;
+
 #pragma mark Construction
 
     /** Constructs this instance for the specified command encoder. */
@@ -522,21 +548,8 @@
 protected:
     void encodeImpl(uint32_t) override;
     void resetImpl() override;
-    void markDirty() override;
 
-    MVKVectorInline<MVKMTLBufferBinding, 4> _bufferBindings;
-    MVKVectorInline<MVKMTLTextureBinding, 4> _textureBindings;
-    MVKVectorInline<MVKMTLSamplerStateBinding, 4> _samplerStateBindings;
-    MVKVectorInline<uint32_t, 4> _swizzleConstants;
-    MVKVectorInline<uint32_t, 4> _bufferSizes;
-    MVKMTLBufferBinding _swizzleBufferBinding;
-    MVKMTLBufferBinding _bufferSizeBufferBinding;
-
-    bool _areBufferBindingsDirty = false;
-    bool _areTextureBindingsDirty = false;
-    bool _areSamplerStateBindingsDirty = false;
-
-    bool _needsSwizzle = false;
+	ResourceBindings<4> _resourceBindings;
 };
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 8920101..c06b32a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -58,11 +58,11 @@
 #pragma mark -
 #pragma mark MVKViewportCommandEncoderState
 
-void MVKViewportCommandEncoderState::setViewports(const MVKVector<VkViewport> &viewports,
+void MVKViewportCommandEncoderState::setViewports(const MVKArrayRef<VkViewport> viewports,
 												  uint32_t firstViewport,
 												  bool isSettingDynamically) {
 
-	size_t vpCnt = viewports.size();
+	size_t vpCnt = viewports.size;
 	uint32_t maxViewports = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports;
 	if ((firstViewport + vpCnt > maxViewports) ||
 		(firstViewport >= maxViewports) ||
@@ -111,11 +111,11 @@
 #pragma mark -
 #pragma mark MVKScissorCommandEncoderState
 
-void MVKScissorCommandEncoderState::setScissors(const MVKVector<VkRect2D> &scissors,
+void MVKScissorCommandEncoderState::setScissors(const MVKArrayRef<VkRect2D> scissors,
                                                 uint32_t firstScissor,
 												bool isSettingDynamically) {
 
-	size_t sCnt = scissors.size();
+	size_t sCnt = scissors.size;
 	uint32_t maxScissors = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports;
 	if ((firstScissor + sCnt > maxScissors) ||
 		(firstScissor >= maxScissors) ||
@@ -164,12 +164,12 @@
 #pragma mark -
 #pragma mark MVKPushConstantsCommandEncoderState
 
-void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKVector<char>& pushConstants) {
+void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKArrayRef<char> pushConstants) {
 	// MSL structs can have a larger size than the equivalent C struct due to MSL alignment needs.
 	// Typically any MSL struct that contains a float4 will also have a size that is rounded up to a multiple of a float4 size.
 	// Ensure that we pass along enough content to cover this extra space even if it is never actually accessed by the shader.
 	size_t pcSizeAlign = _cmdEncoder->getDevice()->_pMetalFeatures->pushConstantSizeAlignment;
-    size_t pcSize = pushConstants.size();
+    size_t pcSize = pushConstants.size;
 	size_t pcBuffSize = mvkAlignByteCount(offset + pcSize, pcSizeAlign);
     mvkEnsureSize(_pushConstants, pcBuffSize);
     copy(pushConstants.begin(), pushConstants.end(), _pushConstants.begin() + offset);
@@ -491,16 +491,10 @@
 #pragma mark -
 #pragma mark MVKResourcesCommandEncoderState
 
-// Updates a value at the given index in the given vector.
-void MVKResourcesCommandEncoderState::updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value) {
-	if (index >= contents.size()) { contents.resize(index + 1); }
-	contents[index] = value;
-}
-
 // If a swizzle is needed for this stage, iterates all the bindings and logs errors for those that need texture swizzling.
-void MVKResourcesCommandEncoderState::assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings) {
+void MVKResourcesCommandEncoderState::assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings) {
 	if (needsSwizzle) {
-		for (MVKMTLTextureBinding& tb : texBindings) {
+		for (auto& tb : texBindings) {
 			VkComponentMapping vkcm = mvkUnpackSwizzle(tb.swizzle);
 			if (!mvkVkComponentMappingsMatch(vkcm, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A})) {
 				MVKLogError("Pipeline does not support component swizzle (%s, %s, %s, %s) required by a VkImageView used in the %s shader."
@@ -519,15 +513,15 @@
 #pragma mark MVKGraphicsResourcesCommandEncoderState
 
 void MVKGraphicsResourcesCommandEncoderState::bindBuffer(MVKShaderStage stage, const MVKMTLBufferBinding& binding) {
-    bind(binding, _shaderStages[stage].bufferBindings, _shaderStages[stage].areBufferBindingsDirty);
+    bind(binding, _shaderStageResourceBindings[stage].bufferBindings, _shaderStageResourceBindings[stage].areBufferBindingsDirty);
 }
 
 void MVKGraphicsResourcesCommandEncoderState::bindTexture(MVKShaderStage stage, const MVKMTLTextureBinding& binding) {
-    bind(binding, _shaderStages[stage].textureBindings, _shaderStages[stage].areTextureBindingsDirty, _shaderStages[stage].needsSwizzle);
+    bind(binding, _shaderStageResourceBindings[stage].textureBindings, _shaderStageResourceBindings[stage].areTextureBindingsDirty, _shaderStageResourceBindings[stage].needsSwizzle);
 }
 
 void MVKGraphicsResourcesCommandEncoderState::bindSamplerState(MVKShaderStage stage, const MVKMTLSamplerStateBinding& binding) {
-    bind(binding, _shaderStages[stage].samplerStateBindings, _shaderStages[stage].areSamplerStateBindingsDirty);
+    bind(binding, _shaderStageResourceBindings[stage].samplerStateBindings, _shaderStageResourceBindings[stage].areSamplerStateBindingsDirty);
 }
 
 void MVKGraphicsResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
@@ -535,13 +529,13 @@
 																bool needTessCtlSwizzleBuffer,
 																bool needTessEvalSwizzleBuffer,
 																bool needFragmentSwizzleBuffer) {
-    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
-        _shaderStages[i].swizzleBufferBinding.index = binding.stages[i];
+    for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+        _shaderStageResourceBindings[i].swizzleBufferBinding.index = binding.stages[i];
     }
-    _shaderStages[kMVKShaderStageVertex].swizzleBufferBinding.isDirty = needVertexSwizzleBuffer;
-    _shaderStages[kMVKShaderStageTessCtl].swizzleBufferBinding.isDirty = needTessCtlSwizzleBuffer;
-    _shaderStages[kMVKShaderStageTessEval].swizzleBufferBinding.isDirty = needTessEvalSwizzleBuffer;
-    _shaderStages[kMVKShaderStageFragment].swizzleBufferBinding.isDirty = needFragmentSwizzleBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageVertex].swizzleBufferBinding.isDirty = needVertexSwizzleBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageTessCtl].swizzleBufferBinding.isDirty = needTessCtlSwizzleBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageTessEval].swizzleBufferBinding.isDirty = needTessEvalSwizzleBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageFragment].swizzleBufferBinding.isDirty = needFragmentSwizzleBuffer;
 }
 
 void MVKGraphicsResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
@@ -549,23 +543,23 @@
 																   bool needTessCtlSizeBuffer,
 																   bool needTessEvalSizeBuffer,
 																   bool needFragmentSizeBuffer) {
-    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
-        _shaderStages[i].bufferSizeBufferBinding.index = binding.stages[i];
+    for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+        _shaderStageResourceBindings[i].bufferSizeBufferBinding.index = binding.stages[i];
     }
-    _shaderStages[kMVKShaderStageVertex].bufferSizeBufferBinding.isDirty = needVertexSizeBuffer;
-    _shaderStages[kMVKShaderStageTessCtl].bufferSizeBufferBinding.isDirty = needTessCtlSizeBuffer;
-    _shaderStages[kMVKShaderStageTessEval].bufferSizeBufferBinding.isDirty = needTessEvalSizeBuffer;
-    _shaderStages[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageVertex].bufferSizeBufferBinding.isDirty = needVertexSizeBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageTessCtl].bufferSizeBufferBinding.isDirty = needTessCtlSizeBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageTessEval].bufferSizeBufferBinding.isDirty = needTessEvalSizeBuffer;
+    _shaderStageResourceBindings[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
 }
 
 void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stage,
                                                              const char* pStageName,
                                                              bool fullImageViewSwizzle,
                                                              std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
-                                                             std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
+                                                             std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, const MVKArrayRef<uint32_t>&)> bindImplicitBuffer,
                                                              std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
                                                              std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler) {
-    auto& shaderStage = _shaderStages[stage];
+    auto& shaderStage = _shaderStageResourceBindings[stage];
     encodeBinding<MVKMTLBufferBinding>(shaderStage.bufferBindings, shaderStage.areBufferBindingsDirty, bindBuffer);
 
     if (shaderStage.swizzleBufferBinding.isDirty) {
@@ -574,10 +568,10 @@
             if (b.isDirty) { updateImplicitBuffer(shaderStage.swizzleConstants, b.index, b.swizzle); }
         }
 
-        bindImplicitBuffer(_cmdEncoder, shaderStage.swizzleBufferBinding, shaderStage.swizzleConstants);
+        bindImplicitBuffer(_cmdEncoder, shaderStage.swizzleBufferBinding, shaderStage.swizzleConstants.contents());
 
     } else {
-        assertMissingSwizzles(shaderStage.needsSwizzle && !fullImageViewSwizzle, pStageName, shaderStage.textureBindings);
+        assertMissingSwizzles(shaderStage.needsSwizzle && !fullImageViewSwizzle, pStageName, shaderStage.textureBindings.contents());
     }
 
     if (shaderStage.bufferSizeBufferBinding.isDirty) {
@@ -585,7 +579,7 @@
             if (b.isDirty) { updateImplicitBuffer(shaderStage.bufferSizes, b.index, b.size); }
         }
 
-        bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes);
+        bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes.contents());
     }
 
     encodeBinding<MVKMTLTextureBinding>(shaderStage.textureBindings, shaderStage.areTextureBindingsDirty, bindTexture);
@@ -595,36 +589,47 @@
 // Mark everything as dirty
 void MVKGraphicsResourcesCommandEncoderState::markDirty() {
     MVKCommandEncoderState::markDirty();
-    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
-        MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].bufferBindings, _shaderStages[i].areBufferBindingsDirty);
-        MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].textureBindings, _shaderStages[i].areTextureBindingsDirty);
-        MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].samplerStateBindings, _shaderStages[i].areSamplerStateBindingsDirty);
+    for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+        MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].bufferBindings, _shaderStageResourceBindings[i].areBufferBindingsDirty);
+        MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].textureBindings, _shaderStageResourceBindings[i].areTextureBindingsDirty);
+        MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].samplerStateBindings, _shaderStageResourceBindings[i].areSamplerStateBindingsDirty);
     }
 }
 
 void MVKGraphicsResourcesCommandEncoderState::encodeImpl(uint32_t stage) {
 
-    MVKPipeline* pipeline = _cmdEncoder->_graphicsPipelineState.getPipeline();
+    MVKGraphicsPipeline* pipeline = (MVKGraphicsPipeline*)_cmdEncoder->_graphicsPipelineState.getPipeline();
     bool fullImageViewSwizzle = pipeline->fullImageViewSwizzle() || _cmdEncoder->getDevice()->_pMetalFeatures->nativeTextureSwizzle;
-    bool forTessellation = ((MVKGraphicsPipeline*)pipeline)->isTessellationPipeline();
+    bool forTessellation = pipeline->isTessellationPipeline();
 
     if (stage == (forTessellation ? kMVKGraphicsStageVertex : kMVKGraphicsStageRasterization)) {
         encodeBindings(kMVKShaderStageVertex, "vertex", fullImageViewSwizzle,
-                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
-                           if (b.isInline)
+                       [pipeline](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
+					       if (b.isInline) {
                                cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,
                                                           b.mtlBytes,
                                                           b.size,
                                                           b.index);
-                           else
+					       } else {
                                [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
                                                                        offset: b.offset
                                                                       atIndex: b.index];
+
+							   // Add any translated vertex bindings for this binding
+							   auto xltdVtxBindings = pipeline->getTranslatedVertexBindings();
+							   for (auto& xltdBind : xltdVtxBindings) {
+								   if (b.index == pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.binding)) {
+									   [cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
+																			   offset: b.offset + xltdBind.translationOffset
+																			  atIndex: pipeline->getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding)];
+								   }
+							   }
+					       }
                        },
-                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
                            cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,
-                                                      s.data(),
-                                                      s.size() * sizeof(uint32_t),
+                                                      s.data,
+                                                      s.size * sizeof(uint32_t),
                                                       b.index);
                        },
                        [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -651,10 +656,10 @@
                                                                                                        offset: b.offset
                                                                                                       atIndex: b.index];
                        },
-                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
                            cmdEncoder->setComputeBytes(cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationControl),
-                                                       s.data(),
-                                                       s.size() * sizeof(uint32_t),
+                                                       s.data,
+                                                       s.size * sizeof(uint32_t),
                                                        b.index);
                        },
                        [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -681,10 +686,10 @@
                                                                        offset: b.offset
                                                                       atIndex: b.index];
                        },
-                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
                            cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,
-                                                      s.data(),
-                                                      s.size() * sizeof(uint32_t),
+                                                      s.data,
+                                                      s.size * sizeof(uint32_t),
                                                       b.index);
                        },
                        [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -711,10 +716,10 @@
                                                                          offset: b.offset
                                                                         atIndex: b.index];
                        },
-                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+                       [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
                            cmdEncoder->setFragmentBytes(cmdEncoder->_mtlRenderEncoder,
-                                                        s.data(),
-                                                        s.size() * sizeof(uint32_t),
+                                                        s.data,
+                                                        s.size * sizeof(uint32_t),
                                                         b.index);
                        },
                        [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -729,21 +734,9 @@
 }
 
 void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
-    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
-        _shaderStages[i].bufferBindings.clear();
-        _shaderStages[i].textureBindings.clear();
-        _shaderStages[i].samplerStateBindings.clear();
-        _shaderStages[i].swizzleConstants.clear();
-        _shaderStages[i].bufferSizes.clear();
-
-        _shaderStages[i].areBufferBindingsDirty = false;
-        _shaderStages[i].areTextureBindingsDirty = false;
-        _shaderStages[i].areSamplerStateBindingsDirty = false;
-        _shaderStages[i].swizzleBufferBinding.isDirty = false;
-        _shaderStages[i].bufferSizeBufferBinding.isDirty = false;
-
-        _shaderStages[i].needsSwizzle = false;
-    }
+	for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+		_shaderStageResourceBindings[i].reset();
+	}
 }
 
 
@@ -751,35 +744,35 @@
 #pragma mark MVKComputeResourcesCommandEncoderState
 
 void MVKComputeResourcesCommandEncoderState::bindBuffer(const MVKMTLBufferBinding& binding) {
-    bind(binding, _bufferBindings, _areBufferBindingsDirty);
+	bind(binding, _resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty);
 }
 
 void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) {
-    bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
+    bind(binding, _resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty, _resourceBindings.needsSwizzle);
 }
 
 void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) {
-    bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
+    bind(binding, _resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty);
 }
 
 void MVKComputeResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
 															   bool needSwizzleBuffer) {
-    _swizzleBufferBinding.index = binding.stages[kMVKShaderStageCompute];
-    _swizzleBufferBinding.isDirty = needSwizzleBuffer;
+    _resourceBindings.swizzleBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+    _resourceBindings.swizzleBufferBinding.isDirty = needSwizzleBuffer;
 }
 
 void MVKComputeResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
 																  bool needBufferSizeBuffer) {
-    _bufferSizeBufferBinding.index = binding.stages[kMVKShaderStageCompute];
-    _bufferSizeBufferBinding.isDirty = needBufferSizeBuffer;
+    _resourceBindings.bufferSizeBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+    _resourceBindings.bufferSizeBufferBinding.isDirty = needBufferSizeBuffer;
 }
 
 // Mark everything as dirty
 void MVKComputeResourcesCommandEncoderState::markDirty() {
     MVKCommandEncoderState::markDirty();
-    MVKResourcesCommandEncoderState::markDirty(_bufferBindings, _areBufferBindingsDirty);
-    MVKResourcesCommandEncoderState::markDirty(_textureBindings, _areTextureBindingsDirty);
-    MVKResourcesCommandEncoderState::markDirty(_samplerStateBindings, _areSamplerStateBindingsDirty);
+    MVKResourcesCommandEncoderState::markDirty(_resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty);
+    MVKResourcesCommandEncoderState::markDirty(_resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty);
+    MVKResourcesCommandEncoderState::markDirty(_resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty);
 }
 
 void MVKComputeResourcesCommandEncoderState::encodeImpl(uint32_t) {
@@ -789,7 +782,7 @@
     if (pipeline)
         fullImageViewSwizzle = pipeline->fullImageViewSwizzle();
 
-    encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty,
+    encodeBinding<MVKMTLBufferBinding>(_resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty,
 									   [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
 											if (b.isInline)
 												cmdEncoder->setComputeBytes(cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
@@ -802,40 +795,40 @@
 																											atIndex: b.index];
                                        });
 
-    if (_swizzleBufferBinding.isDirty) {
+    if (_resourceBindings.swizzleBufferBinding.isDirty) {
 
-		for (auto& b : _textureBindings) {
-			if (b.isDirty) { updateImplicitBuffer(_swizzleConstants, b.index, b.swizzle); }
+		for (auto& b : _resourceBindings.textureBindings) {
+			if (b.isDirty) { updateImplicitBuffer(_resourceBindings.swizzleConstants, b.index, b.swizzle); }
 		}
 
 		_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
-                                     _swizzleConstants.data(),
-                                     _swizzleConstants.size() * sizeof(uint32_t),
-                                     _swizzleBufferBinding.index);
+                                     _resourceBindings.swizzleConstants.data(),
+                                     _resourceBindings.swizzleConstants.size() * sizeof(uint32_t),
+                                     _resourceBindings.swizzleBufferBinding.index);
 
 	} else {
-		assertMissingSwizzles(_needsSwizzle && !fullImageViewSwizzle, "compute", _textureBindings);
+		assertMissingSwizzles(_resourceBindings.needsSwizzle && !fullImageViewSwizzle, "compute", _resourceBindings.textureBindings.contents());
     }
 
-    if (_bufferSizeBufferBinding.isDirty) {
-		for (auto& b : _bufferBindings) {
-			if (b.isDirty) { updateImplicitBuffer(_bufferSizes, b.index, b.size); }
+    if (_resourceBindings.bufferSizeBufferBinding.isDirty) {
+		for (auto& b : _resourceBindings.bufferBindings) {
+			if (b.isDirty) { updateImplicitBuffer(_resourceBindings.bufferSizes, b.index, b.size); }
 		}
 
 		_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
-                                     _bufferSizes.data(),
-                                     _bufferSizes.size() * sizeof(uint32_t),
-                                     _bufferSizeBufferBinding.index);
+                                     _resourceBindings.bufferSizes.data(),
+                                     _resourceBindings.bufferSizes.size() * sizeof(uint32_t),
+                                     _resourceBindings.bufferSizeBufferBinding.index);
 
     }
 
-    encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
+    encodeBinding<MVKMTLTextureBinding>(_resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty,
                                         [](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
                                             [cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setTexture: b.mtlTexture
 																										 atIndex: b.index];
                                         });
 
-    encodeBinding<MVKMTLSamplerStateBinding>(_samplerStateBindings, _areSamplerStateBindingsDirty,
+    encodeBinding<MVKMTLSamplerStateBinding>(_resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty,
                                              [](MVKCommandEncoder* cmdEncoder, MVKMTLSamplerStateBinding& b)->void {
                                                  [cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setSamplerState: b.mtlSamplerState
 																												   atIndex: b.index];
@@ -843,19 +836,7 @@
 }
 
 void MVKComputeResourcesCommandEncoderState::resetImpl() {
-    _bufferBindings.clear();
-    _textureBindings.clear();
-    _samplerStateBindings.clear();
-    _swizzleConstants.clear();
-    _bufferSizes.clear();
-
-    _areBufferBindingsDirty = false;
-    _areTextureBindingsDirty = false;
-    _areSamplerStateBindingsDirty = false;
-    _swizzleBufferBinding.isDirty = false;
-    _bufferSizeBufferBinding.isDirty = false;
-
-	_needsSwizzle = false;
+	_resourceBindings.reset();
 }
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h
index e14ecee..41c68da 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.h
@@ -100,7 +100,7 @@
 	~MVKCommandPool() override;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	MVKDeviceObjectPool<MVKCommandBuffer> _commandBufferPool;
 	std::unordered_set<MVKCommandBuffer*> _allocatedCommandBuffers;
 	MVKCommandEncodingPool _commandEncodingPool;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index 07a2dcf..a92b86e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -369,7 +369,7 @@
         .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED
     };
 	MVKImage* mvkImg = _device->createImage(&createInfo, nullptr);
-	mvkImg->bindDeviceMemory(_transferImageMemory, 0);
+	mvkImg->bindDeviceMemory(_transferImageMemory, 0, 0);
 	return mvkImg;
 }
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
index c47d949..87a9518 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def
@@ -41,17 +41,33 @@
 #	define MVK_CMD_TYPE_POOL_LAST(cmdType) MVK_CMD_TYPE_POOL(cmdType)
 #endif
 
-MVK_CMD_TYPE_POOL(PipelineBarrier)
-MVK_CMD_TYPE_POOL(BindPipeline)
-MVK_CMD_TYPE_POOL(BeginRenderPass)
+#define MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(cmdType, threshold)	\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold)		\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi)
+
+#define MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(cmdType, threshold1, threshold2)	\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold1)						\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold2)						\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi)
+
+#define MVK_CMD_TYPE_POOLS_FROM_3_THRESHOLDS(cmdType, threshold1, threshold2, threshold3)	\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold1)									\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold2)									\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##threshold3)									\
+	MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(cmdType ##Multi)
+
+
+MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(PipelineBarrier, 1, 4)
+MVK_CMD_TYPE_POOL(BindGraphicsPipeline)
+MVK_CMD_TYPE_POOL(BindComputePipeline)
+MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BeginRenderPass, 1, 2)
 MVK_CMD_TYPE_POOL(NextSubpass)
 MVK_CMD_TYPE_POOL(EndRenderPass)
-MVK_CMD_TYPE_POOL(ExecuteCommands)
-MVK_CMD_TYPE_POOL(BindDescriptorSets)
-MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(SetViewport1)
-MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(SetViewportMulti)
-MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(SetScissor1)
-MVK_TMPLT_DECL MVK_CMD_TYPE_POOL(SetScissorMulti)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1)
+MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetViewport, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(SetScissor, 1)
 MVK_CMD_TYPE_POOL(SetLineWidth)
 MVK_CMD_TYPE_POOL(SetDepthBias)
 MVK_CMD_TYPE_POOL(SetBlendConstants)
@@ -59,27 +75,29 @@
 MVK_CMD_TYPE_POOL(SetStencilCompareMask)
 MVK_CMD_TYPE_POOL(SetStencilWriteMask)
 MVK_CMD_TYPE_POOL(SetStencilReference)
-MVK_CMD_TYPE_POOL(BindVertexBuffers)
+MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2)
 MVK_CMD_TYPE_POOL(BindIndexBuffer)
 MVK_CMD_TYPE_POOL(Draw)
 MVK_CMD_TYPE_POOL(DrawIndexed)
 MVK_CMD_TYPE_POOL(DrawIndirect)
 MVK_CMD_TYPE_POOL(DrawIndexedIndirect)
-MVK_CMD_TYPE_POOL(CopyImage)
-MVK_CMD_TYPE_POOL(BlitImage)
-MVK_CMD_TYPE_POOL(ResolveImage)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(CopyImage, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BlitImage, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ResolveImage, 1)
 MVK_CMD_TYPE_POOL(FillBuffer)
 MVK_CMD_TYPE_POOL(UpdateBuffer)
-MVK_CMD_TYPE_POOL(CopyBuffer)
-MVK_CMD_TYPE_POOL(BufferImageCopy)
-MVK_CMD_TYPE_POOL(ClearAttachments)
-MVK_CMD_TYPE_POOL(ClearImage)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(CopyBuffer, 1)
+MVK_CMD_TYPE_POOLS_FROM_3_THRESHOLDS(BufferImageCopy, 1, 4, 8)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ClearSingleAttachment, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ClearMultiAttachments, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ClearColorImage, 1)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ClearDepthStencilImage, 1)
 MVK_CMD_TYPE_POOL(BeginQuery)
 MVK_CMD_TYPE_POOL(EndQuery)
 MVK_CMD_TYPE_POOL(WriteTimestamp)
 MVK_CMD_TYPE_POOL(ResetQueryPool)
 MVK_CMD_TYPE_POOL(CopyQueryPoolResults)
-MVK_CMD_TYPE_POOL(PushConstants)
+MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(PushConstants, 64, 128)
 MVK_CMD_TYPE_POOL(Dispatch)
 MVK_CMD_TYPE_POOL(DispatchIndirect)
 MVK_CMD_TYPE_POOL(PushDescriptorSet)
@@ -87,8 +105,9 @@
 MVK_CMD_TYPE_POOL(DebugMarkerBegin)
 MVK_CMD_TYPE_POOL(DebugMarkerEnd)
 MVK_CMD_TYPE_POOL(DebugMarkerInsert)
-MVK_CMD_TYPE_POOL(SetResetEvent)
-MVK_CMD_TYPE_POOL_LAST(WaitEvents)
+MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(WaitEvents, 1)
+MVK_CMD_TYPE_POOL(SetEvent)
+MVK_CMD_TYPE_POOL_LAST(ResetEvent)
 
 #undef MVK_CMD_TYPE_POOL
 #undef MVK_CMD_TYPE_POOL_LAST
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
index 17f9589..c8dc025 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
@@ -22,7 +22,7 @@
 #include "MVKFoundation.h"
 #include "MVKObjectPool.h"
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 class MVKMTLBufferAllocationPool;
 
@@ -97,7 +97,7 @@
     NSUInteger _nextOffset;
     NSUInteger _allocationLength;
     NSUInteger _mtlBufferLength;
-	MVKVectorInline<id<MTLBuffer>, 64> _mtlBuffers;
+	MVKSmallVector<id<MTLBuffer>, 64> _mtlBuffers;
     MVKDevice* _device;
 };
 
@@ -142,7 +142,7 @@
     ~MVKMTLBufferAllocator() override;
 
 protected:
-	MVKVectorInline<MVKMTLBufferAllocationPool*, 32> _regionPools;
+	MVKSmallVector<MVKMTLBufferAllocationPool*, 32> _regionPools;
     NSUInteger _maxAllocationLength;
 	bool _makeThreadSafe;
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
index 7e1bf25..a09386b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.mm
@@ -81,7 +81,7 @@
 	MVKAssert(length <= _maxAllocationLength, "This MVKMTLBufferAllocator has been configured to dispense MVKMTLBufferRegions no larger than %lu bytes.", (unsigned long)_maxAllocationLength);
 
     // Convert max length to the next power-of-two exponent to use as a lookup
-    uint32_t p2Exp = mvkPowerOfTwoExponent(length);
+    NSUInteger p2Exp = mvkPowerOfTwoExponent(length);
 	MVKMTLBufferAllocationPool* pRP = _regionPools[p2Exp];
 	return _makeThreadSafe ? pRP->acquireObjectSafely() : pRP->acquireObject();
 }
@@ -91,7 +91,7 @@
 	_makeThreadSafe = makeThreadSafe;
 
     // Convert max length to the next power-of-two exponent
-    uint32_t maxP2Exp = mvkPowerOfTwoExponent(_maxAllocationLength);
+    NSUInteger maxP2Exp = mvkPowerOfTwoExponent(_maxAllocationLength);
 
     // Populate the array of region pools to cover the maximum region size
     _regionPools.reserve(maxP2Exp + 1);
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
index f7188d6..a530288 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
@@ -18,29 +18,37 @@
 
 #pragma once
 
+#include "mvk_vulkan.h"
+
 #import <Metal/Metal.h>
 
+
+class MVKResource;
+class MVKBuffer;
+class MVKImage;
+
+
 /** Describes a MTLTexture resource binding. */
 typedef struct {
     union { id<MTLTexture> mtlTexture = nil; id<MTLTexture> mtlResource; }; // aliases
-    uint32_t index = 0;
     uint32_t swizzle = 0;
+	uint16_t index = 0;
     bool isDirty = true;
 } MVKMTLTextureBinding;
 
 /** Describes a MTLSamplerState resource binding. */
 typedef struct {
     union { id<MTLSamplerState> mtlSamplerState = nil; id<MTLSamplerState> mtlResource; }; // aliases
-    uint32_t index = 0;
+    uint16_t index = 0;
     bool isDirty = true;
 } MVKMTLSamplerStateBinding;
 
 /** Describes a MTLBuffer resource binding. */
 typedef struct {
     union { id<MTLBuffer> mtlBuffer = nil; id<MTLBuffer> mtlResource; const void* mtlBytes; }; // aliases
-    NSUInteger offset = 0;
-    uint32_t index = 0;
+    VkDeviceSize offset = 0;
     uint32_t size = 0;
+	uint16_t index = 0;
     bool isDirty = true;
     bool isInline = false;
 } MVKMTLBufferBinding;
@@ -48,7 +56,78 @@
 /** Describes a MTLBuffer resource binding as used for an index buffer. */
 typedef struct {
     union { id<MTLBuffer> mtlBuffer = nil; id<MTLBuffer> mtlResource; }; // aliases
-    NSUInteger offset = 0;
-    MTLIndexType mtlIndexType;
+    VkDeviceSize offset = 0;
+    uint8_t mtlIndexType = 0;		// MTLIndexType
     bool isDirty = true;
 } MVKIndexMTLBufferBinding;
+
+/** Concise and consistent structure for holding pipeline barrier info. */
+typedef struct MVKPipelineBarrier {
+
+	typedef enum : uint8_t {
+		None,
+		Memory,
+		Buffer,
+		Image,
+	} MVKPipelineBarrierType;
+
+	union { MVKBuffer* mvkBuffer = nullptr; MVKImage* mvkImage; MVKResource* mvkResource; };
+	union {
+		struct {
+			VkDeviceSize offset = 0;
+			VkDeviceSize size = 0;
+		};
+		struct {
+			VkImageLayout newLayout;
+			VkImageAspectFlags aspectMask;
+			uint16_t baseArrayLayer;
+			uint16_t layerCount;
+			uint8_t baseMipLevel;
+			uint8_t levelCount;
+		};
+	};
+	VkAccessFlags srcAccessMask = 0;
+	VkAccessFlags dstAccessMask = 0;
+	uint8_t srcQueueFamilyIndex = 0;
+	uint8_t dstQueueFamilyIndex = 0;
+
+	MVKPipelineBarrierType type = None;
+
+	bool isMemoryBarrier() { return type == Memory; }
+	bool isBufferBarrier() { return type == Buffer; }
+	bool isImageBarrier() { return type == Image; }
+
+	MVKPipelineBarrier(const VkMemoryBarrier& vkBarrier) :
+		type(Memory),
+		srcAccessMask(vkBarrier.srcAccessMask),
+		dstAccessMask(vkBarrier.dstAccessMask)
+		{}
+
+	MVKPipelineBarrier(const VkBufferMemoryBarrier& vkBarrier) :
+		type(Buffer),
+		srcAccessMask(vkBarrier.srcAccessMask),
+		dstAccessMask(vkBarrier.dstAccessMask),
+		srcQueueFamilyIndex(vkBarrier.srcQueueFamilyIndex),
+		dstQueueFamilyIndex(vkBarrier.dstQueueFamilyIndex),
+		mvkBuffer((MVKBuffer*)vkBarrier.buffer),
+		offset(vkBarrier.offset),
+		size(vkBarrier.size)
+		{}
+
+	MVKPipelineBarrier(const VkImageMemoryBarrier& vkBarrier) :
+		type(Image),
+		srcAccessMask(vkBarrier.srcAccessMask),
+		dstAccessMask(vkBarrier.dstAccessMask),
+		newLayout(vkBarrier.newLayout),
+		srcQueueFamilyIndex(vkBarrier.srcQueueFamilyIndex),
+		dstQueueFamilyIndex(vkBarrier.dstQueueFamilyIndex),
+		mvkImage((MVKImage*)vkBarrier.image),
+		aspectMask(vkBarrier.subresourceRange.aspectMask),
+		baseMipLevel(vkBarrier.subresourceRange.baseMipLevel),
+		levelCount(vkBarrier.subresourceRange.levelCount),
+		baseArrayLayer(vkBarrier.subresourceRange.baseArrayLayer),
+		layerCount(vkBarrier.subresourceRange.layerCount)
+		{}
+
+} MVKPipelineBarrier;
+
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
index d3cbb05..c00c5bc 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.h
@@ -40,27 +40,30 @@
 #pragma mark Resource memory
 
 	/** Returns the memory requirements of this resource by populating the specified structure. */
-	VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements) override;
+	VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements);
 
 	/** Returns the memory requirements of this resource by populating the specified structure. */
-	VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements) override;
+	VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements);
 
 	/** Binds this resource to the specified offset within the specified memory allocation. */
-	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;
+	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
+
+	/** Binds this resource to the specified offset within the specified memory allocation. */
+	VkResult bindDeviceMemory2(const VkBindBufferMemoryInfo* pBindInfo);
 
 	/** Applies the specified global memory barrier. */
-    void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
-                            VkPipelineStageFlags dstStageMask,
-                            VkMemoryBarrier* pMemoryBarrier,
-                            MVKCommandEncoder* cmdEncoder,
-                            MVKCommandUse cmdUse) override;
+	void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
+							VkPipelineStageFlags dstStageMask,
+							MVKPipelineBarrier& barrier,
+							MVKCommandEncoder* cmdEncoder,
+							MVKCommandUse cmdUse) override;
 
 	/** Applies the specified buffer memory barrier. */
-    void applyBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
-                                  VkPipelineStageFlags dstStageMask,
-                                  VkBufferMemoryBarrier* pBufferMemoryBarrier,
-                                  MVKCommandEncoder* cmdEncoder,
-                                  MVKCommandUse cmdUse);
+	void applyBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
+								  VkPipelineStageFlags dstStageMask,
+								  MVKPipelineBarrier& barrier,
+								  MVKCommandEncoder* cmdEncoder,
+								  MVKCommandUse cmdUse);
 
     /** Returns the intended usage of this buffer. */
     VkBufferUsageFlags getUsage() const { return _usage; }
@@ -72,7 +75,7 @@
 	id<MTLBuffer> getMTLBuffer();
 
 	/** Returns the offset at which the contents of this instance starts within the underlying Metal buffer. */
-	inline NSUInteger getMTLBufferOffset() { return _deviceMemory && _deviceMemory->getMTLHeap() && !_isHostCoherentTexelBuffer ? 0 : _deviceMemoryOffset; }
+	inline NSUInteger getMTLBufferOffset() { return !_deviceMemory || _deviceMemory->getMTLHeap() || _isHostCoherentTexelBuffer ? 0 : _deviceMemoryOffset; }
 
 
 #pragma mark Construction
@@ -85,13 +88,14 @@
 	friend class MVKDeviceMemory;
 	using MVKResource::needsHostReadSync;
 
-	void propogateDebugName() override;
+	void propagateDebugName() override;
 	bool needsHostReadSync(VkPipelineStageFlags srcStageMask,
 						   VkPipelineStageFlags dstStageMask,
-						   VkBufferMemoryBarrier* pBufferMemoryBarrier);
+						   MVKPipelineBarrier& barrier);
 	bool shouldFlushHostMemory();
 	VkResult flushToDevice(VkDeviceSize offset, VkDeviceSize size);
 	VkResult pullFromDevice(VkDeviceSize offset, VkDeviceSize size);
+	void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
 
 	VkBufferUsageFlags _usage;
 	bool _isHostCoherentTexelBuffer = false;
@@ -125,7 +129,7 @@
     ~MVKBufferView() override;
 
 protected:
-	void propogateDebugName() override;
+	void propagateDebugName() override;
 
     MVKBuffer* _buffer;
 	id<MTLTexture> _mtlTexture;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index ed74605..178357d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -28,7 +28,7 @@
 #pragma mark -
 #pragma mark MVKBuffer
 
-void MVKBuffer::propogateDebugName() {
+void MVKBuffer::propagateDebugName() {
 	if (!_debugName) { return; }
 	if (_deviceMemory &&
 		_deviceMemory->isDedicatedAllocation() &&
@@ -66,8 +66,8 @@
 		switch (next->sType) {
 		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
 			auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
-			dedicatedReqs->prefersDedicatedAllocation = VK_FALSE;
-			dedicatedReqs->requiresDedicatedAllocation = VK_FALSE;
+			dedicatedReqs->requiresDedicatedAllocation = _requiresDedicatedMemoryAllocation;
+			dedicatedReqs->prefersDedicatedAllocation = dedicatedReqs->requiresDedicatedAllocation;
 			break;
 		}
 		default:
@@ -88,18 +88,22 @@
 	}
 #endif
 
-	propogateDebugName();
+	propagateDebugName();
 
 	return _deviceMemory ? _deviceMemory->addBuffer(this) : VK_SUCCESS;
 }
 
+VkResult MVKBuffer::bindDeviceMemory2(const VkBindBufferMemoryInfo* pBindInfo) {
+	return bindDeviceMemory((MVKDeviceMemory*)pBindInfo->memory, pBindInfo->memoryOffset);
+}
+
 void MVKBuffer::applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
 								   VkPipelineStageFlags dstStageMask,
-								   VkMemoryBarrier* pMemoryBarrier,
+								   MVKPipelineBarrier& barrier,
                                    MVKCommandEncoder* cmdEncoder,
                                    MVKCommandUse cmdUse) {
 #if MVK_MACOS
-	if ( needsHostReadSync(srcStageMask, dstStageMask, pMemoryBarrier) ) {
+	if ( needsHostReadSync(srcStageMask, dstStageMask, barrier) ) {
 		[cmdEncoder->getMTLBlitEncoder(cmdUse) synchronizeResource: getMTLBuffer()];
 	}
 #endif
@@ -107,16 +111,31 @@
 
 void MVKBuffer::applyBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
 										 VkPipelineStageFlags dstStageMask,
-										 VkBufferMemoryBarrier* pBufferMemoryBarrier,
+										 MVKPipelineBarrier& barrier,
                                          MVKCommandEncoder* cmdEncoder,
                                          MVKCommandUse cmdUse) {
 #if MVK_MACOS
-	if ( needsHostReadSync(srcStageMask, dstStageMask, pBufferMemoryBarrier) ) {
+	if ( needsHostReadSync(srcStageMask, dstStageMask, barrier) ) {
 		[cmdEncoder->getMTLBlitEncoder(cmdUse) synchronizeResource: getMTLBuffer()];
 	}
 #endif
 }
 
+// Returns whether the specified buffer memory barrier requires a sync between this
+// buffer and host memory for the purpose of the host reading texture memory.
+bool MVKBuffer::needsHostReadSync(VkPipelineStageFlags srcStageMask,
+								  VkPipelineStageFlags dstStageMask,
+								  MVKPipelineBarrier& barrier) {
+#if MVK_MACOS
+	return (mvkIsAnyFlagEnabled(dstStageMask, (VK_PIPELINE_STAGE_HOST_BIT)) &&
+			mvkIsAnyFlagEnabled(barrier.dstAccessMask, (VK_ACCESS_HOST_READ_BIT)) &&
+			isMemoryHostAccessible() && (!isMemoryHostCoherent() || _isHostCoherentTexelBuffer));
+#endif
+#if MVK_IOS
+	return false;
+#endif
+}
+
 #if MVK_MACOS
 bool MVKBuffer::shouldFlushHostMemory() { return _isHostCoherentTexelBuffer; }
 #endif
@@ -142,21 +161,6 @@
 	return VK_SUCCESS;
 }
 
-// Returns whether the specified buffer memory barrier requires a sync between this
-// buffer and host memory for the purpose of the host reading texture memory.
-bool MVKBuffer::needsHostReadSync(VkPipelineStageFlags srcStageMask,
-								  VkPipelineStageFlags dstStageMask,
-								  VkBufferMemoryBarrier* pBufferMemoryBarrier) {
-#if MVK_IOS
-	return false;
-#endif
-#if MVK_MACOS
-	return (mvkIsAnyFlagEnabled(dstStageMask, (VK_PIPELINE_STAGE_HOST_BIT)) &&
-			mvkIsAnyFlagEnabled(pBufferMemoryBarrier->dstAccessMask, (VK_ACCESS_HOST_READ_BIT)) &&
-			isMemoryHostAccessible() && (!isMemoryHostCoherent() || _isHostCoherentTexelBuffer));
-#endif
-}
-
 
 #pragma mark Metal
 
@@ -167,16 +171,15 @@
 			_mtlBuffer = [_deviceMemory->getMTLHeap() newBufferWithLength: getByteCount()
 																  options: _deviceMemory->getMTLResourceOptions()
 																   offset: _deviceMemoryOffset];	// retained
-			propogateDebugName();
+			propagateDebugName();
 			return _mtlBuffer;
 #if MVK_MACOS
 		} else if (_isHostCoherentTexelBuffer) {
 			// According to the Vulkan spec, buffers, like linear images, can always use host-coherent memory.
-                        // But texel buffers on Mac cannot use shared memory. So we need to use host-cached
-                        // memory here.
+			// But texel buffers on Mac cannot use shared memory. So we need to use host-cached memory here.
 			_mtlBuffer = [_device->getMTLDevice() newBufferWithLength: getByteCount()
 															  options: MTLResourceStorageModeManaged];	// retained
-			propogateDebugName();
+			propagateDebugName();
 			return _mtlBuffer;
 #endif
 		} else {
@@ -192,6 +195,28 @@
 MVKBuffer::MVKBuffer(MVKDevice* device, const VkBufferCreateInfo* pCreateInfo) : MVKResource(device), _usage(pCreateInfo->usage) {
     _byteAlignment = _device->_pMetalFeatures->mtlBufferAlignment;
     _byteCount = pCreateInfo->size;
+
+	for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+		switch (next->sType) {
+			case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO: {
+				auto* pExtMemInfo = (const VkExternalMemoryBufferCreateInfo*)next;
+				initExternalMemory(pExtMemInfo->handleTypes);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+}
+
+void MVKBuffer::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+	if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR)) {
+		_externalMemoryHandleTypes = handleTypes;
+		auto& xmProps = _device->getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR);
+		_requiresDedicatedMemoryAllocation = _requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+	} else {
+		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateBuffer(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR is supported."));
+	}
 }
 
 MVKBuffer::~MVKBuffer() {
@@ -203,7 +228,7 @@
 #pragma mark -
 #pragma mark MVKBufferView
 
-void MVKBufferView::propogateDebugName() {
+void MVKBufferView::propagateDebugName() {
 	setLabelIfNotNil(_mtlTexture, _debugName);
 }
 
@@ -239,7 +264,7 @@
 		_mtlTexture = [mtlBuff newTextureWithDescriptor: mtlTexDesc
 												 offset: _mtlBufferOffset
 											bytesPerRow: _mtlBytesPerRow];
-		propogateDebugName();
+		propagateDebugName();
     }
     return _mtlTexture;
 }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index d4ef426..65131c7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -19,8 +19,7 @@
 #pragma once
 
 #include "MVKImage.h"
-#include "MVKVector.h"
-#include <vector>
+#include "MVKSmallVector.h"
 
 class MVKDescriptorSet;
 class MVKDescriptorSetLayout;
@@ -31,9 +30,9 @@
 
 /** Indicates the Metal resource indexes used by a single shader stage in a descriptor. */
 typedef struct MVKShaderStageResourceBinding {
-	uint32_t bufferIndex = 0;
-	uint32_t textureIndex = 0;
-	uint32_t samplerIndex = 0;
+	uint16_t bufferIndex = 0;
+	uint16_t textureIndex = 0;
+	uint16_t samplerIndex = 0;
 
 	MVKShaderStageResourceBinding operator+ (const MVKShaderStageResourceBinding& rhs);
 	MVKShaderStageResourceBinding& operator+= (const MVKShaderStageResourceBinding& rhs);
@@ -47,9 +46,9 @@
 typedef struct MVKShaderResourceBinding {
 	MVKShaderStageResourceBinding stages[kMVKShaderStageMax];
 
-	uint32_t getMaxBufferIndex();
-	uint32_t getMaxTextureIndex();
-	uint32_t getMaxSamplerIndex();
+	uint16_t getMaxBufferIndex();
+	uint16_t getMaxTextureIndex();
+	uint16_t getMaxSamplerIndex();
 
 	MVKShaderResourceBinding operator+ (const MVKShaderResourceBinding& rhs);
 	MVKShaderResourceBinding& operator+= (const MVKShaderResourceBinding& rhs);
@@ -89,7 +88,7 @@
 				  MVKDescriptorSet* descSet,
 				  uint32_t descStartIndex,
 				  MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-				  MVKVector<uint32_t>& dynamicOffsets,
+				  MVKArrayRef<uint32_t> dynamicOffsets,
 				  uint32_t* pDynamicOffsetIndex);
 
     /** Encodes this binding layout and the specified descriptor on the specified command encoder immediately. */
@@ -123,7 +122,7 @@
 
 	MVKDescriptorSetLayout* _layout;
 	VkDescriptorSetLayoutBinding _info;
-	std::vector<MVKSampler*> _immutableSamplers;
+	MVKSmallVector<MVKSampler*> _immutableSamplers;
 	MVKShaderResourceBinding _mtlResourceIndexOffsets;
 	bool _applyToStage[kMVKShaderStageMax];
 };
@@ -148,7 +147,7 @@
 					  uint32_t descriptorIndex,
 					  bool stages[],
 					  MVKShaderResourceBinding& mtlIndexes,
-					  MVKVector<uint32_t>& dynamicOffsets,
+					  MVKArrayRef<uint32_t> dynamicOffsets,
 					  uint32_t* pDynamicOffsetIndex) = 0;
 
 	/**
@@ -202,7 +201,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -280,7 +279,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -319,7 +318,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -391,7 +390,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex);
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -433,7 +432,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -473,7 +472,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
@@ -511,7 +510,7 @@
 			  uint32_t descriptorIndex,
 			  bool stages[],
 			  MVKShaderResourceBinding& mtlIndexes,
-			  MVKVector<uint32_t>& dynamicOffsets,
+			  MVKArrayRef<uint32_t> dynamicOffsets,
 			  uint32_t* pDynamicOffsetIndex) override;
 
 	void write(MVKDescriptorSet* mvkDescSet,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 672b2de..140c31b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -41,15 +41,15 @@
 
 #pragma mark MVKShaderResourceBinding
 
-uint32_t MVKShaderResourceBinding::getMaxBufferIndex() {
+uint16_t MVKShaderResourceBinding::getMaxBufferIndex() {
 	return std::max({stages[kMVKShaderStageVertex].bufferIndex, stages[kMVKShaderStageTessCtl].bufferIndex, stages[kMVKShaderStageTessEval].bufferIndex, stages[kMVKShaderStageFragment].bufferIndex, stages[kMVKShaderStageCompute].bufferIndex});
 }
 
-uint32_t MVKShaderResourceBinding::getMaxTextureIndex() {
+uint16_t MVKShaderResourceBinding::getMaxTextureIndex() {
 	return std::max({stages[kMVKShaderStageVertex].textureIndex, stages[kMVKShaderStageTessCtl].textureIndex, stages[kMVKShaderStageTessEval].textureIndex, stages[kMVKShaderStageFragment].textureIndex, stages[kMVKShaderStageCompute].textureIndex});
 }
 
-uint32_t MVKShaderResourceBinding::getMaxSamplerIndex() {
+uint16_t MVKShaderResourceBinding::getMaxSamplerIndex() {
 	return std::max({stages[kMVKShaderStageVertex].samplerIndex, stages[kMVKShaderStageTessCtl].samplerIndex, stages[kMVKShaderStageTessEval].samplerIndex, stages[kMVKShaderStageFragment].samplerIndex, stages[kMVKShaderStageCompute].samplerIndex});
 }
 
@@ -83,7 +83,7 @@
 											 MVKDescriptorSet* descSet,
 											 uint32_t descStartIndex,
 											 MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-											 MVKVector<uint32_t>& dynamicOffsets,
+											 MVKArrayRef<uint32_t> dynamicOffsets,
 											 uint32_t* pDynamicOffsetIndex) {
 
 	// Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding.
@@ -148,7 +148,11 @@
                 MVKBuffer* buffer = (MVKBuffer*)bufferInfo.buffer;
                 bb.mtlBuffer = buffer->getMTLBuffer();
                 bb.offset = buffer->getMTLBufferOffset() + bufferInfo.offset;
-				bb.size = (uint32_t)buffer->getByteCount();
+                if (bufferInfo.range == VK_WHOLE_SIZE)
+                    bb.size = (uint32_t)(buffer->getByteCount() - bb.offset);
+                else
+                    bb.size = (uint32_t)bufferInfo.range;
+
                 for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
                     if (_applyToStage[i]) {
                         bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
@@ -185,33 +189,32 @@
             case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
                 const auto& imageInfo = get<VkDescriptorImageInfo>(pData, stride, rezIdx - dstArrayElement);
                 MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
-                tb.mtlTexture = imageView->getMTLTexture();
-                if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) {
-                    tb.swizzle = imageView->getPackedSwizzle();
-                } else {
-                    tb.swizzle = 0;
-                }
-                if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
-                    id<MTLTexture> mtlTex = tb.mtlTexture;
-                    if (mtlTex.parentTexture) { mtlTex = mtlTex.parentTexture; }
-                    bb.mtlBuffer = mtlTex.buffer;
-                    bb.offset = mtlTex.bufferOffset;
-                    bb.size = (uint32_t)(mtlTex.height * mtlTex.bufferBytesPerRow);
-                }
-                for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
-                    if (_applyToStage[i]) {
-                        tb.index = mtlIdxs.stages[i].textureIndex + rezIdx;
-                        if (i == kMVKShaderStageCompute) {
-							if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
-                        } else {
-							if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
-                        }
-                        if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
-                            bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
+                uint8_t planeCount = (imageView) ? imageView->getPlaneCount() : 1;
+                for (uint8_t planeIndex = 0; planeIndex < planeCount; planeIndex++) {
+                    tb.mtlTexture = imageView->getMTLTexture(planeIndex);
+                    tb.swizzle = (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ? imageView->getPackedSwizzle() : 0;
+                    if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
+                        id<MTLTexture> mtlTex = tb.mtlTexture;
+                        if (mtlTex.parentTexture) { mtlTex = mtlTex.parentTexture; }
+                        bb.mtlBuffer = mtlTex.buffer;
+                        bb.offset = mtlTex.bufferOffset;
+                        bb.size = (uint32_t)(mtlTex.height * mtlTex.bufferBytesPerRow);
+                    }
+                    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
+                        if (_applyToStage[i]) {
+                            tb.index = mtlIdxs.stages[i].textureIndex + rezIdx + planeIndex;
                             if (i == kMVKShaderStageCompute) {
-                                if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
+                                if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
                             } else {
-                                if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); }
+                                if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
+                            }
+                            if (_info.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
+                                bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
+                                if (i == kMVKShaderStageCompute) {
+                                    if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
+                                } else {
+                                    if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); }
+                                }
                             }
                         }
                     }
@@ -276,30 +279,29 @@
             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
                 const auto& imageInfo = get<VkDescriptorImageInfo>(pData, stride, rezIdx - dstArrayElement);
                 MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
-                tb.mtlTexture = imageView->getMTLTexture();
-                if (imageView) {
-                    tb.swizzle = imageView->getPackedSwizzle();
-                } else {
-                    tb.swizzle = 0;
-                }
-				MVKSampler* sampler;
-				if (_immutableSamplers.empty()) {
-					sampler = (MVKSampler*)imageInfo.sampler;
-					validate(sampler);
-				} else {
-					sampler = _immutableSamplers[rezIdx];
-				}
-                sb.mtlSamplerState = sampler->getMTLSamplerState();
-                for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
-                    if (_applyToStage[i]) {
-                        tb.index = mtlIdxs.stages[i].textureIndex + rezIdx;
-                        sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx;
-                        if (i == kMVKShaderStageCompute) {
-							if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
-							if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); }
-                        } else {
-							if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
-							if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); }
+                uint8_t planeCount = (imageView) ? imageView->getPlaneCount() : 1;
+                for (uint8_t planeIndex = 0; planeIndex < planeCount; planeIndex++) {
+                    tb.mtlTexture = imageView->getMTLTexture(planeIndex);
+                    tb.swizzle = (imageView) ? imageView->getPackedSwizzle() : 0;
+                    MVKSampler* sampler;
+                    if (_immutableSamplers.empty()) {
+                        sampler = (MVKSampler*)imageInfo.sampler;
+                        validate(sampler);
+                    } else {
+                        sampler = _immutableSamplers[rezIdx];
+                    }
+                    sb.mtlSamplerState = sampler->getMTLSamplerState();
+                    for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
+                        if (_applyToStage[i]) {
+                            tb.index = mtlIdxs.stages[i].textureIndex + rezIdx + planeIndex;
+                            sb.index = mtlIdxs.stages[i].samplerIndex + rezIdx;
+                            if (i == kMVKShaderStageCompute) {
+                                if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
+                                if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindSamplerState(sb); }
+                            } else {
+                                if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
+                                if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindSamplerState(MVKShaderStage(i), sb); }
+                            }
                         }
                     }
                 }
@@ -323,7 +325,7 @@
 // If depth compare is required, but unavailable on the device, the sampler can only be used as an immutable sampler
 bool MVKDescriptorSetLayoutBinding::validate(MVKSampler* mvkSampler) {
 	if (mvkSampler->getRequiresConstExprSampler()) {
-		mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdPushDescriptorSet/vkCmdPushDescriptorSetWithTemplate(): Depth texture samplers using a compare operation can only be used as immutable samplers on this device.");
+		mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdPushDescriptorSet/vkCmdPushDescriptorSetWithTemplate(): Tried to push an immutable sampler.");
 		return false;
 	}
 	return true;
@@ -433,7 +435,19 @@
 				if ( !_device->_pMetalFeatures->arrayOfSamplers ) {
 					_layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Device %s does not support arrays of samplers.", _device->getName()));
 				}
+                if ( pBinding->pImmutableSamplers ) {
+                    _layout->setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Sampler arrays contaning multi planar samplers are not supported."));
+                }
 			}
+
+            if ( pBinding->pImmutableSamplers ) {
+                for (uint32_t i = 0; i < pBinding->descriptorCount; i++) {
+                    uint8_t planeCount = ((MVKSampler*)pBinding->pImmutableSamplers[i])->getPlaneCount();
+                    if (planeCount > 1) {
+                        pDescSetCounts->textureIndex += planeCount - 1;
+                    }
+                }
+            }
             break;
 
         case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
@@ -476,7 +490,7 @@
 							   uint32_t descriptorIndex,
 							   bool stages[],
 							   MVKShaderResourceBinding& mtlIndexes,
-							   MVKVector<uint32_t>& dynamicOffsets,
+							   MVKArrayRef<uint32_t> dynamicOffsets,
 							   uint32_t* pDynamicOffsetIndex) {
 	MVKMTLBufferBinding bb;
 	NSUInteger bufferDynamicOffset = 0;
@@ -485,14 +499,18 @@
 		// After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
-			bufferDynamicOffset = dynamicOffsets[*pDynamicOffsetIndex];
-			(*pDynamicOffsetIndex)++;           // Move on to next dynamic offset (and feedback to caller)
+			if (dynamicOffsets.size > *pDynamicOffsetIndex) {
+				bufferDynamicOffset = dynamicOffsets[(*pDynamicOffsetIndex)++];	// Move on to next dynamic offset (and feedback to caller)
+			}
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 		case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
 			if (_mvkBuffer) {
 				bb.mtlBuffer = _mvkBuffer->getMTLBuffer();
 				bb.offset = _mvkBuffer->getMTLBufferOffset() + _buffOffset + bufferDynamicOffset;
-				bb.size = (uint32_t)_mvkBuffer->getByteCount();
+				if (_buffRange == VK_WHOLE_SIZE)
+					bb.size = (uint32_t)(_mvkBuffer->getByteCount() - bb.offset);
+				else
+					bb.size = (uint32_t)_buffRange;
 			}
 			for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
 				if (stages[i]) {
@@ -577,12 +595,12 @@
 
 // A null cmdEncoder can be passed to perform a validation pass
 void MVKInlineUniformBlockDescriptor::bind(MVKCommandEncoder* cmdEncoder,
-									  VkDescriptorType descriptorType,
-									  uint32_t descriptorIndex,
-									  bool stages[],
-									  MVKShaderResourceBinding& mtlIndexes,
-									  MVKVector<uint32_t>& dynamicOffsets,
-									  uint32_t* pDynamicOffsetIndex) {
+										   VkDescriptorType descriptorType,
+										   uint32_t descriptorIndex,
+										   bool stages[],
+										   MVKShaderResourceBinding& mtlIndexes,
+										   MVKArrayRef<uint32_t> dynamicOffsets,
+										   uint32_t* pDynamicOffsetIndex) {
 	MVKMTLBufferBinding bb;
 
 	switch (descriptorType) {
@@ -678,55 +696,56 @@
 							  uint32_t descriptorIndex,
 							  bool stages[],
 							  MVKShaderResourceBinding& mtlIndexes,
-							  MVKVector<uint32_t>& dynamicOffsets,
+							  MVKArrayRef<uint32_t> dynamicOffsets,
 							  uint32_t* pDynamicOffsetIndex) {
-	MVKMTLTextureBinding tb;
-	MVKMTLBufferBinding bb;
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
 		case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
 		case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
-		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
-			if (_mvkImageView) {
-				tb.mtlTexture = _mvkImageView->getMTLTexture();
-			}
-			if ((descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
-				tb.mtlTexture) {
-				tb.swizzle = _mvkImageView->getPackedSwizzle();
-			} else {
-				tb.swizzle = 0;
-			}
-			if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && tb.mtlTexture) {
-				id<MTLTexture> mtlTex = tb.mtlTexture;
-				if (mtlTex.parentTexture) { mtlTex = mtlTex.parentTexture; }
-				bb.mtlBuffer = mtlTex.buffer;
-				bb.offset = mtlTex.bufferOffset;
-				bb.size = (uint32_t)(mtlTex.height * mtlTex.bufferBytesPerRow);
-			}
-			for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
-				if (stages[i]) {
-					tb.index = mtlIndexes.stages[i].textureIndex + descriptorIndex;
-					if (i == kMVKShaderStageCompute) {
-						if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
-					} else {
-						if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
-					}
-					if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
-						bb.index = mtlIndexes.stages[i].bufferIndex + descriptorIndex;
-						if (i == kMVKShaderStageCompute) {
-							if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
-						} else {
-							if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); }
-						}
-					}
-				}
-			}
+		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
 			break;
-		}
 
 		default:
-			break;
+			return;
 	}
+    
+    uint8_t planeCount = (_mvkImageView) ? _mvkImageView->getPlaneCount() : 1;
+    for (uint8_t planeIndex = 0; planeIndex < planeCount; planeIndex++) {
+        MVKMTLTextureBinding tb;
+        MVKMTLBufferBinding bb;
+        
+        if (_mvkImageView) {
+            tb.mtlTexture = _mvkImageView->getMTLTexture(planeIndex);
+        }
+        tb.swizzle = ((descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
+                       descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
+                       tb.mtlTexture) ? _mvkImageView->getPackedSwizzle() : 0;
+        if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE && tb.mtlTexture) {
+            id<MTLTexture> mtlTex = tb.mtlTexture;
+            if (mtlTex.parentTexture) { mtlTex = mtlTex.parentTexture; }
+            bb.mtlBuffer = mtlTex.buffer;
+            bb.offset = mtlTex.bufferOffset;
+            bb.size = (uint32_t)(mtlTex.height * mtlTex.bufferBytesPerRow);
+        }
+        for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
+            if (stages[i]) {
+                tb.index = mtlIndexes.stages[i].textureIndex + descriptorIndex + planeIndex;
+                if (i == kMVKShaderStageCompute) {
+                    if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindTexture(tb); }
+                } else {
+                    if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindTexture(MVKShaderStage(i), tb); }
+                }
+                if (descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
+                    bb.index = mtlIndexes.stages[i].bufferIndex + descriptorIndex + planeIndex;
+                    if (i == kMVKShaderStageCompute) {
+                        if (cmdEncoder) { cmdEncoder->_computeResourcesState.bindBuffer(bb); }
+                    } else {
+                        if (cmdEncoder) { cmdEncoder->_graphicsResourcesState.bindBuffer(MVKShaderStage(i), bb); }
+                    }
+                }
+            }
+        }
+    }
 }
 
 void MVKImageDescriptor::write(MVKDescriptorSet* mvkDescSet,
@@ -796,7 +815,7 @@
 									 uint32_t descriptorIndex,
 									 bool stages[],
 									 MVKShaderResourceBinding& mtlIndexes,
-									 MVKVector<uint32_t>& dynamicOffsets,
+									 MVKArrayRef<uint32_t> dynamicOffsets,
 									 uint32_t* pDynamicOffsetIndex) {
 	MVKMTLSamplerStateBinding sb;
 	switch (descriptorType) {
@@ -837,7 +856,7 @@
 				const auto* pImgInfo = &get<VkDescriptorImageInfo>(pData, stride, srcIndex);
 				_mvkSampler = (MVKSampler*)pImgInfo->sampler;
 				if (_mvkSampler && _mvkSampler->getRequiresConstExprSampler()) {
-					_mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkUpdateDescriptorSets(): Depth texture samplers using a compare operation can only be used as immutable samplers on this device.");
+					_mvkSampler->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkUpdateDescriptorSets(): Tried to push an immutable sampler.");
 				}
 
 				if (_mvkSampler) { _mvkSampler->retain(); }
@@ -914,7 +933,7 @@
 								uint32_t descriptorIndex,
 								bool stages[],
 								MVKShaderResourceBinding& mtlIndexes,
-								MVKVector<uint32_t>& dynamicOffsets,
+								MVKArrayRef<uint32_t> dynamicOffsets,
 								uint32_t* pDynamicOffsetIndex) {
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_SAMPLER: {
@@ -983,7 +1002,7 @@
 											 uint32_t descriptorIndex,
 											 bool stages[],
 											 MVKShaderResourceBinding& mtlIndexes,
-											 MVKVector<uint32_t>& dynamicOffsets,
+											 MVKArrayRef<uint32_t> dynamicOffsets,
 											 uint32_t* pDynamicOffsetIndex) {
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
@@ -1057,7 +1076,7 @@
 									uint32_t descriptorIndex,
 									bool stages[],
 									MVKShaderResourceBinding& mtlIndexes,
-									MVKVector<uint32_t>& dynamicOffsets,
+									MVKArrayRef<uint32_t> dynamicOffsets,
 									uint32_t* pDynamicOffsetIndex) {
 	MVKMTLTextureBinding tb;
 	MVKMTLBufferBinding bb;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 51756a3..532c14f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -19,6 +19,7 @@
 #pragma once
 
 #include "MVKDescriptor.h"
+#include "MVKSmallVector.h"
 #include <unordered_set>
 #include <unordered_map>
 #include <vector>
@@ -46,13 +47,13 @@
     void bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
                            MVKDescriptorSet* descSet,
                            MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                           MVKVector<uint32_t>& dynamicOffsets,
+                           MVKArrayRef<uint32_t> dynamicOffsets,
                            uint32_t* pDynamicOffsetIndex);
 
 
 	/** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */
 	void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
-						   MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+						   MVKArrayRef<VkWriteDescriptorSet>& descriptorWrites,
 						   MVKShaderResourceBinding& dslMTLRezIdxOffsets);
 
 
@@ -80,12 +81,12 @@
 	friend class MVKDescriptorSet;
 	friend class MVKDescriptorPool;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	inline uint32_t getDescriptorCount() { return _descriptorCount; }
 	uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex);
 	inline MVKDescriptorSetLayoutBinding* getBinding(uint32_t binding) { return &_bindings[_bindingToIndex[binding]]; }
 
-	std::vector<MVKDescriptorSetLayoutBinding> _bindings;
+	MVKSmallVector<MVKDescriptorSetLayoutBinding> _bindings;
 	std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
 	MVKShaderResourceBinding _mtlResourceCounts;
 	uint32_t _descriptorCount;
@@ -132,12 +133,12 @@
 	friend class MVKDescriptorSetLayoutBinding;
 	friend class MVKDescriptorPool;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	inline MVKDescriptor* getDescriptor(uint32_t index) { return _descriptors[index]; }
 
 	MVKDescriptorSetLayout* _layout;
 	MVKDescriptorPool* _pool;
-	std::vector<MVKDescriptor*> _descriptors;
+	MVKSmallVector<MVKDescriptor*> _descriptors;
 };
 
 
@@ -164,8 +165,8 @@
 	void freeDescriptor(MVKDescriptor* mvkDesc);
 	void reset();
 
-	std::vector<DescriptorClass> _descriptors;
-	std::vector<bool> _availability;
+	MVKSmallVector<DescriptorClass> _descriptors;
+	MVKSmallVector<bool> _availability;
 	uint32_t _nextAvailableIndex;
 	bool _supportAvailability;
 };
@@ -228,7 +229,7 @@
 	/** Free's up the specified descriptor set. */
 	VkResult freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets);
 
-	/** Destoys all currently allocated descriptor sets. */
+	/** Destroys all currently allocated descriptor sets. */
 	VkResult reset(VkDescriptorPoolResetFlags flags);
 
 	MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo);
@@ -238,7 +239,7 @@
 protected:
 	friend class MVKDescriptorSet;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	VkResult allocateDescriptorSet(MVKDescriptorSetLayout* mvkDSL, VkDescriptorSet* pVKDS);
 	void freeDescriptorSet(MVKDescriptorSet* mvkDS);
 	VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc);
@@ -280,10 +281,10 @@
 	~MVKDescriptorUpdateTemplate() override = default;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 	VkDescriptorUpdateTemplateTypeKHR _type;
-	MVKVectorInline<VkDescriptorUpdateTemplateEntryKHR, 1> _entries;
+	MVKSmallVector<VkDescriptorUpdateTemplateEntryKHR, 1> _entries;
 };
 
 #pragma mark -
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index a433703..32decbd 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -38,12 +38,12 @@
 void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
                                                MVKDescriptorSet* descSet,
                                                MVKShaderResourceBinding& dslMTLRezIdxOffsets,
-                                               MVKVector<uint32_t>& dynamicOffsets,
+                                               MVKArrayRef<uint32_t> dynamicOffsets,
                                                uint32_t* pDynamicOffsetIndex) {
     if (_isPushDescriptorLayout) return;
 
 	clearConfigurationResult();
-    uint32_t bindCnt = (uint32_t)_bindings.size();
+    size_t bindCnt = _bindings.size();
     for (uint32_t descIdx = 0, bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
 		descIdx += _bindings[bindIdx].bind(cmdEncoder, descSet, descIdx,
 										   dslMTLRezIdxOffsets, dynamicOffsets,
@@ -94,7 +94,7 @@
 
 // A null cmdEncoder can be passed to perform a validation pass
 void MVKDescriptorSetLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
-                                               MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+                                               MVKArrayRef<VkWriteDescriptorSet>& descriptorWrites,
                                                MVKShaderResourceBinding& dslMTLRezIdxOffsets) {
 
     if (!_isPushDescriptorLayout) return;
@@ -109,11 +109,10 @@
         const VkBufferView* pTexelBufferView = descWrite.pTexelBufferView;
         const VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock = nullptr;
         if (_device->_enabledExtensions.vk_EXT_inline_uniform_block.enabled) {
-            for (auto* next = (VkWriteDescriptorSetInlineUniformBlockEXT*)descWrite.pNext; next; next = (VkWriteDescriptorSetInlineUniformBlockEXT*)next->pNext)
-            {
+			for (const auto* next = (VkBaseInStructure*)descWrite.pNext; next; next = next->pNext) {
                 switch (next->sType) {
                 case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: {
-                    pInlineUniformBlock = next;
+					pInlineUniformBlock = (VkWriteDescriptorSetInlineUniformBlockEXT*)next;
                     break;
                 }
                 default:
@@ -570,7 +569,7 @@
 		return _preallocatedDescriptors->allocateDescriptor(descriptorType, pMVKDesc);
 	}
 
-	// Otherwise instantiate one of the apporpriate type now
+	// Otherwise instantiate one of the appropriate type now
 	switch (descriptorType) {
 		case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
 			*pMVKDesc = new MVKUniformBufferDescriptor();
@@ -689,11 +688,10 @@
 
 		const VkWriteDescriptorSetInlineUniformBlockEXT* pInlineUniformBlock = nullptr;
 		if (dstSet->getDevice()->_enabledExtensions.vk_EXT_inline_uniform_block.enabled) {
-			for (auto* next = (VkWriteDescriptorSetInlineUniformBlockEXT*)pDescWrite->pNext; next; next = (VkWriteDescriptorSetInlineUniformBlockEXT*)next->pNext)
-			{
+			for (const auto* next = (VkBaseInStructure*)pDescWrite->pNext; next; next = next->pNext) {
 				switch (next->sType) {
 				case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT: {
-					pInlineUniformBlock = next;
+					pInlineUniformBlock = (VkWriteDescriptorSetInlineUniformBlockEXT*)next;
 					break;
 				}
 				default:
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index c9527f0..760bc93 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -20,9 +20,10 @@
 
 #include "MVKFoundation.h"
 #include "MVKVulkanAPIObject.h"
+#include "MVKMTLResourceBindings.h"
 #include "MVKLayers.h"
 #include "MVKObjectPool.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include "MVKPixelFormats.h"
 #include "MVKOSExtensions.h"
 #include "mvk_datatypes.hpp"
@@ -56,6 +57,7 @@
 class MVKPipelineLayout;
 class MVKPipeline;
 class MVKSampler;
+class MVKSamplerYcbcrConversion;
 class MVKDescriptorSetLayout;
 class MVKDescriptorPool;
 class MVKDescriptorUpdateTemplate;
@@ -117,12 +119,9 @@
 	void getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties);
 
 	/** Populates the specified structure with the format properties of this device. */
-	void getFormatProperties(VkFormat format, VkFormatProperties2KHR* pFormatProperties);
+	void getFormatProperties(VkFormat format, VkFormatProperties2* pFormatProperties);
 
-    /** 
-     * Populates the specified structure with the image format properties
-     * supported for the specified image characteristics on this device.
-     */
+	/** Populates the image format properties supported on this device. */
     VkResult getImageFormatProperties(VkFormat format,
                                       VkImageType type,
                                       VkImageTiling tiling,
@@ -130,12 +129,13 @@
                                       VkImageCreateFlags flags,
                                       VkImageFormatProperties* pImageFormatProperties);
 
-    /** 
-     * Populates the specified structure with the image format properties
-     * supported for the specified image characteristics on this device.
-     */
-    VkResult getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
-                                      VkImageFormatProperties2KHR* pImageFormatProperties);
+    /** Populates the image format properties supported on this device. */
+    VkResult getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+                                      VkImageFormatProperties2* pImageFormatProperties);
+
+	/** Populates the external buffer properties supported on this device. */
+	void getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+									 VkExternalBufferProperties* pExternalBufferProperties);
 
 #pragma mark Surfaces
 
@@ -244,13 +244,13 @@
 #pragma mark Memory models
 
 	/** Returns a pointer to the memory characteristics of this device. */
-    inline const VkPhysicalDeviceMemoryProperties* getPhysicalDeviceMemoryProperties() { return &_memoryProperties; }
+    inline const VkPhysicalDeviceMemoryProperties* getMemoryProperties() { return &_memoryProperties; }
 
 	/** Populates the specified memory properties with the memory characteristics of this device. */
-	VkResult getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMemoryProperties* pMemoryProperties);
+	VkResult getMemoryProperties(VkPhysicalDeviceMemoryProperties* pMemoryProperties);
 
 	/** Populates the specified memory properties with the memory characteristics of this device. */
-	VkResult getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+	VkResult getMemoryProperties(VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
 
 	/**
 	 * Returns a bit mask of all memory type indices. 
@@ -285,6 +285,12 @@
 	/** Returns whether this is a unified memory device. */
 	bool getHasUnifiedMemory();
 
+	/** Returns the external memory properties supported for buffers for the handle type. */
+	VkExternalMemoryProperties& getExternalBufferProperties(VkExternalMemoryHandleTypeFlagBits handleType);
+
+	/** Returns the external memory properties supported for images for the handle type. */
+	VkExternalMemoryProperties& getExternalImageProperties(VkExternalMemoryHandleTypeFlagBits handleType);
+
 	
 #pragma mark Metal
 
@@ -327,7 +333,7 @@
 protected:
 	friend class MVKDevice;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	MTLFeatureSet getMaximalMTLFeatureSet();
     void initMetalFeatures();
 	void initFeatures();
@@ -339,12 +345,14 @@
 	uint64_t getVRAMSize();
 	uint64_t getRecommendedMaxWorkingSetSize();
 	uint64_t getCurrentAllocatedSize();
+	void initExternalMemoryProperties();
 	void initExtensions();
-	MVKVector<MVKQueueFamily*>& getQueueFamilies();
+	MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
 	void initPipelineCacheUUID();
 	uint32_t getHighestMTLFeatureSet();
 	uint64_t getSpirvCrossRevision();
-	bool getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo);
+	bool getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo);
+	void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
 	void logGPUInfo();
 
 	id<MTLDevice> _mtlDevice;
@@ -355,13 +363,15 @@
 	VkPhysicalDeviceProperties _properties;
 	VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT _texelBuffAlignProperties;
 	VkPhysicalDeviceMemoryProperties _memoryProperties;
-	MVKVectorInline<MVKQueueFamily*, kMVKQueueFamilyCount> _queueFamilies;
+	MVKSmallVector<MVKQueueFamily*, kMVKQueueFamilyCount> _queueFamilies;
 	MVKPixelFormats _pixelFormats;
 	uint32_t _allMemoryTypes;
 	uint32_t _hostVisibleMemoryTypes;
 	uint32_t _hostCoherentMemoryTypes;
 	uint32_t _privateMemoryTypes;
 	uint32_t _lazilyAllocatedMemoryTypes;
+	VkExternalMemoryProperties _mtlBufferExternalMemoryProperties;
+	VkExternalMemoryProperties _mtlTextureExternalMemoryProperties;
 };
 
 
@@ -512,6 +522,11 @@
 	void destroySampler(MVKSampler* mvkSamp,
 						const VkAllocationCallbacks* pAllocator);
 
+	MVKSamplerYcbcrConversion* createSamplerYcbcrConversion(const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+										                    const VkAllocationCallbacks* pAllocator);
+	void destroySamplerYcbcrConversion(MVKSamplerYcbcrConversion* mvkSampConv,
+								       const VkAllocationCallbacks* pAllocator);
+
 	MVKDescriptorSetLayout* createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
 													  const VkAllocationCallbacks* pAllocator);
 	void destroyDescriptorSetLayout(MVKDescriptorSetLayout* mvkDSL,
@@ -553,9 +568,9 @@
 	/** Applies the specified global memory barrier to all resource issued by this device. */
 	void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
 							VkPipelineStageFlags dstStageMask,
-							VkMemoryBarrier* pMemoryBarrier,
-                            MVKCommandEncoder* cmdEncoder,
-                            MVKCommandUse cmdUse);
+							MVKPipelineBarrier& barrier,
+							MVKCommandEncoder* cmdEncoder,
+							MVKCommandUse cmdUse);
 
     /**
 	 * If performance is being tracked, returns a monotonic timestamp value for use performance timestamping.
@@ -643,6 +658,7 @@
 	const VkPhysicalDeviceVariablePointerFeatures _enabledVarPtrFeatures;
 	const VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT _enabledInterlockFeatures;
 	const VkPhysicalDeviceHostQueryResetFeaturesEXT _enabledHostQryResetFeatures;
+	const VkPhysicalDeviceSamplerYcbcrConversionFeatures _enabledSamplerYcbcrConversionFeatures;
 	const VkPhysicalDeviceScalarBlockLayoutFeaturesEXT _enabledScalarLayoutFeatures;
 	const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT _enabledTexelBuffAlignFeatures;
 	const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT _enabledVtxAttrDivFeatures;
@@ -686,7 +702,7 @@
     }
 
 protected:
-	void propogateDebugName() override  {}
+	void propagateDebugName() override  {}
 	MVKResource* addResource(MVKResource* rez);
 	MVKResource* removeResource(MVKResource* rez);
     void initPerformanceTracking();
@@ -703,8 +719,8 @@
 	MVKPhysicalDevice* _physicalDevice;
     MVKCommandResourceFactory* _commandResourceFactory;
 	MTLCompileOptions* _mtlCompileOptions;
-	MVKVectorInline<MVKVectorInline<MVKQueue*, kMVKQueueCountPerQueueFamily>, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex;
-	MVKVectorInline<MVKResource*, 256> _resources;
+	MVKSmallVector<MVKSmallVector<MVKQueue*, kMVKQueueCountPerQueueFamily>, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex;
+	MVKSmallVector<MVKResource*, 256> _resources;
 	std::mutex _rezLock;
     std::mutex _perfLock;
     id<MTLBuffer> _globalVisibilityResultMTLBuffer;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 4713c8d..a5ae030 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -62,172 +62,232 @@
 }
 
 void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures* features) {
-    if (features) { *features = _features; }
+    *features = _features;
 }
 
 void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
-    if (features) {
-        features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-        features->features = _features;
-        for (auto* next = (VkBaseOutStructure*)features->pNext; next; next = next->pNext) {
-            switch ((uint32_t)next->sType) {
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
-                    auto* storageFeatures = (VkPhysicalDevice16BitStorageFeatures*)next;
-                    storageFeatures->storageBuffer16BitAccess = true;
-                    storageFeatures->uniformAndStorageBuffer16BitAccess = true;
-                    storageFeatures->storagePushConstant16 = true;
-                    storageFeatures->storageInputOutput16 = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR: {
-                    auto* storageFeatures = (VkPhysicalDevice8BitStorageFeaturesKHR*)next;
-                    storageFeatures->storageBuffer8BitAccess = true;
-                    storageFeatures->uniformAndStorageBuffer8BitAccess = true;
-                    storageFeatures->storagePushConstant8 = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR: {
-                    auto* f16Features = (VkPhysicalDeviceFloat16Int8FeaturesKHR*)next;
-                    f16Features->shaderFloat16 = true;
-                    f16Features->shaderInt8 = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
-                    auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
-                    uboLayoutFeatures->uniformBufferStandardLayout = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES: {
-                    auto* varPtrFeatures = (VkPhysicalDeviceVariablePointerFeatures*)next;
-                    varPtrFeatures->variablePointersStorageBuffer = true;
-                    varPtrFeatures->variablePointers = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
-                    auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
-                    interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
-                    interlockFeatures->fragmentShaderPixelInterlock = _metalFeatures.rasterOrderGroups;
-                    interlockFeatures->fragmentShaderShadingRateInterlock = false;    // Requires variable rate shading; not supported yet in Metal
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: {
-                    auto* hostQueryResetFeatures = (VkPhysicalDeviceHostQueryResetFeaturesEXT*)next;
-                    hostQueryResetFeatures->hostQueryReset = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT: {
-                    auto* scalarLayoutFeatures = (VkPhysicalDeviceScalarBlockLayoutFeaturesEXT*)next;
-                    scalarLayoutFeatures->scalarBlockLayout = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: {
-                    auto* texelBuffAlignFeatures = (VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT*)next;
-                    texelBuffAlignFeatures->texelBufferAlignment = _metalFeatures.texelBuffers && [_mtlDevice respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)];
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
-                    auto* divisorFeatures = (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT*)next;
-                    divisorFeatures->vertexAttributeInstanceRateDivisor = true;
-                    divisorFeatures->vertexAttributeInstanceRateZeroDivisor = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: {
-                    auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
-					portabilityFeatures->constantAlphaColorBlendFactors = true;
-                    portabilityFeatures->triangleFans = false;
-					portabilityFeatures->pointPolygons = false;
-                    portabilityFeatures->separateStencilMaskRef = true;
-					portabilityFeatures->events = true;
-                    portabilityFeatures->standardImageViews = _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle || _metalFeatures.nativeTextureSwizzle;
-                    portabilityFeatures->samplerMipLodBias = false;
-					portabilityFeatures->mutableComparisonSamplers = _metalFeatures.depthSampleCompare;
-					portabilityFeatures->tessellationIsolines = false;
-					portabilityFeatures->tessellationPointMode = false;
-					portabilityFeatures->shaderSampleRateInterpolationFunctions = false;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
-                    auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
-                    shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
-                    break;
-                }
-                case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: {
-                    auto* inlineUniformBlockFeatures = (VkPhysicalDeviceInlineUniformBlockFeaturesEXT*)next;
-                    inlineUniformBlockFeatures->inlineUniformBlock = true;
-                    inlineUniformBlockFeatures->descriptorBindingInlineUniformBlockUpdateAfterBind = true;
-                    break;
-                }
-                default:
-                    break;
-            }
-        }
-    }
+	features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+	features->features = _features;
+	for (auto* next = (VkBaseOutStructure*)features->pNext; next; next = next->pNext) {
+		switch ((uint32_t)next->sType) {
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: {
+				auto* storageFeatures = (VkPhysicalDevice16BitStorageFeatures*)next;
+				storageFeatures->storageBuffer16BitAccess = true;
+				storageFeatures->uniformAndStorageBuffer16BitAccess = true;
+				storageFeatures->storagePushConstant16 = true;
+				storageFeatures->storageInputOutput16 = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR: {
+				auto* storageFeatures = (VkPhysicalDevice8BitStorageFeaturesKHR*)next;
+				storageFeatures->storageBuffer8BitAccess = true;
+				storageFeatures->uniformAndStorageBuffer8BitAccess = true;
+				storageFeatures->storagePushConstant8 = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR: {
+				auto* f16Features = (VkPhysicalDeviceFloat16Int8FeaturesKHR*)next;
+				f16Features->shaderFloat16 = true;
+				f16Features->shaderInt8 = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
+				auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
+				uboLayoutFeatures->uniformBufferStandardLayout = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES: {
+				auto* varPtrFeatures = (VkPhysicalDeviceVariablePointerFeatures*)next;
+				varPtrFeatures->variablePointersStorageBuffer = true;
+				varPtrFeatures->variablePointers = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: {
+				auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next;
+				interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups;
+				interlockFeatures->fragmentShaderPixelInterlock = _metalFeatures.rasterOrderGroups;
+				interlockFeatures->fragmentShaderShadingRateInterlock = false;    // Requires variable rate shading; not supported yet in Metal
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: {
+				auto* hostQueryResetFeatures = (VkPhysicalDeviceHostQueryResetFeaturesEXT*)next;
+				hostQueryResetFeatures->hostQueryReset = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT: {
+				auto* scalarLayoutFeatures = (VkPhysicalDeviceScalarBlockLayoutFeaturesEXT*)next;
+				scalarLayoutFeatures->scalarBlockLayout = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT: {
+				auto* texelBuffAlignFeatures = (VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT*)next;
+				texelBuffAlignFeatures->texelBufferAlignment = _metalFeatures.texelBuffers && [_mtlDevice respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)];
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
+				auto* divisorFeatures = (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT*)next;
+				divisorFeatures->vertexAttributeInstanceRateDivisor = true;
+				divisorFeatures->vertexAttributeInstanceRateZeroDivisor = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: {
+				auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
+				portabilityFeatures->constantAlphaColorBlendFactors = true;
+				portabilityFeatures->triangleFans = false;
+				portabilityFeatures->pointPolygons = false;
+				portabilityFeatures->separateStencilMaskRef = true;
+				portabilityFeatures->events = true;
+				portabilityFeatures->standardImageViews = _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle || _metalFeatures.nativeTextureSwizzle;
+				portabilityFeatures->samplerMipLodBias = false;
+				portabilityFeatures->mutableComparisonSamplers = _metalFeatures.depthSampleCompare;
+				portabilityFeatures->tessellationIsolines = false;
+				portabilityFeatures->tessellationPointMode = false;
+				portabilityFeatures->shaderSampleRateInterpolationFunctions = false;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
+				auto* samplerYcbcrConvFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
+				samplerYcbcrConvFeatures->samplerYcbcrConversion = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
+				auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
+				shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT: {
+				auto* inlineUniformBlockFeatures = (VkPhysicalDeviceInlineUniformBlockFeaturesEXT*)next;
+				inlineUniformBlockFeatures->inlineUniformBlock = true;
+				inlineUniformBlockFeatures->descriptorBindingInlineUniformBlockUpdateAfterBind = true;
+				break;
+			}
+			default:
+				break;
+		}
+	}
 }
 
 void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties* properties) {
-    if (properties) { *properties = _properties; }
+	*properties = _properties;
 }
 
 void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
-    if (properties) {
-        properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-        properties->properties = _properties;
-		for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
-			switch ((uint32_t)next->sType) {
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
-                auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
-                pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
-                break;
-            }
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
-                auto* maint3Props = (VkPhysicalDeviceMaintenance3Properties*)next;
-                maint3Props->maxPerSetDescriptors = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount + _metalFeatures.maxPerStageSamplerCount) * 4;
-                maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
-                break;
-            }
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
-                auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
-                pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
-                break;
-            }
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
-                auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
-                // Save the 'next' pointer; we'll unintentionally overwrite it
-                // on the next line. Put it back when we're done.
-                void* savedNext = texelBuffAlignProps->pNext;
-                *texelBuffAlignProps = _texelBuffAlignProperties;
-                texelBuffAlignProps->pNext = savedNext;
-                break;
-            }
-            case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
-                auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
-                divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
-                break;
-            }
+	properties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+	properties->properties = _properties;
+	for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
+		switch ((uint32_t)next->sType) {
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
+				auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
+				pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
+				auto* maint3Props = (VkPhysicalDeviceMaintenance3Properties*)next;
+				maint3Props->maxPerSetDescriptors = (_metalFeatures.maxPerStageBufferCount + _metalFeatures.maxPerStageTextureCount + _metalFeatures.maxPerStageSamplerCount) * 4;
+				maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
+				auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
+				pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
+				auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
+				// Save the 'next' pointer; we'll unintentionally overwrite it
+				// on the next line. Put it back when we're done.
+				void* savedNext = texelBuffAlignProps->pNext;
+				*texelBuffAlignProps = _texelBuffAlignProperties;
+				texelBuffAlignProps->pNext = savedNext;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
+				auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
+				divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
+				populate((VkPhysicalDeviceIDProperties*)next);
+				break;
+			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
 				auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
 				portabilityProps->minVertexInputBindingStrideAlignment = 4;
 				break;
 			}
-            default:
-                break;
-            }
-        }
-    }
+			case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: {
+				auto* samplerYcbcrConvProps = (VkSamplerYcbcrConversionImageFormatProperties*)next;
+				samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = 3;
+				break;
+			}
+			default:
+				break;
+		}
+	}
+}
+
+// Populates the device ID properties structure
+void MVKPhysicalDevice::populate(VkPhysicalDeviceIDProperties* pDevIdProps) {
+
+	uint8_t* uuid;
+	size_t uuidComponentOffset;
+
+	//  ---- Device ID ----------------------------------------------
+	uuid = pDevIdProps->deviceUUID;
+	uuidComponentOffset = 0;
+	mvkClear(uuid, VK_UUID_SIZE);
+
+	// First 4 bytes contains GPU vendor ID
+	uint32_t vendorID = _properties.vendorID;
+	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(vendorID);
+	uuidComponentOffset += sizeof(vendorID);
+
+	// Next 4 bytes contains GPU device ID
+	uint32_t deviceID = _properties.deviceID;
+	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(deviceID);
+	uuidComponentOffset += sizeof(deviceID);
+
+	// Last 8 bytes contain the GPU registry ID
+	uint64_t regID = mvkGetRegistryID(_mtlDevice);
+	*(uint64_t*)&uuid[uuidComponentOffset] = NSSwapHostLongLongToBig(regID);
+	uuidComponentOffset += sizeof(regID);
+
+
+	// ---- Driver ID ----------------------------------------------
+	uuid = pDevIdProps->driverUUID;
+	uuidComponentOffset = 0;
+	mvkClear(uuid, VK_UUID_SIZE);
+
+	// First 4 bytes contains MoltenVK prefix
+	const char* mvkPfx = "MVK";
+	size_t mvkPfxLen = strlen(mvkPfx);
+	mvkCopy(&uuid[uuidComponentOffset], (uint8_t*)mvkPfx, mvkPfxLen);
+	uuidComponentOffset += mvkPfxLen + 1;
+
+	// Next 4 bytes contains MoltenVK version
+	uint32_t mvkVersion = MVK_VERSION;
+	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion);
+	uuidComponentOffset += sizeof(mvkVersion);
+
+	// Next 4 bytes contains highest Metal feature set supported by this device
+	uint32_t mtlFeatSet = getHighestMTLFeatureSet();
+	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet);
+	uuidComponentOffset += sizeof(mtlFeatSet);
+
+
+	// ---- LUID ignored for Metal devices ------------------------
+	mvkClear(pDevIdProps->deviceLUID, VK_LUID_SIZE);
+	pDevIdProps->deviceNodeMask = 0;
+	pDevIdProps->deviceLUIDValid = VK_FALSE;
 }
 
 void MVKPhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties* pFormatProperties) {
-    if (pFormatProperties) {
-		*pFormatProperties = _pixelFormats.getVkFormatProperties(format);
-	}
+	*pFormatProperties = _pixelFormats.getVkFormatProperties(format);
 }
 
-void MVKPhysicalDevice::getFormatProperties(VkFormat format,
-                                            VkFormatProperties2KHR* pFormatProperties) {
-	if (pFormatProperties) {
-		pFormatProperties->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
-		pFormatProperties->formatProperties = _pixelFormats.getVkFormatProperties(format);
-	}
+void MVKPhysicalDevice::getFormatProperties(VkFormat format, VkFormatProperties2KHR* pFormatProperties) {
+	pFormatProperties->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
+	getFormatProperties(format, &pFormatProperties->formatProperties);
 }
 
 VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
@@ -363,32 +423,41 @@
 	return VK_SUCCESS;
 }
 
-VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo,
-                                                     VkImageFormatProperties2KHR* pImageFormatProperties) {
+VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
+													 VkImageFormatProperties2* pImageFormatProperties) {
 
-    if ( !pImageFormatInfo || pImageFormatInfo->sType != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR ) {
-        return VK_ERROR_FORMAT_NOT_SUPPORTED;
-    }
+	for (const auto* nextInfo = (VkBaseInStructure*)pImageFormatInfo->pNext; nextInfo; nextInfo = nextInfo->pNext) {
+		switch (nextInfo->sType) {
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: {
+				// Return information about external memory support for MTLTexture.
+				// Search VkImageFormatProperties2 for the corresponding VkExternalImageFormatProperties and populate it.
+				auto* pExtImgFmtInfo = (VkPhysicalDeviceExternalImageFormatInfo*)nextInfo;
+				for (auto* nextProps = (VkBaseOutStructure*)pImageFormatProperties->pNext; nextProps; nextProps = nextProps->pNext) {
+					if (nextProps->sType == VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES) {
+						auto* pExtImgFmtProps = (VkExternalImageFormatProperties*)nextProps;
+						pExtImgFmtProps->externalMemoryProperties = getExternalImageProperties(pExtImgFmtInfo->handleType);
+					}
+				}
+				break;
+			}
+			default:
+				break;
+		}
+	}
 
-    if ( !_pixelFormats.isSupported(pImageFormatInfo->format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
+	if ( !_pixelFormats.isSupported(pImageFormatInfo->format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 
 	if ( !getImageViewIsSupported(pImageFormatInfo) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
 
-	if (pImageFormatProperties) {
-		pImageFormatProperties->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR;
-		return getImageFormatProperties(pImageFormatInfo->format, pImageFormatInfo->type,
-										pImageFormatInfo->tiling, pImageFormatInfo->usage,
-										pImageFormatInfo->flags,
-										&pImageFormatProperties->imageFormatProperties);
-	}
-
-	return VK_SUCCESS;
+	return getImageFormatProperties(pImageFormatInfo->format, pImageFormatInfo->type,
+									pImageFormatInfo->tiling, pImageFormatInfo->usage,
+									pImageFormatInfo->flags,
+									&pImageFormatProperties->imageFormatProperties);
 }
 
 // If the image format info links portability image view info, test if an image view of that configuration is supported
-bool MVKPhysicalDevice::getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2KHR *pImageFormatInfo) {
-	auto* next = (MVKVkAPIStructHeader*)pImageFormatInfo->pNext;
-	while (next) {
+bool MVKPhysicalDevice::getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo) {
+	for (const auto* next = (VkBaseInStructure*)pImageFormatInfo->pNext; next; next = next->pNext) {
 		switch ((uint32_t)next->sType) {
 			case VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO: {
 
@@ -397,13 +466,12 @@
 
 				MTLPixelFormat mtlPixFmt;
 				bool useSwizzle;
-				return (MVKImageView::validateSwizzledMTLPixelFormat(&viewInfo, &_pixelFormats, this,
+				return (MVKImageView::validateSwizzledMTLPixelFormat(&viewInfo, this,
 																	 _metalFeatures.nativeTextureSwizzle,
 																	 _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle,
 																	 mtlPixFmt, useSwizzle) == VK_SUCCESS);
 			}
 			default:
-				next = (MVKVkAPIStructHeader*)next->pNext;
 				break;
 		}
 	}
@@ -411,6 +479,27 @@
 	return true;
 }
 
+void MVKPhysicalDevice::getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+													VkExternalBufferProperties* pExternalBufferProperties) {
+	pExternalBufferProperties->externalMemoryProperties = getExternalBufferProperties(pExternalBufferInfo->handleType);
+}
+
+static VkExternalMemoryProperties _emptyExtMemProps = {};
+
+VkExternalMemoryProperties& MVKPhysicalDevice::getExternalBufferProperties(VkExternalMemoryHandleTypeFlagBits handleType) {
+	switch (handleType) {
+		case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR:		return _mtlBufferExternalMemoryProperties;
+		default: 													return _emptyExtMemProps;
+	}
+}
+
+VkExternalMemoryProperties& MVKPhysicalDevice::getExternalImageProperties(VkExternalMemoryHandleTypeFlagBits handleType) {
+	switch (handleType) {
+		case VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR:		return _mtlTextureExternalMemoryProperties;
+		default: 													return _emptyExtMemProps;
+	}
+}
+
 
 #pragma mark Surfaces
 
@@ -472,7 +561,7 @@
 		MTLPixelFormatBGR10A2Unorm,
 	};
 
-	MVKVectorInline<VkColorSpaceKHR, 16> colorSpaces;
+	MVKSmallVector<VkColorSpaceKHR, 16> colorSpaces;
 	colorSpaces.push_back(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
 	if (getInstance()->_enabledExtensions.vk_EXT_swapchain_colorspace.enabled) {
 #if MVK_MACOS
@@ -632,7 +721,7 @@
 // In addition, Metal queues are always general purpose, so the default behaviour is for all
 // queue families to support graphics + compute + transfer, unless the app indicates it
 // requires queue family specialization.
-MVKVector<MVKQueueFamily*>& MVKPhysicalDevice::getQueueFamilies() {
+MVKArrayRef<MVKQueueFamily*> MVKPhysicalDevice::getQueueFamilies() {
 	if (_queueFamilies.empty()) {
 		VkQueueFamilyProperties qfProps;
 		bool specialize = _mvkInstance->getMoltenVKConfiguration()->specializedQueueFamilies;
@@ -660,14 +749,13 @@
 
 		MVKAssert(kMVKQueueFamilyCount >= _queueFamilies.size(), "Adjust value of kMVKQueueFamilyCount.");
 	}
-	return _queueFamilies;
+	return _queueFamilies.contents();
 }
 
 VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
 													 VkQueueFamilyProperties* pQueueFamilyProperties) {
-
-	auto& qFams = getQueueFamilies();
-	uint32_t qfCnt = uint32_t(qFams.size());
+	auto qFams = getQueueFamilies();
+	uint32_t qfCnt = uint32_t(qFams.size);
 
 	// If properties aren't actually being requested yet, simply update the returned count
 	if ( !pQueueFamilyProperties ) {
@@ -691,7 +779,6 @@
 
 VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
 													 VkQueueFamilyProperties2KHR* pQueueFamilyProperties) {
-
 	VkResult rslt;
 	if (pQueueFamilyProperties) {
 		// Populate temp array of VkQueueFamilyProperties then copy into array of VkQueueFamilyProperties2KHR.
@@ -714,17 +801,16 @@
 #pragma mark Memory models
 
 /** Populates the specified memory properties with the memory characteristics of this device. */
-VkResult MVKPhysicalDevice::getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMemoryProperties* pMemoryProperties) {
+VkResult MVKPhysicalDevice::getMemoryProperties(VkPhysicalDeviceMemoryProperties* pMemoryProperties) {
 	*pMemoryProperties = _memoryProperties;
 	return VK_SUCCESS;
 }
 
-VkResult MVKPhysicalDevice::getPhysicalDeviceMemoryProperties(VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
-	if (pMemoryProperties) {
-		pMemoryProperties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
-		pMemoryProperties->memoryProperties = _memoryProperties;
-		for (auto* next = (VkBaseOutStructure*)pMemoryProperties->pNext; next; next = next->pNext) {
-			switch (next->sType) {
+VkResult MVKPhysicalDevice::getMemoryProperties(VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+	pMemoryProperties->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
+	pMemoryProperties->memoryProperties = _memoryProperties;
+	for (auto* next = (VkBaseOutStructure*)pMemoryProperties->pNext; next; next = next->pNext) {
+		switch (next->sType) {
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT: {
 				auto* budgetProps = (VkPhysicalDeviceMemoryBudgetPropertiesEXT*)next;
 				mvkClear(budgetProps->heapBudget, VK_MAX_MEMORY_HEAPS);
@@ -739,7 +825,6 @@
 			}
 			default:
 				break;
-			}
 		}
 	}
 	return VK_SUCCESS;
@@ -757,8 +842,9 @@
 	initMetalFeatures();        		// Call first.
 	initFeatures();             		// Call second.
 	initProperties();           		// Call third.
-	initMemoryProperties();
 	initExtensions();
+	initMemoryProperties();
+	initExternalMemoryProperties();
 	logGPUInfo();
 }
 
@@ -783,6 +869,8 @@
 
 	_metalFeatures.pushConstantSizeAlignment = 16;     // Min float4 alignment for typical uniform structs.
 
+	_metalFeatures.maxTextureLayers = (2 * KIBI);
+
 	_metalFeatures.ioSurfaces = MVK_SUPPORT_IOSURFACE_BOOL;
 
 	// Metal supports 2 or 3 concurrent CAMetalLayer drawables.
@@ -1151,7 +1239,7 @@
 	_properties.limits.maxImageDimensionCube = _metalFeatures.maxTextureDimension;
 	_properties.limits.maxFramebufferWidth = _metalFeatures.maxTextureDimension;
 	_properties.limits.maxFramebufferHeight = _metalFeatures.maxTextureDimension;
-	_properties.limits.maxFramebufferLayers = _metalFeatures.layeredRendering ?  256 : 1;
+	_properties.limits.maxFramebufferLayers = _metalFeatures.layeredRendering ? _metalFeatures.maxTextureLayers : 1;
 
     _properties.limits.maxViewportDimensions[0] = _metalFeatures.maxTextureDimension;
     _properties.limits.maxViewportDimensions[1] = _metalFeatures.maxTextureDimension;
@@ -1160,15 +1248,15 @@
     _properties.limits.viewportBoundsRange[1] = (2.0 * maxVPDim) - 1;
     _properties.limits.maxViewports = _features.multiViewport ? kMVKCachedViewportScissorCount : 1;
 
-	_properties.limits.maxImageDimension3D = (2 * KIBI);
-	_properties.limits.maxImageArrayLayers = (2 * KIBI);
+	_properties.limits.maxImageDimension3D = _metalFeatures.maxTextureLayers;
+	_properties.limits.maxImageArrayLayers = _metalFeatures.maxTextureLayers;
 	_properties.limits.maxSamplerAnisotropy = 16;
 
     _properties.limits.maxVertexInputAttributes = 31;
     _properties.limits.maxVertexInputBindings = 31;
 
-    _properties.limits.maxVertexInputAttributeOffset = (4 * KIBI);
-    _properties.limits.maxVertexInputBindingStride = _properties.limits.maxVertexInputAttributeOffset - 1;
+    _properties.limits.maxVertexInputBindingStride = (2 * KIBI);
+	_properties.limits.maxVertexInputAttributeOffset = _properties.limits.maxVertexInputBindingStride - 1;
 
 	_properties.limits.maxPerStageDescriptorSamplers = _metalFeatures.maxPerStageSamplerCount;
 	_properties.limits.maxPerStageDescriptorUniformBuffers = _metalFeatures.maxPerStageBufferCount;
@@ -1214,6 +1302,7 @@
         uint32_t maxStorage = 0, maxUniform = 0;
         bool singleTexelStorage = true, singleTexelUniform = true;
         _pixelFormats.enumerateSupportedFormats({0, 0, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT}, true, [&](VkFormat vk) {
+            if ( _pixelFormats.getChromaSubsamplingComponentBits(vk) > 0 ) { return false; }    // Skip chroma subsampling formats
 			MTLPixelFormat mtlFmt = _pixelFormats.getMTLPixelFormat(vk);
 			if ( !mtlFmt ) { return false; }	// If format is invalid, avoid validation errors on MTLDevice format alignment calls
 
@@ -1223,7 +1312,7 @@
             } else {
                 alignment = [_mtlDevice minimumLinearTextureAlignmentForPixelFormat: mtlFmt];
             }
-            VkFormatProperties props = _pixelFormats.getVkFormatProperties(vk);
+            VkFormatProperties& props = _pixelFormats.getVkFormatProperties(vk);
             // For uncompressed formats, this is the size of a single texel.
             // Note that no implementations of Metal support compressed formats
             // in a linear texture (including texture buffers). It's likely that even
@@ -1373,6 +1462,7 @@
 		_properties.limits.maxComputeSharedMemorySize = (32 * KIBI);
 #endif
 	}
+	_properties.limits.maxSamplerLodBias = 0;	// Bias not supported in API, but can be applied in shader directly.
 
     _properties.limits.minTexelOffset = -8;
     _properties.limits.maxTexelOffset = 7;
@@ -1389,7 +1479,7 @@
     _properties.limits.maxComputeWorkGroupCount[1] = kMVKUndefinedLargeUInt32;
     _properties.limits.maxComputeWorkGroupCount[2] = kMVKUndefinedLargeUInt32;
 
-    _properties.limits.maxDrawIndexedIndexValue = numeric_limits<uint32_t>::max();
+    _properties.limits.maxDrawIndexedIndexValue = numeric_limits<uint32_t>::max();	// Must be (2^32 - 1) to support fullDrawIndexUint32
     _properties.limits.maxDrawIndirectCount = kMVKUndefinedLargeUInt32;
 
     _properties.limits.maxClipDistances = kMVKUndefinedLargeUInt32;
@@ -1405,8 +1495,6 @@
     _properties.limits.mipmapPrecisionBits = 4;
     _properties.limits.viewportSubPixelBits = 0;
 
-    _properties.limits.maxSamplerLodBias = 2;
-
     _properties.limits.discreteQueuePriorities = 2;
 
     _properties.limits.minInterpolationOffset = -0.5;
@@ -1462,8 +1550,7 @@
 	if (regID) {
 		entry = IOServiceGetMatchingService(kIOMasterPortDefault, IORegistryEntryIDMatching(regID));
 		if (entry) {
-			// That returned the IOGraphicsAccelerator nub. Its parent, then, is the actual
-			// PCI device.
+			// That returned the IOGraphicsAccelerator nub. Its parent, then, is the actual PCI device.
 			io_registry_entry_t parent;
 			if (IORegistryEntryGetParentEntry(entry, kIOServicePlane, &parent) == kIOReturnSuccess) {
 				isFound = true;
@@ -1657,7 +1744,7 @@
 	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion);
 	uuidComponentOffset += sizeof(mvkVersion);
 
-	// Next 4 bytes contains hightest Metal feature set supported by this device
+	// Next 4 bytes contains highest Metal feature set supported by this device
 	uint32_t mtlFeatSet = getHighestMTLFeatureSet();
 	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet);
 	uuidComponentOffset += sizeof(mtlFeatSet);
@@ -1884,6 +1971,22 @@
 #endif
 }
 
+void MVKPhysicalDevice::initExternalMemoryProperties() {
+
+	// Buffers
+	_mtlBufferExternalMemoryProperties.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
+																 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT);
+	_mtlBufferExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+	_mtlBufferExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR;
+
+	// Images
+	_mtlTextureExternalMemoryProperties.externalMemoryFeatures = (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
+																  VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT |
+																  VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+	_mtlTextureExternalMemoryProperties.exportFromImportedHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+	_mtlTextureExternalMemoryProperties.compatibleHandleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR;
+}
+
 void MVKPhysicalDevice::initExtensions() {
 	MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_supportedExtensions;
 	pWritableExtns->disableAllButEnabledDeviceExtensions();
@@ -2101,8 +2204,10 @@
 
 void MVKDevice::destroyBuffer(MVKBuffer* mvkBuff,
 							  const VkAllocationCallbacks* pAllocator) {
-	removeResource(mvkBuff);
-	mvkBuff->destroy();
+	if (mvkBuff) {
+		removeResource(mvkBuff);
+		mvkBuff->destroy();
+	}
 }
 
 MVKBufferView* MVKDevice::createBufferView(const VkBufferViewCreateInfo* pCreateInfo,
@@ -2112,7 +2217,7 @@
 
 void MVKDevice::destroyBufferView(MVKBufferView* mvkBuffView,
                                   const VkAllocationCallbacks* pAllocator) {
-    mvkBuffView->destroy();
+	if (mvkBuffView) { mvkBuffView->destroy(); }
 }
 
 MVKImage* MVKDevice::createImage(const VkImageCreateInfo* pCreateInfo,
@@ -2128,16 +2233,23 @@
 			break;
 		}
 	}
-	if (swapchainInfo) {
-		return (MVKImage*)addResource(new MVKPeerSwapchainImage(this, pCreateInfo, (MVKSwapchain*)swapchainInfo->swapchain, uint32_t(-1)));
-	}
-	return (MVKImage*)addResource(new MVKImage(this, pCreateInfo));
+    MVKImage* mvkImg = (swapchainInfo)
+        ? new MVKPeerSwapchainImage(this, pCreateInfo, (MVKSwapchain*)swapchainInfo->swapchain, uint32_t(-1))
+        : new MVKImage(this, pCreateInfo);
+    for (auto& memoryBinding : mvkImg->_memoryBindings) {
+        addResource(memoryBinding.get());
+    }
+	return mvkImg;
 }
 
 void MVKDevice::destroyImage(MVKImage* mvkImg,
 							 const VkAllocationCallbacks* pAllocator) {
-	removeResource(mvkImg);
-	mvkImg->destroy();
+	if (mvkImg) {
+		for (auto& memoryBinding : mvkImg->_memoryBindings) {
+            removeResource(memoryBinding.get());
+        }
+		mvkImg->destroy();
+	}
 }
 
 MVKImageView* MVKDevice::createImageView(const VkImageViewCreateInfo* pCreateInfo,
@@ -2147,7 +2259,7 @@
 
 void MVKDevice::destroyImageView(MVKImageView* mvkImgView,
 								 const VkAllocationCallbacks* pAllocator) {
-	mvkImgView->destroy();
+	if (mvkImgView) { mvkImgView->destroy(); }
 }
 
 MVKSwapchain* MVKDevice::createSwapchain(const VkSwapchainCreateInfoKHR* pCreateInfo,
@@ -2157,20 +2269,28 @@
 
 void MVKDevice::destroySwapchain(MVKSwapchain* mvkSwpChn,
 								 const VkAllocationCallbacks* pAllocator) {
-	mvkSwpChn->destroy();
+	if (mvkSwpChn) { mvkSwpChn->destroy(); }
 }
 
 MVKPresentableSwapchainImage* MVKDevice::createPresentableSwapchainImage(const VkImageCreateInfo* pCreateInfo,
 																		 MVKSwapchain* swapchain,
 																		 uint32_t swapchainIndex,
 																		 const VkAllocationCallbacks* pAllocator) {
-	return (MVKPresentableSwapchainImage*)addResource(new MVKPresentableSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex));
+    MVKPresentableSwapchainImage* mvkImg = new MVKPresentableSwapchainImage(this, pCreateInfo, swapchain, swapchainIndex);
+    for (auto& memoryBinding : mvkImg->_memoryBindings) {
+        addResource(memoryBinding.get());
+    }
+    return mvkImg;
 }
 
 void MVKDevice::destroyPresentableSwapchainImage(MVKPresentableSwapchainImage* mvkImg,
 												 const VkAllocationCallbacks* pAllocator) {
-	removeResource(mvkImg);
-	mvkImg->destroy();
+	if (mvkImg) {
+		for (auto& memoryBinding : mvkImg->_memoryBindings) {
+            removeResource(memoryBinding.get());
+        }
+		mvkImg->destroy();
+	}
 }
 
 MVKFence* MVKDevice::createFence(const VkFenceCreateInfo* pCreateInfo,
@@ -2180,7 +2300,7 @@
 
 void MVKDevice::destroyFence(MVKFence* mvkFence,
 							 const VkAllocationCallbacks* pAllocator) {
-	mvkFence->destroy();
+	if (mvkFence) { mvkFence->destroy(); }
 }
 
 MVKSemaphore* MVKDevice::createSemaphore(const VkSemaphoreCreateInfo* pCreateInfo,
@@ -2196,7 +2316,7 @@
 
 void MVKDevice::destroySemaphore(MVKSemaphore* mvkSem4,
 								 const VkAllocationCallbacks* pAllocator) {
-	mvkSem4->destroy();
+	if (mvkSem4) { mvkSem4->destroy(); }
 }
 
 MVKEvent* MVKDevice::createEvent(const VkEventCreateInfo* pCreateInfo,
@@ -2209,7 +2329,7 @@
 }
 
 void MVKDevice::destroyEvent(MVKEvent* mvkEvent, const VkAllocationCallbacks* pAllocator) {
-	mvkEvent->destroy();
+	if (mvkEvent) { mvkEvent->destroy(); }
 }
 
 MVKQueryPool* MVKDevice::createQueryPool(const VkQueryPoolCreateInfo* pCreateInfo,
@@ -2228,7 +2348,7 @@
 
 void MVKDevice::destroyQueryPool(MVKQueryPool* mvkQP,
 								 const VkAllocationCallbacks* pAllocator) {
-	mvkQP->destroy();
+	if (mvkQP) { mvkQP->destroy(); }
 }
 
 MVKShaderModule* MVKDevice::createShaderModule(const VkShaderModuleCreateInfo* pCreateInfo,
@@ -2238,7 +2358,7 @@
 
 void MVKDevice::destroyShaderModule(MVKShaderModule* mvkShdrMod,
 									const VkAllocationCallbacks* pAllocator) {
-	mvkShdrMod->destroy();
+	if (mvkShdrMod) { mvkShdrMod->destroy(); }
 }
 
 MVKPipelineCache* MVKDevice::createPipelineCache(const VkPipelineCacheCreateInfo* pCreateInfo,
@@ -2248,7 +2368,7 @@
 
 void MVKDevice::destroyPipelineCache(MVKPipelineCache* mvkPLC,
 									 const VkAllocationCallbacks* pAllocator) {
-	mvkPLC->destroy();
+	if (mvkPLC) { mvkPLC->destroy(); }
 }
 
 MVKPipelineLayout* MVKDevice::createPipelineLayout(const VkPipelineLayoutCreateInfo* pCreateInfo,
@@ -2258,7 +2378,7 @@
 
 void MVKDevice::destroyPipelineLayout(MVKPipelineLayout* mvkPLL,
 									  const VkAllocationCallbacks* pAllocator) {
-	mvkPLL->destroy();
+	if (mvkPLL) { mvkPLL->destroy(); }
 }
 
 template<typename PipelineType, typename PipelineInfoType>
@@ -2319,7 +2439,7 @@
 
 void MVKDevice::destroyPipeline(MVKPipeline* mvkPL,
                                 const VkAllocationCallbacks* pAllocator) {
-    mvkPL->destroy();
+	if (mvkPL) { mvkPL->destroy(); }
 }
 
 MVKSampler* MVKDevice::createSampler(const VkSamplerCreateInfo* pCreateInfo,
@@ -2329,7 +2449,17 @@
 
 void MVKDevice::destroySampler(MVKSampler* mvkSamp,
 							   const VkAllocationCallbacks* pAllocator) {
-	mvkSamp->destroy();
+	if (mvkSamp) { mvkSamp->destroy(); }
+}
+
+MVKSamplerYcbcrConversion* MVKDevice::createSamplerYcbcrConversion(const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+																   const VkAllocationCallbacks* pAllocator) {
+	return new MVKSamplerYcbcrConversion(this, pCreateInfo);
+}
+
+void MVKDevice::destroySamplerYcbcrConversion(MVKSamplerYcbcrConversion* mvkSampConv,
+											  const VkAllocationCallbacks* pAllocator) {
+	mvkSampConv->destroy();
 }
 
 MVKDescriptorSetLayout* MVKDevice::createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
@@ -2339,7 +2469,7 @@
 
 void MVKDevice::destroyDescriptorSetLayout(MVKDescriptorSetLayout* mvkDSL,
 										   const VkAllocationCallbacks* pAllocator) {
-	mvkDSL->destroy();
+	if (mvkDSL) { mvkDSL->destroy(); }
 }
 
 MVKDescriptorPool* MVKDevice::createDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo,
@@ -2349,7 +2479,7 @@
 
 void MVKDevice::destroyDescriptorPool(MVKDescriptorPool* mvkDP,
 									  const VkAllocationCallbacks* pAllocator) {
-	mvkDP->destroy();
+	if (mvkDP) { mvkDP->destroy(); }
 }
 
 MVKDescriptorUpdateTemplate* MVKDevice::createDescriptorUpdateTemplate(
@@ -2360,7 +2490,7 @@
 
 void MVKDevice::destroyDescriptorUpdateTemplate(MVKDescriptorUpdateTemplate* mvkDUT,
 												const VkAllocationCallbacks* pAllocator) {
-	mvkDUT->destroy();
+	if (mvkDUT) { mvkDUT->destroy(); }
 }
 
 MVKFramebuffer* MVKDevice::createFramebuffer(const VkFramebufferCreateInfo* pCreateInfo,
@@ -2370,7 +2500,7 @@
 
 void MVKDevice::destroyFramebuffer(MVKFramebuffer* mvkFB,
 								   const VkAllocationCallbacks* pAllocator) {
-	mvkFB->destroy();
+	if (mvkFB) { mvkFB->destroy(); }
 }
 
 MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo* pCreateInfo,
@@ -2380,7 +2510,7 @@
 
 void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP,
 								  const VkAllocationCallbacks* pAllocator) {
-	mvkRP->destroy();
+	if (mvkRP) { mvkRP->destroy(); }
 }
 
 MVKCommandPool* MVKDevice::createCommandPool(const VkCommandPoolCreateInfo* pCreateInfo,
@@ -2390,7 +2520,7 @@
 
 void MVKDevice::destroyCommandPool(MVKCommandPool* mvkCmdPool,
 								   const VkAllocationCallbacks* pAllocator) {
-	mvkCmdPool->destroy();
+	if (mvkCmdPool) { mvkCmdPool->destroy(); }
 }
 
 MVKDeviceMemory* MVKDevice::allocateMemory(const VkMemoryAllocateInfo* pAllocateInfo,
@@ -2400,7 +2530,7 @@
 
 void MVKDevice::freeMemory(MVKDeviceMemory* mvkDevMem,
 						   const VkAllocationCallbacks* pAllocator) {
-	mvkDevMem->destroy();
+	if (mvkDevMem) { mvkDevMem->destroy(); }
 }
 
 
@@ -2422,14 +2552,14 @@
 
 void MVKDevice::applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
 								   VkPipelineStageFlags dstStageMask,
-								   VkMemoryBarrier* pMemoryBarrier,
-                                   MVKCommandEncoder* cmdEncoder,
-                                   MVKCommandUse cmdUse) {
+								   MVKPipelineBarrier& barrier,
+								   MVKCommandEncoder* cmdEncoder,
+								   MVKCommandUse cmdUse) {
 	if (!mvkIsAnyFlagEnabled(dstStageMask, VK_PIPELINE_STAGE_HOST_BIT) ||
-		!mvkIsAnyFlagEnabled(pMemoryBarrier->dstAccessMask, VK_ACCESS_HOST_READ_BIT) ) { return; }
+		!mvkIsAnyFlagEnabled(barrier.dstAccessMask, VK_ACCESS_HOST_READ_BIT) ) { return; }
 	lock_guard<mutex> lock(_rezLock);
-    for (auto& rez : _resources) {
-		rez->applyMemoryBarrier(srcStageMask, dstStageMask, pMemoryBarrier, cmdEncoder, cmdUse);
+	for (auto& rez : _resources) {
+		rez->applyMemoryBarrier(srcStageMask, dstStageMask, barrier, cmdEncoder, cmdUse);
 	}
 }
 
@@ -2583,6 +2713,7 @@
 	_enabledVarPtrFeatures(),
 	_enabledInterlockFeatures(),
 	_enabledHostQryResetFeatures(),
+	_enabledSamplerYcbcrConversionFeatures(),
 	_enabledScalarLayoutFeatures(),
 	_enabledTexelBuffAlignFeatures(),
 	_enabledVtxAttrDivFeatures(),
@@ -2744,6 +2875,7 @@
 	mvkClear(&_enabledVarPtrFeatures);
 	mvkClear(&_enabledInterlockFeatures);
 	mvkClear(&_enabledHostQryResetFeatures);
+	mvkClear(&_enabledSamplerYcbcrConversionFeatures);
 	mvkClear(&_enabledScalarLayoutFeatures);
 	mvkClear(&_enabledTexelBuffAlignFeatures);
 	mvkClear(&_enabledVtxAttrDivFeatures);
@@ -2766,9 +2898,13 @@
 	pdScalarLayoutFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT;
 	pdScalarLayoutFeatures.pNext = &pdTexelBuffAlignFeatures;
 
+	VkPhysicalDeviceSamplerYcbcrConversionFeatures pdSamplerYcbcrConversionFeatures;
+	pdSamplerYcbcrConversionFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
+	pdSamplerYcbcrConversionFeatures.pNext = &pdScalarLayoutFeatures;
+
 	VkPhysicalDeviceHostQueryResetFeaturesEXT pdHostQryResetFeatures;
 	pdHostQryResetFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT;
-	pdHostQryResetFeatures.pNext = &pdScalarLayoutFeatures;
+	pdHostQryResetFeatures.pNext = &pdSamplerYcbcrConversionFeatures;
 
 	VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT pdInterlockFeatures;
 	pdInterlockFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT;
@@ -2807,8 +2943,7 @@
 					   &pdFeats2.features.robustBufferAccess, 55);
 	}
 
-	auto* next = (MVKVkAPIStructHeader*)pCreateInfo->pNext;
-	while (next) {
+	for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
 		switch ((uint32_t)next->sType) {
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
 				auto* requestedFeatures = (VkPhysicalDeviceFeatures2*)next;
@@ -2866,6 +3001,13 @@
 							   &pdHostQryResetFeatures.hostQueryReset, 1);
 				break;
 			}
+			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
+				auto* requestedFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
+				enableFeatures(&_enabledSamplerYcbcrConversionFeatures.samplerYcbcrConversion,
+							   &requestedFeatures->samplerYcbcrConversion,
+							   &pdSamplerYcbcrConversionFeatures.samplerYcbcrConversion, 1);
+				break;
+			}
 			case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT: {
 				auto* requestedFeatures = (VkPhysicalDeviceScalarBlockLayoutFeaturesEXT*)next;
 				enableFeatures(&_enabledScalarLayoutFeatures.scalarBlockLayout,
@@ -2897,7 +3039,6 @@
 			default:
 				break;
 		}
-		next = (MVKVkAPIStructHeader*)next->pNext;
 	}
 }
 
@@ -2919,7 +3060,7 @@
 
 // Create the command queues
 void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) {
-	auto& qFams = _physicalDevice->getQueueFamilies();
+	auto qFams = _physicalDevice->getQueueFamilies();
 	uint32_t qrCnt = pCreateInfo->queueCreateInfoCount;
 	for (uint32_t qrIdx = 0; qrIdx < qrCnt; qrIdx++) {
 		const VkDeviceQueueCreateInfo* pQFInfo = &pCreateInfo->pQueueCreateInfos[qrIdx];
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
index 5fc2cb2..1369e41 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
@@ -19,13 +19,16 @@
 #pragma once
 
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <mutex>
 
 #import <Metal/Metal.h>
 
-class MVKBuffer;
-class MVKImage;
+class MVKImageMemoryBinding;
+
+// TODO: These are inoperable placeholders until VK_KHR_external_memory_metal defines them properly
+static const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
+static const VkExternalMemoryHandleTypeFlagBits VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
 
 
 #pragma mark MVKDeviceMemory
@@ -87,7 +90,7 @@
 	 * to coherent memory can be forced by setting evenIfCoherent to true.
 	 *
 	 * If pBlitEnc is not null, it points to a holder for a MTLBlitCommandEncoder and its
-	 * assocated MTLCommandBuffer. If this instance has a MTLBuffer using managed memory,
+	 * associated MTLCommandBuffer. If this instance has a MTLBuffer using managed memory,
 	 * this function may call synchronizeResource: on the MTLBlitCommandEncoder to
 	 * synchronize the GPU contents to the CPU. If the contents of the pBlitEnc do not
 	 * include a MTLBlitCommandEncoder and MTLCommandBuffer, this function will create
@@ -113,7 +116,7 @@
 	/** Returns the Metal CPU cache mode used by this memory allocation. */
 	inline MTLCPUCacheMode getMTLCPUCacheMode() { return _mtlCPUCacheMode; }
 
-	/** Returns the Metal reource options used by this memory allocation. */
+	/** Returns the Metal resource options used by this memory allocation. */
 	inline MTLResourceOptions getMTLResourceOptions() { return mvkMTLResourceOptions(_mtlStorageMode, _mtlCPUCacheMode); }
 
 
@@ -127,23 +130,24 @@
     ~MVKDeviceMemory() override;
 
 protected:
-	friend MVKBuffer;
-	friend MVKImage;
+	friend class MVKBuffer;
+    friend class MVKImageMemoryBinding;
 
-	void propogateDebugName() override;
+	void propagateDebugName() override;
 	VkDeviceSize adjustMemorySize(VkDeviceSize size, VkDeviceSize offset);
 	VkResult addBuffer(MVKBuffer* mvkBuff);
 	void removeBuffer(MVKBuffer* mvkBuff);
-	VkResult addImage(MVKImage* mvkImg);
-	void removeImage(MVKImage* mvkImg);
+	VkResult addImageMemoryBinding(MVKImageMemoryBinding* mvkImg);
+	void removeImageMemoryBinding(MVKImageMemoryBinding* mvkImg);
 	bool ensureMTLHeap();
 	bool ensureMTLBuffer();
 	bool ensureHostMemory();
 	void freeHostMemory();
 	MVKResource* getDedicatedResource();
+	void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
 
-	MVKVectorInline<MVKBuffer*, 4> _buffers;
-	MVKVectorInline<MVKImage*, 4> _images;
+	MVKSmallVector<MVKBuffer*, 4> _buffers;
+	MVKSmallVector<MVKImageMemoryBinding*, 4> _imageMemoryBindings;
 	std::mutex _rezLock;
     VkDeviceSize _allocationSize = 0;
 	VkDeviceSize _mapOffset = 0;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
index 714a8f9..2f25601 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
@@ -32,7 +32,7 @@
 
 #pragma mark MVKDeviceMemory
 
-void MVKDeviceMemory::propogateDebugName() {
+void MVKDeviceMemory::propagateDebugName() {
 	setLabelIfNotNil(_mtlHeap, _debugName);
 	setLabelIfNotNil(_mtlBuffer, _debugName);
 }
@@ -92,7 +92,7 @@
 		// If we have an MTLHeap object, there's no need to sync memory manually between images and the buffer.
 		if (!_mtlHeap) {
 			lock_guard<mutex> lock(_rezLock);
-			for (auto& img : _images) { img->flushToDevice(offset, memSize); }
+			for (auto& img : _imageMemoryBindings) { img->flushToDevice(offset, memSize); }
 			for (auto& buf : _buffers) { buf->flushToDevice(offset, memSize); }
 		}
 	}
@@ -107,7 +107,7 @@
     VkDeviceSize memSize = adjustMemorySize(size, offset);
 	if (memSize > 0 && isMemoryHostAccessible() && (evenIfCoherent || !isMemoryHostCoherent()) && !_mtlHeap) {
 		lock_guard<mutex> lock(_rezLock);
-        for (auto& img : _images) { img->pullFromDevice(offset, memSize); }
+        for (auto& img : _imageMemoryBindings) { img->pullFromDevice(offset, memSize); }
         for (auto& buf : _buffers) { buf->pullFromDevice(offset, memSize); }
 
 #if MVK_MACOS
@@ -152,23 +152,23 @@
 	mvkRemoveAllOccurances(_buffers, mvkBuff);
 }
 
-VkResult MVKDeviceMemory::addImage(MVKImage* mvkImg) {
+VkResult MVKDeviceMemory::addImageMemoryBinding(MVKImageMemoryBinding* mvkImg) {
 	lock_guard<mutex> lock(_rezLock);
 
 	// If a dedicated alloc, ensure this image is the one and only image
 	// I am dedicated to.
-	if (_isDedicated && (_images.empty() || _images[0] != mvkImg) ) {
+	if (_isDedicated && (_imageMemoryBindings.empty() || _imageMemoryBindings[0] != mvkImg) ) {
 		return reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not bind VkImage %p to a VkDeviceMemory dedicated to resource %p. A dedicated allocation may only be used with the resource it was dedicated to.", mvkImg, getDedicatedResource() );
 	}
 
-	if (!_isDedicated) { _images.push_back(mvkImg); }
+	if (!_isDedicated) { _imageMemoryBindings.push_back(mvkImg); }
 
 	return VK_SUCCESS;
 }
 
-void MVKDeviceMemory::removeImage(MVKImage* mvkImg) {
+void MVKDeviceMemory::removeImageMemoryBinding(MVKImageMemoryBinding* mvkImg) {
 	lock_guard<mutex> lock(_rezLock);
-	mvkRemoveAllOccurances(_images, mvkImg);
+	mvkRemoveAllOccurances(_imageMemoryBindings, mvkImg);
 }
 
 // Ensures that this instance is backed by a MTLHeap object,
@@ -205,7 +205,7 @@
 	[heapDesc release];
 	if (!_mtlHeap) { return false; }
 
-	propogateDebugName();
+	propagateDebugName();
 
 	return true;
 }
@@ -237,7 +237,7 @@
 	if (!_mtlBuffer) { return false; }
 	_pMemory = isMemoryHostAccessible() ? _mtlBuffer.contents : nullptr;
 
-	propogateDebugName();
+	propagateDebugName();
 
 	return true;
 }
@@ -266,10 +266,7 @@
 
 MVKResource* MVKDeviceMemory::getDedicatedResource() {
 	MVKAssert(_isDedicated, "This method should only be called on dedicated allocations!");
-	if (_buffers.empty())
-		return _images[0];
-	else
-		return _buffers[0];
+	return _buffers.empty() ? (MVKResource*)_imageMemoryBindings[0] : (MVKResource*)_buffers[0];
 }
 
 MVKDeviceMemory::MVKDeviceMemory(MVKDevice* device,
@@ -284,22 +281,28 @@
 
 	VkImage dedicatedImage = VK_NULL_HANDLE;
 	VkBuffer dedicatedBuffer = VK_NULL_HANDLE;
-	auto* next = (VkStructureType*)pAllocateInfo->pNext;
-	while (next) {
-		switch (*next) {
-		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
-			auto* pDedicatedInfo = (VkMemoryDedicatedAllocateInfo*)next;
-			dedicatedImage = pDedicatedInfo->image;
-			dedicatedBuffer = pDedicatedInfo->buffer;
-			next = (VkStructureType*)pDedicatedInfo->pNext;
-			break;
-		}
-		default:
-			next = (VkStructureType*)((VkMemoryAllocateInfo*)next)->pNext;
-			break;
+	VkExternalMemoryHandleTypeFlags handleTypes = 0;
+	for (const auto* next = (const VkBaseInStructure*)pAllocateInfo->pNext; next; next = next->pNext) {
+		switch (next->sType) {
+			case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
+				auto* pDedicatedInfo = (VkMemoryDedicatedAllocateInfo*)next;
+				dedicatedImage = pDedicatedInfo->image;
+				dedicatedBuffer = pDedicatedInfo->buffer;
+				_isDedicated = dedicatedImage || dedicatedBuffer;
+				break;
+			}
+			case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: {
+				auto* pExpMemInfo = (VkExportMemoryAllocateInfo*)next;
+				handleTypes = pExpMemInfo->handleTypes;
+				break;
+			}
+			default:
+				break;
 		}
 	}
 
+	initExternalMemory(handleTypes);	// After setting _isDedicated
+
 	// "Dedicated" means this memory can only be used for this image or buffer.
 	if (dedicatedImage) {
 #if MVK_MACOS
@@ -316,14 +319,18 @@
 			}
 		}
 #endif
-		_isDedicated = true;
-		_images.push_back((MVKImage*)dedicatedImage);
+        for (auto& memoryBinding : ((MVKImage*)dedicatedImage)->_memoryBindings) {
+            _imageMemoryBindings.push_back(memoryBinding.get());
+        }
 		return;
 	}
 
-	// If we can, create a MTLHeap. This should happen before creating the buffer
-	// allowing us to map its contents.
-	if (!dedicatedImage && !dedicatedBuffer) {
+	if (dedicatedBuffer) {
+		_buffers.push_back((MVKBuffer*)dedicatedBuffer);
+	}
+
+	// If we can, create a MTLHeap. This should happen before creating the buffer, allowing us to map its contents.
+	if ( !_isDedicated ) {
 		if (!ensureMTLHeap()) {
 			setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate VkDeviceMemory of size %llu bytes.", _allocationSize));
 			return;
@@ -334,10 +341,26 @@
 	if (isMemoryHostCoherent() && !ensureMTLBuffer() ) {
 		setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate a host-coherent VkDeviceMemory of size %llu bytes. The maximum memory-aligned size of a host-coherent VkDeviceMemory is %llu bytes.", _allocationSize, _device->_pMetalFeatures->maxMTLBufferSize));
 	}
+}
 
-	if (dedicatedBuffer) {
-		_isDedicated = true;
-		_buffers.push_back((MVKBuffer*)dedicatedBuffer);
+void MVKDeviceMemory::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+	if ( !handleTypes ) { return; }
+	
+	if ( !mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR | VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR) ) {
+		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkAllocateMemory(): Only external memory handle types VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR or VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR are supported."));
+	}
+
+	bool requiresDedicated = false;
+	if (mvkIsAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR)) {
+		auto& xmProps = _device->getPhysicalDevice()->getExternalBufferProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_KHR);
+		requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+	}
+	if (mvkIsAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR)) {
+		auto& xmProps = _device->getPhysicalDevice()->getExternalImageProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR);
+		requiresDedicated = requiresDedicated || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+	}
+	if (requiresDedicated && !_isDedicated) {
+		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "vkAllocateMemory(): External memory requires a dedicated VkBuffer or VkImage."));
 	}
 }
 
@@ -346,7 +369,7 @@
     // to allow the resource to callback to remove itself from the collection.
     auto buffCopies = _buffers;
     for (auto& buf : buffCopies) { buf->bindDeviceMemory(nullptr, 0); }
-	auto imgCopies = _images;
+	auto imgCopies = _imageMemoryBindings;
 	for (auto& img : imgCopies) { img->bindDeviceMemory(nullptr, 0); }
 
 	[_mtlBuffer release];
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
index cd0838b..33339b2 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
@@ -20,7 +20,7 @@
 
 #include "MVKDevice.h"
 #include "MVKImage.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 
 #pragma mark MVKFramebuffer
@@ -52,10 +52,10 @@
 	MVKFramebuffer(MVKDevice* device, const VkFramebufferCreateInfo* pCreateInfo);
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 	VkExtent2D _extent;
 	uint32_t _layerCount;
-	MVKVectorInline<MVKImageView*, 4> _attachments;
+	MVKSmallVector<MVKImageView*, 4> _attachments;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index 89e5af0..dd0ea13 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -21,7 +21,7 @@
 #include "MVKResource.h"
 #include "MVKCommandResourceFactory.h"
 #include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
 #include <unordered_map>
 #include <mutex>
@@ -33,19 +33,112 @@
 class MVKCommandEncoder;
 
 
+#pragma mark -
+#pragma mark MVKImagePlane
+
 /** Tracks the state of an image subresource.  */
 typedef struct {
-	VkImageSubresource subresource;
-	VkSubresourceLayout layout;
-	VkImageLayout layoutState;
+    VkImageSubresource subresource;
+    VkSubresourceLayout layout;
+    VkImageLayout layoutState;
 } MVKImageSubresource;
 
+class MVKImagePlane {
+
+public:
+    /** Returns the Metal texture underlying this image plane. */
+    id<MTLTexture> getMTLTexture();
+
+    /** Returns a Metal texture that interprets the pixels in the specified format. */
+    id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
+
+    void releaseMTLTexture();
+
+    ~MVKImagePlane();
+
+protected:
+    MTLTextureDescriptor* newMTLTextureDescriptor();
+    void initSubresources(const VkImageCreateInfo* pCreateInfo);
+    MVKImageSubresource* getSubresource(uint32_t mipLevel, uint32_t arrayLayer);
+    void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
+    void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
+    void propagateDebugName();
+    MVKImageMemoryBinding* getMemoryBinding() const;
+
+    MVKImagePlane(MVKImage* image, uint8_t planeIndex);
+
+    friend class MVKImageMemoryBinding;
+    friend MVKImage;
+    MVKImage* _image;
+    uint8_t _planeIndex;
+    VkExtent2D _blockTexelSize;
+    uint32_t _bytesPerBlock;
+    MTLPixelFormat _mtlPixFmt;
+    id<MTLTexture> _mtlTexture;
+    std::unordered_map<NSUInteger, id<MTLTexture>> _mtlTextureViews;
+    MVKSmallVector<MVKImageSubresource, 1> _subresources;
+};
+
+
+#pragma mark -
+#pragma mark MVKImageMemoryBinding
+
+class MVKImageMemoryBinding : public MVKResource {
+
+public:
+    
+    /** Returns the Vulkan type of this object. */
+    VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_UNKNOWN; }
+
+    /** Returns the debug report object type of this object. */
+    VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; }
+
+    /** Returns the memory requirements of this resource by populating the specified structure. */
+    VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements);
+
+    /** Returns the memory requirements of this resource by populating the specified structure. */
+    VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+
+    /** Binds this resource to the specified offset within the specified memory allocation. */
+    VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
+
+    /** Applies the specified global memory barrier. */
+    void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
+                            VkPipelineStageFlags dstStageMask,
+                            MVKPipelineBarrier& barrier,
+                            MVKCommandEncoder* cmdEncoder,
+                            MVKCommandUse cmdUse) override;
+    
+    ~MVKImageMemoryBinding();
+
+protected:
+    friend MVKDeviceMemory;
+    friend MVKImagePlane;
+    friend MVKImage;
+
+    void propagateDebugName() override;
+    bool needsHostReadSync(VkPipelineStageFlags srcStageMask,
+                           VkPipelineStageFlags dstStageMask,
+                           VkMemoryBarrier* pMemoryBarrier) override;
+    bool shouldFlushHostMemory();
+    VkResult flushToDevice(VkDeviceSize offset, VkDeviceSize size);
+    VkResult pullFromDevice(VkDeviceSize offset, VkDeviceSize size);
+    uint8_t beginPlaneIndex() const;
+    uint8_t endPlaneIndex() const;
+
+    MVKImageMemoryBinding(MVKDevice* device, MVKImage* image, uint8_t planeIndex);
+
+    MVKImage* _image;
+    uint8_t _planeIndex;
+    bool _usesTexelBuffer;
+};
+
 
 #pragma mark -
 #pragma mark MVKImage
 
 /** Represents a Vulkan image. */
-class MVKImage : public MVKResource {
+class MVKImage : public MVKVulkanAPIDeviceObject {
 
 public:
 
@@ -55,6 +148,9 @@
 	/** Returns the debug report object type of this object. */
 	VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT; }
 
+    /** Returns the plane index of VkImageAspectFlags. */
+    static uint8_t getPlaneFromVkImageAspectFlags(VkImageAspectFlags aspectMask);
+
 	/**
 	 * Returns the Vulkan image type of this image.
 	 * This may be different than the value originally specified for the image
@@ -63,7 +159,7 @@
     VkImageType getImageType();
 
     /** Returns the Vulkan image format of this image. */
-    VkFormat getVkFormat();
+    VkFormat getVkFormat() { return _vkFormat; };
 
 	/** Returns whether this image has a depth or stencil format. */
 	bool getIsDepthStencil();
@@ -81,7 +177,7 @@
 	 * Returns the 3D extent of this image at the specified mipmap level. 
 	 * For 2D or cube images, the Z component will be 1.
 	 */
-	VkExtent3D getExtent3D(uint32_t mipLevel);
+	VkExtent3D getExtent3D(uint8_t planeIndex, uint32_t mipLevel);
 
 	/** Returns the number of mipmap levels in this image. */
 	inline uint32_t getMipLevelCount() { return _mipLevels; }
@@ -101,7 +197,7 @@
       * For compressed formats, this is the number of bytes in a row of blocks, which
       * will typically span more than one row of texels.
 	  */
-	VkDeviceSize getBytesPerRow(uint32_t mipLevel);
+	VkDeviceSize getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel);
 
 	/**
 	 * Returns the number of bytes per image layer (for cube, array, or 3D images) 
@@ -109,7 +205,10 @@
 	 * of bytes per row (as returned by the getBytesPerRow() function, multiplied by 
 	 * the height of each 2D image.
 	 */
-	VkDeviceSize getBytesPerLayer(uint32_t mipLevel);
+	VkDeviceSize getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel);
+    
+    /** Returns the number of planes of this image view. */
+    inline uint8_t getPlaneCount() { return _planes.size(); }
 
 	/** Populates the specified layout for the specified sub-resource. */
 	VkResult getSubresourceLayout(const VkImageSubresource* pSubresource,
@@ -122,35 +221,31 @@
 #pragma mark Resource memory
 
 	/** Returns the memory requirements of this resource by populating the specified structure. */
-	VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements) override;
+	VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements, uint8_t planeIndex);
 
 	/** Returns the memory requirements of this resource by populating the specified structure. */
-	VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements) override;
+	VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements);
 
 	/** Binds this resource to the specified offset within the specified memory allocation. */
-	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;
+	virtual VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex);
 
-	/** Applies the specified global memory barrier. */
-    void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
-                            VkPipelineStageFlags dstStageMask,
-                            VkMemoryBarrier* pMemoryBarrier,
-                            MVKCommandEncoder* cmdEncoder,
-                            MVKCommandUse cmdUse) override;
+	/** Binds this resource to the specified offset within the specified memory allocation. */
+	virtual VkResult bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo);
 
 	/** Applies the specified image memory barrier. */
-    void applyImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
-                                 VkPipelineStageFlags dstStageMask,
-                                 VkImageMemoryBarrier* pImageMemoryBarrier,
-                                 MVKCommandEncoder* cmdEncoder,
-                                 MVKCommandUse cmdUse);
+	void applyImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
+								 VkPipelineStageFlags dstStageMask,
+								 MVKPipelineBarrier& barrier,
+								 MVKCommandEncoder* cmdEncoder,
+								 MVKCommandUse cmdUse);
 
 #pragma mark Metal
 
 	/** Returns the Metal texture underlying this image. */
-	virtual id<MTLTexture> getMTLTexture();
+	virtual id<MTLTexture> getMTLTexture(uint8_t planeIndex);
 
 	/** Returns a Metal texture that interprets the pixels in the specified format. */
-	id<MTLTexture> getMTLTexture(MTLPixelFormat mtlPixFmt);
+	id<MTLTexture> getMTLTexture(uint8_t planeIndex, MTLPixelFormat mtlPixFmt);
 
     /**
      * Sets this image to use the specified MTLTexture.
@@ -160,7 +255,7 @@
      *
      * If a MTLTexture has already been created for this image, it will be destroyed.
      */
-    VkResult setMTLTexture(id<MTLTexture> mtlTexture);
+    VkResult setMTLTexture(uint8_t planeIndex, id<MTLTexture> mtlTexture);
 
     /**
      * Indicates that this VkImage should use an IOSurface to underlay the Metal texture.
@@ -186,7 +281,7 @@
     IOSurfaceRef getIOSurface();
 
 	/** Returns the Metal pixel format of this image. */
-	inline MTLPixelFormat getMTLPixelFormat() { return _mtlPixelFormat; }
+	inline MTLPixelFormat getMTLPixelFormat(uint8_t planeIndex) { return _planes[planeIndex]->_mtlPixFmt; }
 
 	/** Returns the Metal texture type of this image. */
 	inline MTLTextureType getMTLTextureType() { return _mtlTextureType; }
@@ -222,49 +317,37 @@
 	~MVKImage() override;
 
 protected:
-	friend class MVKDeviceMemory;
-	friend class MVKImageView;
-	using MVKResource::needsHostReadSync;
+    friend MVKDeviceMemory;
+    friend MVKDevice;
+    friend MVKImageMemoryBinding;
+    friend MVKImagePlane;
+    friend class MVKImageViewPlane;
+	friend MVKImageView;
 
-	void propogateDebugName() override;
-	MVKImageSubresource* getSubresource(uint32_t mipLevel, uint32_t arrayLayer);
+	void propagateDebugName() override;
 	void validateConfig(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
 	VkSampleCountFlagBits validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
 	uint32_t validateMipLevels(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
 	bool validateLinear(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
-	bool validateUseTexelBuffer();
-	void initSubresources(const VkImageCreateInfo* pCreateInfo);
-	void initSubresourceLayout(MVKImageSubresource& imgSubRez);
-	id<MTLTexture> newMTLTexture();
-	void releaseMTLTexture();
+	void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
     void releaseIOSurface();
-	MTLTextureDescriptor* newMTLTextureDescriptor();
-    void updateMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
-    void getMTLTextureContent(MVKImageSubresource& subresource, VkDeviceSize offset, VkDeviceSize size);
-	bool shouldFlushHostMemory();
-	VkResult flushToDevice(VkDeviceSize offset, VkDeviceSize size);
-	VkResult pullFromDevice(VkDeviceSize offset, VkDeviceSize size);
-	bool needsHostReadSync(VkPipelineStageFlags srcStageMask,
-						   VkPipelineStageFlags dstStageMask,
-						   VkImageMemoryBarrier* pImageMemoryBarrier);
 
-	MVKVectorInline<MVKImageSubresource, 1> _subresources;
-	std::unordered_map<NSUInteger, id<MTLTexture>> _mtlTextureViews;
+    MVKSmallVector<std::unique_ptr<MVKImageMemoryBinding>, 3> _memoryBindings;
+    MVKSmallVector<std::unique_ptr<MVKImagePlane>, 3> _planes;
     VkExtent3D _extent;
     uint32_t _mipLevels;
     uint32_t _arrayLayers;
     VkSampleCountFlagBits _samples;
     VkImageUsageFlags _usage;
-	MTLPixelFormat _mtlPixelFormat;
+    VkFormat _vkFormat;
 	MTLTextureType _mtlTextureType;
-    id<MTLTexture> _mtlTexture;
     std::mutex _lock;
     IOSurfaceRef _ioSurface;
 	VkDeviceSize _rowByteAlignment;
     bool _isDepthStencilAttachment;
 	bool _canSupportMTLTextureView;
     bool _hasExpectedTexelSize;
-	bool _usesTexelBuffer;
+    bool _hasChromaSubsampling;
 	bool _isLinear;
 	bool _is3DCompressed;
 	bool _isAliasable;
@@ -280,12 +363,12 @@
 public:
 
 	/** Binds this resource to the specified offset within the specified memory allocation. */
-	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) override;
+	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) override;
 
 #pragma mark Metal
 
 	/** Returns the Metal texture used by the CAMetalDrawable underlying this image. */
-	id<MTLTexture> getMTLTexture() override;
+	id<MTLTexture> getMTLTexture(uint8_t planeIndex) override;
 
 
 #pragma mark Construction
@@ -336,7 +419,7 @@
 	 * the presentDrawable: method of the command buffer. If mtlCmdBuff is nil, the contained
 	 * drawable is presented immediately using the present method of the drawable.
 	 */
-	void presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff);
+	void presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, bool hasPresentTime, uint32_t presentID, uint64_t desiredPresentTime);
 
 
 #pragma mark Construction
@@ -365,7 +448,7 @@
 
 	id<CAMetalDrawable> _mtlDrawable;
 	MVKSwapchainImageAvailability _availability;
-	MVKVectorInline<MVKSwapchainSignaler, 1> _availabilitySignalers;
+	MVKSmallVector<MVKSwapchainSignaler, 1> _availabilitySignalers;
 	MVKSwapchainSignaler _preSignaler;
 	std::mutex _availabilityLock;
 };
@@ -380,7 +463,7 @@
 public:
 
 	/** Binds this resource according to the specified bind information. */
-	VkResult bindDeviceMemory2(const void* pBindInfo) override;
+	VkResult bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) override;
 
 
 #pragma mark Construction
@@ -398,6 +481,34 @@
 
 
 #pragma mark -
+#pragma mark MVKImageViewPlane
+
+class MVKImageViewPlane {
+
+public:
+    /** Returns the Metal texture underlying this image view. */
+    id<MTLTexture> getMTLTexture();
+
+    void releaseMTLTexture();
+
+    ~MVKImageViewPlane();
+
+protected:
+    void propagateDebugName();
+    id<MTLTexture> newMTLTexture();
+    MVKImageViewPlane(MVKImageView* imageView, uint8_t planeIndex, MTLPixelFormat mtlPixFmt, const VkImageViewCreateInfo* pCreateInfo);
+
+    friend MVKImageView;
+    MVKImageView* _imageView;
+    uint8_t _planeIndex;
+    MTLPixelFormat _mtlPixFmt;
+    uint32_t _packedSwizzle;
+    id<MTLTexture> _mtlTexture;
+    bool _useMTLTextureView;
+};
+
+
+#pragma mark -
 #pragma mark MVKImageView
 
 /** Represents a Vulkan image view. */
@@ -414,17 +525,20 @@
 #pragma mark Metal
 
 	/** Returns the Metal texture underlying this image view. */
-	id<MTLTexture> getMTLTexture();
+	id<MTLTexture> getMTLTexture(uint8_t planeIndex) { return _planes[planeIndex]->getMTLTexture(); }
 
 	/** Returns the Metal pixel format of this image view. */
-	inline MTLPixelFormat getMTLPixelFormat() { return _mtlPixelFormat; }
+	inline MTLPixelFormat getMTLPixelFormat(uint8_t planeIndex) { return _planes[planeIndex]->_mtlPixFmt; }
+    
+    /** Returns the packed component swizzle of this image view. */
+    inline uint32_t getPackedSwizzle() { return _planes[0]->_packedSwizzle; }
+    
+    /** Returns the number of planes of this image view. */
+    inline uint8_t getPlaneCount() { return _planes.size(); }
 
 	/** Returns the Metal texture type of this image view. */
 	inline MTLTextureType getMTLTextureType() { return _mtlTextureType; }
 
-	/** Returns the packed component swizzle of this image view. */
-	inline uint32_t getPackedSwizzle() { return _packedSwizzle; }
-
 	/**
 	 * Populates the texture of the specified render pass descriptor
 	 * with the Metal texture underlying this image.
@@ -454,7 +568,6 @@
 	 * This is a static function that can be used to validate image view formats prior to creating one.
 	 */
 	static VkResult validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
-												   MVKPixelFormats* mvkPixFmts,
 												   MVKVulkanAPIObject* apiObject,
 												   bool hasNativeSwizzleSupport,
 												   bool hasShaderSwizzleSupport,
@@ -468,23 +581,54 @@
 				 const VkImageViewCreateInfo* pCreateInfo,
 				 const MVKConfiguration* pAltMVKConfig = nullptr);
 
-	~MVKImageView() override;
-
 protected:
-	void propogateDebugName() override;
-	id<MTLTexture> newMTLTexture();
-	void initMTLTextureViewSupport();
-	void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo);
+    friend MVKImageViewPlane;
+    
+	void propagateDebugName() override;
 
     MVKImage* _image;
+    MVKSmallVector<std::unique_ptr<MVKImageViewPlane>, 3> _planes;
     VkImageSubresourceRange _subresourceRange;
     VkImageUsageFlags _usage;
-	id<MTLTexture> _mtlTexture;
 	std::mutex _lock;
-	MTLPixelFormat _mtlPixelFormat;
 	MTLTextureType _mtlTextureType;
-	uint32_t _packedSwizzle;
-	bool _useMTLTextureView;
+};
+
+
+#pragma mark -
+#pragma mark MVKSamplerYcbcrConversion
+
+/** Represents a Vulkan sampler ycbcr conversion. */
+class MVKSamplerYcbcrConversion : public MVKVulkanAPIDeviceObject {
+
+public:
+    /** Returns the Vulkan type of this object. */
+    VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION; }
+
+    /** Returns the debug report object type of this object. */
+    VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT; }
+    
+    /** Returns the number of planes of this ycbcr conversion. */
+    inline uint8_t getPlaneCount() { return _planes; }
+
+    /** Writes this conversion settings to a MSL constant sampler */
+    void updateConstExprSampler(SPIRV_CROSS_NAMESPACE::MSLConstexprSampler& constExprSampler) const;
+
+    MVKSamplerYcbcrConversion(MVKDevice* device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo);
+
+    ~MVKSamplerYcbcrConversion() override {}
+
+protected:
+    void propagateDebugName() override {}
+
+    uint8_t _planes, _bpc;
+    SPIRV_CROSS_NAMESPACE::MSLFormatResolution _resolution;
+    SPIRV_CROSS_NAMESPACE::MSLSamplerFilter _chroma_filter;
+    SPIRV_CROSS_NAMESPACE::MSLChromaLocation _x_chroma_offset, _y_chroma_offset;
+    SPIRV_CROSS_NAMESPACE::MSLComponentSwizzle _swizzle[4];
+    SPIRV_CROSS_NAMESPACE::MSLSamplerYCbCrModelConversion _ycbcr_model;
+    SPIRV_CROSS_NAMESPACE::MSLSamplerYCbCrRange _ycbcr_range;
+    bool _forceExplicitReconstruction;
 };
 
 
@@ -504,6 +648,10 @@
 
 	/** Returns the Metal sampler state. */
 	inline id<MTLSamplerState> getMTLSamplerState() { return _mtlSamplerState; }
+    
+    /** Returns the number of planes if this is a ycbcr conversion or 0 otherwise. */
+    inline uint8_t getPlaneCount() { return (_ycbcrConversion) ? _ycbcrConversion->getPlaneCount() : 0; }
+
 
 	/**
 	 * If this sampler requires hardcoding in MSL, populates the hardcoded sampler in the resource binding.
@@ -519,11 +667,12 @@
 	~MVKSampler() override;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	MTLSamplerDescriptor* newMTLSamplerDescriptor(const VkSamplerCreateInfo* pCreateInfo);
 	void initConstExprSampler(const VkSamplerCreateInfo* pCreateInfo);
 
 	id<MTLSamplerState> _mtlSamplerState;
 	SPIRV_CROSS_NAMESPACE::MSLConstexprSampler _constExprSampler;
+	MVKSamplerYcbcrConversion* _ycbcrConversion;
 	bool _requiresConstExprSampler;
 };
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 89fb6dd..a2a8ac5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -32,40 +32,455 @@
 using namespace std;
 using namespace SPIRV_CROSS_NAMESPACE;
 
+#pragma mark -
+#pragma mark MVKImagePlane
+
+id<MTLTexture> MVKImagePlane::getMTLTexture() {
+    if ( !_mtlTexture && _image->_vkFormat ) {
+        // Lock and check again in case another thread has created the texture.
+        lock_guard<mutex> lock(_image->_lock);
+        if (_mtlTexture) { return _mtlTexture; }
+
+        MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor();    // temp retain
+        MVKImageMemoryBinding* memoryBinding = getMemoryBinding();
+
+        if (_image->_ioSurface) {
+            _mtlTexture = [_image->getMTLDevice()
+                           newTextureWithDescriptor: mtlTexDesc
+                           iosurface: _image->_ioSurface
+                           plane: _planeIndex];
+        } else if (memoryBinding->_usesTexelBuffer) {
+            _mtlTexture = [memoryBinding->_deviceMemory->getMTLBuffer()
+                           newTextureWithDescriptor: mtlTexDesc
+                           offset: memoryBinding->getDeviceMemoryOffset()
+                           bytesPerRow: _subresources[0].layout.rowPitch];
+        } else if (memoryBinding->_deviceMemory->getMTLHeap() && !_image->getIsDepthStencil()) {
+            // Metal support for depth/stencil from heaps is flaky
+            _mtlTexture = [memoryBinding->_deviceMemory->getMTLHeap()
+                           newTextureWithDescriptor: mtlTexDesc
+                           offset: memoryBinding->getDeviceMemoryOffset()];
+            if (_image->_isAliasable) { [_mtlTexture makeAliasable]; }
+        } else {
+            _mtlTexture = [_image->getMTLDevice() newTextureWithDescriptor: mtlTexDesc];
+        }
+
+        [mtlTexDesc release];                                            // temp release
+
+        propagateDebugName();
+    }
+    return _mtlTexture;
+}
+
+id<MTLTexture> MVKImagePlane::getMTLTexture(MTLPixelFormat mtlPixFmt) {
+    if (mtlPixFmt == _mtlPixFmt) { return _mtlTexture; }
+    id<MTLTexture> mtlTex = _mtlTextureViews[mtlPixFmt];
+    if ( !mtlTex ) {
+        // Lock and check again in case another thread has created the view texture.
+        // baseTex retreived outside of lock to avoid deadlock if it too needs to be lazily created.
+        lock_guard<mutex> lock(_image->_lock);
+        mtlTex = _mtlTextureViews[mtlPixFmt];
+        if ( !mtlTex ) {
+            mtlTex = [_mtlTexture newTextureViewWithPixelFormat: mtlPixFmt];    // retained
+            _mtlTextureViews[mtlPixFmt] = mtlTex;
+        }
+    }
+    return mtlTex;
+}
+
+void MVKImagePlane::releaseMTLTexture() {
+    [_mtlTexture release];
+    for (auto elem : _mtlTextureViews) {
+        [elem.second release];
+    }
+}
+
+// Returns a Metal texture descriptor constructed from the properties of this image.
+// It is the caller's responsibility to release the returned descriptor object.
+MTLTextureDescriptor* MVKImagePlane::newMTLTextureDescriptor() {
+    MTLPixelFormat mtlPixFmt = _mtlPixFmt;
+    MTLTextureUsage minUsage = MTLTextureUsageUnknown;
+#if MVK_MACOS
+    if (_image->_is3DCompressed) {
+        // Metal before 3.0 doesn't support 3D compressed textures, so we'll decompress
+        // the texture ourselves. This, then, is the *uncompressed* format.
+        mtlPixFmt = MTLPixelFormatBGRA8Unorm;
+        minUsage = MTLTextureUsageShaderWrite;
+    }
+#endif
+
+    VkExtent3D extent = _image->getExtent3D(_planeIndex, 0);
+    MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor new];    // retained
+    mtlTexDesc.pixelFormat = mtlPixFmt;
+    mtlTexDesc.textureType = _image->_mtlTextureType;
+    mtlTexDesc.width = extent.width;
+    mtlTexDesc.height = extent.height;
+    mtlTexDesc.depth = extent.depth;
+    mtlTexDesc.mipmapLevelCount = _image->_mipLevels;
+    mtlTexDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_image->_samples);
+    mtlTexDesc.arrayLength = _image->_arrayLayers;
+    mtlTexDesc.usageMVK = _image->getPixelFormats()->getMTLTextureUsage(_image->_usage, mtlPixFmt, minUsage);
+    mtlTexDesc.storageModeMVK = _image->getMTLStorageMode();
+    mtlTexDesc.cpuCacheMode = _image->getMTLCPUCacheMode();
+
+    return mtlTexDesc;
+}
+
+// Initializes the subresource definitions.
+void MVKImagePlane::initSubresources(const VkImageCreateInfo* pCreateInfo) {
+    _subresources.reserve(_image->_mipLevels * _image->_arrayLayers);
+
+    MVKImageSubresource subRez;
+    subRez.subresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << _planeIndex;
+    subRez.layoutState = pCreateInfo->initialLayout;
+
+    VkDeviceSize offset = 0;
+    if (_planeIndex > 0 && _image->_memoryBindings.size() == 1) {
+        auto subresources = &_image->_planes[_planeIndex-1]->_subresources;
+        VkSubresourceLayout& lastLayout = (*subresources)[subresources->size()-1].layout;
+        offset = lastLayout.offset+lastLayout.size;
+    }
+
+    for (uint32_t mipLvl = 0; mipLvl < _image->_mipLevels; mipLvl++) {
+        subRez.subresource.mipLevel = mipLvl;
+        VkDeviceSize rowPitch = _image->getBytesPerRow(_planeIndex, mipLvl);
+        VkDeviceSize depthPitch = _image->getBytesPerLayer(_planeIndex, mipLvl);
+
+        for (uint32_t layer = 0; layer < _image->_arrayLayers; layer++) {
+            subRez.subresource.arrayLayer = layer;
+
+            VkSubresourceLayout& layout = subRez.layout;
+            layout.offset = offset;
+            layout.size = depthPitch * _image->_extent.depth;
+            layout.rowPitch = rowPitch;
+            layout.depthPitch = depthPitch;
+
+            _subresources.push_back(subRez);
+            offset += layout.size;
+        }
+    }
+}
+
+// Returns a pointer to the internal subresource for the specified MIP level layer.
+MVKImageSubresource* MVKImagePlane::getSubresource(uint32_t mipLevel, uint32_t arrayLayer) {
+    uint32_t srIdx = (mipLevel * _image->_arrayLayers) + arrayLayer;
+    return (srIdx < _subresources.size()) ? &_subresources[srIdx] : NULL;
+}
+
+// Updates the contents of the underlying MTLTexture, corresponding to the
+// specified subresource definition, from the underlying memory buffer.
+void MVKImagePlane::updateMTLTextureContent(MVKImageSubresource& subresource,
+                                            VkDeviceSize offset, VkDeviceSize size) {
+
+    VkImageSubresource& imgSubRez = subresource.subresource;
+    VkSubresourceLayout& imgLayout = subresource.layout;
+
+    // Check if subresource overlaps the memory range.
+    VkDeviceSize memStart = offset;
+    VkDeviceSize memEnd = offset + size;
+    VkDeviceSize imgStart = imgLayout.offset;
+    VkDeviceSize imgEnd = imgLayout.offset + imgLayout.size;
+    if (imgStart >= memEnd || imgEnd <= memStart) { return; }
+
+    // Don't update if host memory has not been mapped yet.
+    void* pHostMem = getMemoryBinding()->getHostMemoryAddress();
+    if ( !pHostMem ) { return; }
+
+    VkExtent3D mipExtent = _image->getExtent3D(_planeIndex, imgSubRez.mipLevel);
+    void* pImgBytes = (void*)((uintptr_t)pHostMem + imgLayout.offset);
+
+    MTLRegion mtlRegion;
+    mtlRegion.origin = MTLOriginMake(0, 0, 0);
+    mtlRegion.size = mvkMTLSizeFromVkExtent3D(mipExtent);
+
+#if MVK_MACOS
+    std::unique_ptr<char[]> decompBuffer;
+    if (_image->_is3DCompressed) {
+        // We cannot upload the texture data directly in this case. But we
+        // can upload the decompressed image data.
+        std::unique_ptr<MVKCodec> codec = mvkCreateCodec(_image->getVkFormat());
+        if (!codec) {
+            _image->reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "A 3D texture used a compressed format that MoltenVK does not yet support.");
+            return;
+        }
+        VkSubresourceLayout destLayout;
+        destLayout.rowPitch = 4 * mipExtent.width;
+        destLayout.depthPitch = destLayout.rowPitch * mipExtent.height;
+        destLayout.size = destLayout.depthPitch * mipExtent.depth;
+        decompBuffer = std::unique_ptr<char[]>(new char[destLayout.size]);
+        codec->decompress(decompBuffer.get(), pImgBytes, destLayout, imgLayout, mipExtent);
+        pImgBytes = decompBuffer.get();
+        imgLayout = destLayout;
+    }
+#endif
+
+    VkImageType imgType = _image->getImageType();
+    VkDeviceSize bytesPerRow = (imgType != VK_IMAGE_TYPE_1D) ? imgLayout.rowPitch : 0;
+    VkDeviceSize bytesPerImage = (imgType == VK_IMAGE_TYPE_3D) ? imgLayout.depthPitch : 0;
+
+    id<MTLTexture> mtlTex = getMTLTexture();
+    if (_image->getPixelFormats()->isPVRTCFormat(mtlTex.pixelFormat)) {
+        bytesPerRow = 0;
+        bytesPerImage = 0;
+    }
+
+    [mtlTex replaceRegion: mtlRegion
+              mipmapLevel: imgSubRez.mipLevel
+                    slice: imgSubRez.arrayLayer
+                withBytes: pImgBytes
+              bytesPerRow: bytesPerRow
+            bytesPerImage: bytesPerImage];
+}
+
+// Updates the contents of the underlying memory buffer from the contents of
+// the underlying MTLTexture, corresponding to the specified subresource definition.
+void MVKImagePlane::getMTLTextureContent(MVKImageSubresource& subresource,
+                                         VkDeviceSize offset, VkDeviceSize size) {
+
+    VkImageSubresource& imgSubRez = subresource.subresource;
+    VkSubresourceLayout& imgLayout = subresource.layout;
+
+    // Check if subresource overlaps the memory range.
+    VkDeviceSize memStart = offset;
+    VkDeviceSize memEnd = offset + size;
+    VkDeviceSize imgStart = imgLayout.offset;
+    VkDeviceSize imgEnd = imgLayout.offset + imgLayout.size;
+    if (imgStart >= memEnd || imgEnd <= memStart) { return; }
+
+    // Don't update if host memory has not been mapped yet.
+    void* pHostMem = getMemoryBinding()->getHostMemoryAddress();
+    if ( !pHostMem ) { return; }
+
+    VkExtent3D mipExtent = _image->getExtent3D(_planeIndex, imgSubRez.mipLevel);
+    void* pImgBytes = (void*)((uintptr_t)pHostMem + imgLayout.offset);
+
+    MTLRegion mtlRegion;
+    mtlRegion.origin = MTLOriginMake(0, 0, 0);
+    mtlRegion.size = mvkMTLSizeFromVkExtent3D(mipExtent);
+
+    VkImageType imgType = _image->getImageType();
+    VkDeviceSize bytesPerRow = (imgType != VK_IMAGE_TYPE_1D) ? imgLayout.rowPitch : 0;
+    VkDeviceSize bytesPerImage = (imgType == VK_IMAGE_TYPE_3D) ? imgLayout.depthPitch : 0;
+
+    [_mtlTexture getBytes: pImgBytes
+              bytesPerRow: bytesPerRow
+            bytesPerImage: bytesPerImage
+               fromRegion: mtlRegion
+              mipmapLevel: imgSubRez.mipLevel
+                    slice: imgSubRez.arrayLayer];
+}
+
+void MVKImagePlane::propagateDebugName() {
+    setLabelIfNotNil(_image->_planes[_planeIndex]->_mtlTexture, _image->_debugName);
+}
+
+MVKImageMemoryBinding* MVKImagePlane::getMemoryBinding() const {
+    return (_image->_memoryBindings.size() > 1) ? _image->_memoryBindings[_planeIndex].get() : _image->_memoryBindings[0].get();
+}
+
+MVKImagePlane::MVKImagePlane(MVKImage* image, uint8_t planeIndex) {
+    _image = image;
+    _planeIndex = planeIndex;
+    _mtlTexture = nil;
+}
+
+MVKImagePlane::~MVKImagePlane() {
+    releaseMTLTexture();
+}
+
+
+#pragma mark -
+#pragma mark MVKImageMemoryBinding
+
+VkResult MVKImageMemoryBinding::getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements) {
+    pMemoryRequirements->size = _byteCount;
+    pMemoryRequirements->alignment = _byteAlignment;
+    return VK_SUCCESS;
+}
+
+VkResult MVKImageMemoryBinding::getMemoryRequirements(const void*, VkMemoryRequirements2* pMemoryRequirements) {
+    pMemoryRequirements->sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+    for (auto* next = (VkBaseOutStructure*)pMemoryRequirements->pNext; next; next = next->pNext) {
+        switch (next->sType) {
+        case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
+            auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
+            bool writable = mvkIsAnyFlagEnabled(_image->_usage, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+            dedicatedReqs->requiresDedicatedAllocation = _requiresDedicatedMemoryAllocation;
+            dedicatedReqs->prefersDedicatedAllocation = (dedicatedReqs->requiresDedicatedAllocation ||
+                                                        (!_usesTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps)));
+            break;
+        }
+        default:
+            break;
+        }
+    }
+    return VK_SUCCESS;
+}
+
+// Memory may have been mapped before image was bound, and needs to be loaded into the MTLTexture.
+VkResult MVKImageMemoryBinding::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) {
+    if (_deviceMemory) { _deviceMemory->removeImageMemoryBinding(this); }
+    MVKResource::bindDeviceMemory(mvkMem, memOffset);
+
+    _usesTexelBuffer = _device->_pMetalFeatures->texelBuffers && _deviceMemory && _deviceMemory->_mtlBuffer; // Texel buffers available
+    _usesTexelBuffer = _usesTexelBuffer && (isMemoryHostAccessible() || _device->_pMetalFeatures->placementHeaps) && _image->_isLinear && !_image->getIsCompressed(); // Applicable memory layout
+
+#if MVK_MACOS
+    // macOS cannot use shared memory for texel buffers.
+    // Test _deviceMemory->isMemoryHostCoherent() directly because local version overrides.
+    _usesTexelBuffer = _usesTexelBuffer && _deviceMemory && !_deviceMemory->isMemoryHostCoherent();
+#endif
+
+    flushToDevice(getDeviceMemoryOffset(), getByteCount());
+    return _deviceMemory ? _deviceMemory->addImageMemoryBinding(this) : VK_SUCCESS;
+}
+
+void MVKImageMemoryBinding::applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
+                                               VkPipelineStageFlags dstStageMask,
+                                               MVKPipelineBarrier& barrier,
+                                               MVKCommandEncoder* cmdEncoder,
+                                               MVKCommandUse cmdUse) {
+#if MVK_MACOS
+    if ( needsHostReadSync(srcStageMask, dstStageMask, (VkMemoryBarrier*)&barrier) ) {
+        for(uint8_t planeIndex = beginPlaneIndex(); planeIndex < endPlaneIndex(); planeIndex++) {
+            [cmdEncoder->getMTLBlitEncoder(cmdUse) synchronizeResource: _image->_planes[planeIndex]->_mtlTexture];
+        }
+    }
+#endif
+}
+
+void MVKImageMemoryBinding::propagateDebugName() {
+    for(uint8_t planeIndex = beginPlaneIndex(); planeIndex < endPlaneIndex(); planeIndex++) {
+        _image->_planes[planeIndex]->propagateDebugName();
+    }
+}
+
+// Returns whether the specified image memory barrier requires a sync between this
+// texture and host memory for the purpose of the host reading texture memory.
+bool MVKImageMemoryBinding::needsHostReadSync(VkPipelineStageFlags srcStageMask,
+                                              VkPipelineStageFlags dstStageMask,
+                                              VkMemoryBarrier* pMemoryBarrier) {
+#if MVK_MACOS
+    MVKPipelineBarrier& barrier = *(MVKPipelineBarrier*)pMemoryBarrier;
+    return ((barrier.newLayout == VK_IMAGE_LAYOUT_GENERAL) &&
+            mvkIsAnyFlagEnabled(barrier.dstAccessMask, (VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_READ_BIT)) &&
+            isMemoryHostAccessible() && !isMemoryHostCoherent());
+#endif
+#if MVK_IOS
+    return false;
+#endif
+}
+
+bool MVKImageMemoryBinding::shouldFlushHostMemory() { return isMemoryHostAccessible() && !_usesTexelBuffer; }
+
+// Flushes the device memory at the specified memory range into the MTLTexture. Updates
+// all subresources that overlap the specified range and are in an updatable layout state.
+VkResult MVKImageMemoryBinding::flushToDevice(VkDeviceSize offset, VkDeviceSize size) {
+    if (shouldFlushHostMemory()) {
+        for(uint8_t planeIndex = beginPlaneIndex(); planeIndex < endPlaneIndex(); planeIndex++) {
+            for (auto& subRez : _image->_planes[planeIndex]->_subresources) {
+                switch (subRez.layoutState) {
+                    case VK_IMAGE_LAYOUT_UNDEFINED:
+                    case VK_IMAGE_LAYOUT_PREINITIALIZED:
+                    case VK_IMAGE_LAYOUT_GENERAL: {
+                        _image->_planes[planeIndex]->updateMTLTextureContent(subRez, offset, size);
+                        break;
+                    }
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+    return VK_SUCCESS;
+}
+
+// Pulls content from the MTLTexture into the device memory at the specified memory range.
+// Pulls from all subresources that overlap the specified range and are in an updatable layout state.
+VkResult MVKImageMemoryBinding::pullFromDevice(VkDeviceSize offset, VkDeviceSize size) {
+    if (shouldFlushHostMemory()) {
+        for(uint8_t planeIndex = beginPlaneIndex(); planeIndex < endPlaneIndex(); planeIndex++) {
+            for (auto& subRez : _image->_planes[planeIndex]->_subresources) {
+                switch (subRez.layoutState) {
+                    case VK_IMAGE_LAYOUT_GENERAL: {
+                        _image->_planes[planeIndex]->getMTLTextureContent(subRez, offset, size);
+                        break;
+                    }
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+    return VK_SUCCESS;
+}
+
+uint8_t MVKImageMemoryBinding::beginPlaneIndex() const {
+    return (_image->_memoryBindings.size() > 1) ? _planeIndex : 0;
+}
+
+uint8_t MVKImageMemoryBinding::endPlaneIndex() const {
+    return (_image->_memoryBindings.size() > 1) ? _planeIndex : (uint8_t)_image->_memoryBindings.size();
+}
+
+MVKImageMemoryBinding::MVKImageMemoryBinding(MVKDevice* device, MVKImage* image, uint8_t planeIndex) : MVKResource(device) {
+    _image = image;
+    _planeIndex = planeIndex;
+    _usesTexelBuffer = false;
+}
+
+MVKImageMemoryBinding::~MVKImageMemoryBinding() {
+    if (_deviceMemory) { _deviceMemory->removeImageMemoryBinding(this); }
+}
+
 
 #pragma mark MVKImage
 
-void MVKImage::propogateDebugName() { setLabelIfNotNil(_mtlTexture, _debugName); }
+uint8_t MVKImage::getPlaneFromVkImageAspectFlags(VkImageAspectFlags aspectMask) {
+    return (aspectMask & VK_IMAGE_ASPECT_PLANE_2_BIT) ? 2 :
+           (aspectMask & VK_IMAGE_ASPECT_PLANE_1_BIT) ? 1 :
+           0;
+}
+
+void MVKImage::propagateDebugName() {
+    for (uint8_t planeIndex = 0; planeIndex < _planes.size(); planeIndex++) {
+        _planes[planeIndex]->propagateDebugName();
+    }
+}
 
 VkImageType MVKImage::getImageType() { return mvkVkImageTypeFromMTLTextureType(_mtlTextureType); }
 
-VkFormat MVKImage::getVkFormat() { return getPixelFormats()->getVkFormat(_mtlPixelFormat); }
+bool MVKImage::getIsDepthStencil() { return getPixelFormats()->getFormatType(_vkFormat) == kMVKFormatDepthStencil; }
 
-bool MVKImage::getIsDepthStencil() { return getPixelFormats()->getFormatType(_mtlPixelFormat) == kMVKFormatDepthStencil; }
+bool MVKImage::getIsCompressed() { return getPixelFormats()->getFormatType(_vkFormat) == kMVKFormatCompressed; }
 
-bool MVKImage::getIsCompressed() { return getPixelFormats()->getFormatType(_mtlPixelFormat) == kMVKFormatCompressed; }
-
-VkExtent3D MVKImage::getExtent3D(uint32_t mipLevel) {
-	return mvkMipmapLevelSizeFromBaseSize3D(_extent, mipLevel);
+VkExtent3D MVKImage::getExtent3D(uint8_t planeIndex, uint32_t mipLevel) {
+    VkExtent3D extent = _extent;
+    if (_hasChromaSubsampling) {
+        extent.width /= _planes[planeIndex]->_blockTexelSize.width;
+        extent.height /= _planes[planeIndex]->_blockTexelSize.height;
+    }
+	return mvkMipmapLevelSizeFromBaseSize3D(extent, mipLevel);
 }
 
-VkDeviceSize MVKImage::getBytesPerRow(uint32_t mipLevel) {
-    size_t bytesPerRow = getPixelFormats()->getBytesPerRow(_mtlPixelFormat, getExtent3D(mipLevel).width);
+VkDeviceSize MVKImage::getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel) {
+    size_t bytesPerRow = getPixelFormats()->getBytesPerRow(_vkFormat, getExtent3D(planeIndex, mipLevel).width);
     return mvkAlignByteCount(bytesPerRow, _rowByteAlignment);
 }
 
-VkDeviceSize MVKImage::getBytesPerLayer(uint32_t mipLevel) {
-    return getPixelFormats()->getBytesPerLayer(_mtlPixelFormat, getBytesPerRow(mipLevel), getExtent3D(mipLevel).height);
+VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel) {
+    VkExtent3D extent = getExtent3D(planeIndex, mipLevel);
+    size_t bytesPerRow = getPixelFormats()->getBytesPerRow(_vkFormat, extent.width);
+    return getPixelFormats()->getBytesPerLayer(_vkFormat, bytesPerRow, extent.height);
 }
 
 VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
 										VkSubresourceLayout* pLayout) {
-	MVKImageSubresource* pImgRez = getSubresource(pSubresource->mipLevel,
-												  pSubresource->arrayLayer);
-	if ( !pImgRez ) { return VK_INCOMPLETE; }
+    uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(pSubresource->aspectMask);
+    MVKImageSubresource* pImgRez = _planes[planeIndex]->getSubresource(pSubresource->mipLevel, pSubresource->arrayLayer);
+    if ( !pImgRez ) { return VK_INCOMPLETE; }
 
-	*pLayout = pImgRez->layout;
-	return VK_SUCCESS;
+    *pLayout = pImgRez->layout;
+    return VK_SUCCESS;
 }
 
 void MVKImage::getTransferDescriptorData(MVKImageDescriptorData& imgData) {
@@ -81,254 +496,115 @@
 
 #pragma mark Resource memory
 
-void MVKImage::applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
-								  VkPipelineStageFlags dstStageMask,
-								  VkMemoryBarrier* pMemoryBarrier,
-                                  MVKCommandEncoder* cmdEncoder,
-                                  MVKCommandUse cmdUse) {
-#if MVK_MACOS
-	if ( needsHostReadSync(srcStageMask, dstStageMask, pMemoryBarrier) ) {
-		[cmdEncoder->getMTLBlitEncoder(cmdUse) synchronizeResource: getMTLTexture()];
-	}
-#endif
-}
-
 void MVKImage::applyImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
 									   VkPipelineStageFlags dstStageMask,
-									   VkImageMemoryBarrier* pImageMemoryBarrier,
-                                       MVKCommandEncoder* cmdEncoder,
-                                       MVKCommandUse cmdUse) {
-	const VkImageSubresourceRange& srRange = pImageMemoryBarrier->subresourceRange;
+									   MVKPipelineBarrier& barrier,
+									   MVKCommandEncoder* cmdEncoder,
+									   MVKCommandUse cmdUse) {
 
 	// Extract the mipmap levels that are to be updated
-	uint32_t mipLvlStart = srRange.baseMipLevel;
-	uint32_t mipLvlCnt = srRange.levelCount;
-	uint32_t mipLvlEnd = (mipLvlCnt == VK_REMAINING_MIP_LEVELS
+	uint32_t mipLvlStart = barrier.baseMipLevel;
+	uint32_t mipLvlEnd = (barrier.levelCount == (uint8_t)VK_REMAINING_MIP_LEVELS
 						  ? getMipLevelCount()
-						  : (mipLvlStart + mipLvlCnt));
+						  : (mipLvlStart + barrier.levelCount));
 
 	// Extract the cube or array layers (slices) that are to be updated
-	uint32_t layerStart = srRange.baseArrayLayer;
-	uint32_t layerCnt = srRange.layerCount;
-	uint32_t layerEnd = (layerCnt == VK_REMAINING_ARRAY_LAYERS
+	uint32_t layerStart = barrier.baseArrayLayer;
+	uint32_t layerEnd = (barrier.layerCount == (uint16_t)VK_REMAINING_ARRAY_LAYERS
 						 ? getLayerCount()
-						 : (layerStart + layerCnt));
-
-#if MVK_MACOS
-	bool needsSync = needsHostReadSync(srcStageMask, dstStageMask, pImageMemoryBarrier);
-	id<MTLTexture> mtlTex = needsSync ? getMTLTexture() : nil;
-	id<MTLBlitCommandEncoder> mtlBlitEncoder = needsSync ? cmdEncoder->getMTLBlitEncoder(cmdUse) : nil;
-#endif
+						 : (layerStart + barrier.layerCount));
 
 	// Iterate across mipmap levels and layers, and update the image layout state for each
-	for (uint32_t mipLvl = mipLvlStart; mipLvl < mipLvlEnd; mipLvl++) {
-		for (uint32_t layer = layerStart; layer < layerEnd; layer++) {
-			MVKImageSubresource* pImgRez = getSubresource(mipLvl, layer);
-			if (pImgRez) { pImgRez->layoutState = pImageMemoryBarrier->newLayout; }
+    for (uint8_t planeIndex = 0; planeIndex < _planes.size(); planeIndex++) {
+        if (_hasChromaSubsampling && (barrier.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT << planeIndex)) == 0) { continue; }
+        for (uint32_t mipLvl = mipLvlStart; mipLvl < mipLvlEnd; mipLvl++) {
+            for (uint32_t layer = layerStart; layer < layerEnd; layer++) {
+                MVKImageSubresource* pImgRez = _planes[planeIndex]->getSubresource(mipLvl, layer);
+                if (pImgRez) { pImgRez->layoutState = barrier.newLayout; }
 #if MVK_MACOS
-			if (needsSync) { [mtlBlitEncoder synchronizeTexture: mtlTex slice: layer level: mipLvl]; }
+                bool needsSync = _planes[planeIndex]->getMemoryBinding()->needsHostReadSync(srcStageMask, dstStageMask, (VkMemoryBarrier*)&barrier);
+                id<MTLBlitCommandEncoder> mtlBlitEncoder = needsSync ? cmdEncoder->getMTLBlitEncoder(cmdUse) : nil;
+                if (needsSync) { [mtlBlitEncoder synchronizeTexture: _planes[planeIndex]->_mtlTexture slice: layer level: mipLvl]; }
 #endif
-		}
-	}
+            }
+        }
+    }
 }
 
-// Returns whether the specified image memory barrier requires a sync between this
-// texture and host memory for the purpose of the host reading texture memory.
-bool MVKImage::needsHostReadSync(VkPipelineStageFlags srcStageMask,
-								 VkPipelineStageFlags dstStageMask,
-								 VkImageMemoryBarrier* pImageMemoryBarrier) {
-#if MVK_IOS
-	return false;
-#endif
+VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements, uint8_t planeIndex) {
+    pMemoryRequirements->memoryTypeBits = (_isDepthStencilAttachment)
+                                          ? _device->getPhysicalDevice()->getPrivateMemoryTypes()
+                                          : _device->getPhysicalDevice()->getAllMemoryTypes();
 #if MVK_MACOS
-	return ((pImageMemoryBarrier->newLayout == VK_IMAGE_LAYOUT_GENERAL) &&
-			mvkIsAnyFlagEnabled(pImageMemoryBarrier->dstAccessMask, (VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_READ_BIT)) &&
-			isMemoryHostAccessible() && !isMemoryHostCoherent());
-#endif
-}
-
-// Returns a pointer to the internal subresource for the specified MIP level layer.
-MVKImageSubresource* MVKImage::getSubresource(uint32_t mipLevel, uint32_t arrayLayer) {
-	uint32_t srIdx = (mipLevel * _arrayLayers) + arrayLayer;
-	return (srIdx < _subresources.size()) ? &_subresources[srIdx] : NULL;
-}
-
-VkResult MVKImage::getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements) {
-	pMemoryRequirements->size = _byteCount;
-	pMemoryRequirements->alignment = _byteAlignment;
-	pMemoryRequirements->memoryTypeBits = (_isDepthStencilAttachment
-										   ? _device->getPhysicalDevice()->getPrivateMemoryTypes()
-										   : _device->getPhysicalDevice()->getAllMemoryTypes());
-#if MVK_MACOS
-	// Metal on macOS does not provide native support for host-coherent memory, but Vulkan requires it for Linear images
-	if ( !_isLinear ) {
-		mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
-	}
+    // Metal on macOS does not provide native support for host-coherent memory, but Vulkan requires it for Linear images
+    if ( !_isLinear ) {
+        mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
+    }
 #endif
 #if MVK_IOS
-	// Only transient attachments may use memoryless storage
-	if (!mvkAreAllFlagsEnabled(_usage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ) {
-		mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
-	}
+    // Only transient attachments may use memoryless storage
+    if (!mvkAreAllFlagsEnabled(_usage, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) ) {
+        mvkDisableFlags(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
+    }
 #endif
-	return VK_SUCCESS;
+    return _memoryBindings[planeIndex]->getMemoryRequirements(pMemoryRequirements);
 }
 
-VkResult MVKImage::getMemoryRequirements(const void*, VkMemoryRequirements2* pMemoryRequirements) {
-	pMemoryRequirements->sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
-	getMemoryRequirements(&pMemoryRequirements->memoryRequirements);
+VkResult MVKImage::getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+    uint8_t planeIndex = 0;
 	for (auto* next = (VkBaseOutStructure*)pMemoryRequirements->pNext; next; next = next->pNext) {
 		switch (next->sType) {
-		case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
-			auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
-			bool writable = mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
-			dedicatedReqs->prefersDedicatedAllocation = !_usesTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps);
-			dedicatedReqs->requiresDedicatedAllocation = VK_FALSE;
+		case VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO: {
+			auto* planeReqs = (VkImagePlaneMemoryRequirementsInfo*)next;
+            planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(planeReqs->planeAspect);
 			break;
 		}
 		default:
 			break;
 		}
 	}
-	return VK_SUCCESS;
+    return getMemoryRequirements(&pMemoryRequirements->memoryRequirements, planeIndex);
 }
 
-// Memory may have been mapped before image was bound, and needs to be loaded into the MTLTexture.
-VkResult MVKImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) {
-	if (_deviceMemory) { _deviceMemory->removeImage(this); }
-
-	MVKResource::bindDeviceMemory(mvkMem, memOffset);
-
-	_usesTexelBuffer = validateUseTexelBuffer();
-
-	flushToDevice(getDeviceMemoryOffset(), getByteCount());
-
-	return _deviceMemory ? _deviceMemory->addImage(this) : VK_SUCCESS;
+VkResult MVKImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) {
+    return _memoryBindings[planeIndex]->bindDeviceMemory(mvkMem, memOffset);
 }
 
-bool MVKImage::validateUseTexelBuffer() {
-	VkExtent2D blockExt = getPixelFormats()->getBlockTexelSize(_mtlPixelFormat);
-	bool isUncompressed = blockExt.width == 1 && blockExt.height == 1;
-
-	bool useTexelBuffer = _device->_pMetalFeatures->texelBuffers;								// Texel buffers available
-	useTexelBuffer = useTexelBuffer && (isMemoryHostAccessible() || _device->_pMetalFeatures->placementHeaps) && _isLinear && isUncompressed;	// Applicable memory layout
-	useTexelBuffer = useTexelBuffer && _deviceMemory && _deviceMemory->_mtlBuffer;				// Buffer is available to overlay
-
-#if MVK_MACOS
-	// macOS cannot use shared memory for texel buffers.
-	// Test _deviceMemory->isMemoryHostCoherent() directly because local version overrides.
-	useTexelBuffer = useTexelBuffer && _deviceMemory && !_deviceMemory->isMemoryHostCoherent();
-#endif
-
-	return useTexelBuffer;
-}
-
-bool MVKImage::shouldFlushHostMemory() { return isMemoryHostAccessible() && !_usesTexelBuffer; }
-
-// Flushes the device memory at the specified memory range into the MTLTexture. Updates
-// all subresources that overlap the specified range and are in an updatable layout state.
-VkResult MVKImage::flushToDevice(VkDeviceSize offset, VkDeviceSize size) {
-	if (shouldFlushHostMemory()) {
-		for (auto& subRez : _subresources) {
-			switch (subRez.layoutState) {
-				case VK_IMAGE_LAYOUT_UNDEFINED:
-				case VK_IMAGE_LAYOUT_PREINITIALIZED:
-				case VK_IMAGE_LAYOUT_GENERAL: {
-					updateMTLTextureContent(subRez, offset, size);
-					break;
-				}
-				default:
-					break;
-			}
-		}
-	}
-	return VK_SUCCESS;
-}
-
-// Pulls content from the MTLTexture into the device memory at the specified memory range.
-// Pulls from all subresources that overlap the specified range and are in an updatable layout state.
-VkResult MVKImage::pullFromDevice(VkDeviceSize offset, VkDeviceSize size) {
-	if (shouldFlushHostMemory()) {
-		for (auto& subRez : _subresources) {
-			switch (subRez.layoutState) {
-				case VK_IMAGE_LAYOUT_GENERAL: {
-					getMTLTextureContent(subRez, offset, size);
-					break;
-				}
-				default:
-					break;
-			}
-		}
-	}
-	return VK_SUCCESS;
+VkResult MVKImage::bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) {
+    uint8_t planeIndex = 0;
+    for (const auto* next = (const VkBaseInStructure*)pBindInfo->pNext; next; next = next->pNext) {
+        switch (next->sType) {
+            case VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO: {
+                const VkBindImagePlaneMemoryInfo* imagePlaneMemoryInfo = (const VkBindImagePlaneMemoryInfo*)next;
+                planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(imagePlaneMemoryInfo->planeAspect);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    return bindDeviceMemory((MVKDeviceMemory*)pBindInfo->memory, pBindInfo->memoryOffset, planeIndex);
 }
 
 
 #pragma mark Metal
 
-id<MTLTexture> MVKImage::getMTLTexture() {
-	if ( !_mtlTexture && _mtlPixelFormat ) {
-
-		// Lock and check again in case another thread has created the texture.
-		lock_guard<mutex> lock(_lock);
-		if (_mtlTexture) { return _mtlTexture; }
-
-		_mtlTexture = newMTLTexture();   // retained
-
-		propogateDebugName();
-	}
-	return _mtlTexture;
+id<MTLTexture> MVKImage::getMTLTexture(uint8_t planeIndex) {
+	return _planes[planeIndex]->getMTLTexture();
 }
 
-id<MTLTexture> MVKImage::getMTLTexture(MTLPixelFormat mtlPixFmt) {
-	if (mtlPixFmt == _mtlPixelFormat) { return getMTLTexture(); }
-
-	id<MTLTexture> mtlTex = _mtlTextureViews[mtlPixFmt];
-	if ( !mtlTex ) {
-		// Lock and check again in case another thread has created the view texture.
-		// baseTex retreived outside of lock to avoid deadlock if it too needs to be lazily created.
-		id<MTLTexture> baseTex = getMTLTexture();
-		lock_guard<mutex> lock(_lock);
-		mtlTex = _mtlTextureViews[mtlPixFmt];
-		if ( !mtlTex ) {
-			mtlTex = [baseTex newTextureViewWithPixelFormat: mtlPixFmt];	// retained
-			_mtlTextureViews[mtlPixFmt] = mtlTex;
-		}
-	}
-	return mtlTex;
+id<MTLTexture> MVKImage::getMTLTexture(uint8_t planeIndex, MTLPixelFormat mtlPixFmt) {
+    return _planes[planeIndex]->getMTLTexture(mtlPixFmt);
 }
 
-id<MTLTexture> MVKImage::newMTLTexture() {
-	id<MTLTexture> mtlTex = nil;
-	MTLTextureDescriptor* mtlTexDesc = newMTLTextureDescriptor();	// temp retain
-
-	if (_ioSurface) {
-		mtlTex = [getMTLDevice() newTextureWithDescriptor: mtlTexDesc iosurface: _ioSurface plane: 0];
-	} else if (_usesTexelBuffer) {
-		mtlTex = [_deviceMemory->_mtlBuffer newTextureWithDescriptor: mtlTexDesc
-															  offset: getDeviceMemoryOffset()
-														 bytesPerRow: _subresources[0].layout.rowPitch];
-	} else if (_deviceMemory->_mtlHeap && !getIsDepthStencil()) {	// Metal support for depth/stencil from heaps is flaky
-		mtlTex = [_deviceMemory->_mtlHeap newTextureWithDescriptor: mtlTexDesc
-															offset: getDeviceMemoryOffset()];
-		if (_isAliasable) [mtlTex makeAliasable];
-	} else {
-		mtlTex = [getMTLDevice() newTextureWithDescriptor: mtlTexDesc];
-	}
-
-	[mtlTexDesc release];											// temp release
-	return mtlTex;
-}
-
-VkResult MVKImage::setMTLTexture(id<MTLTexture> mtlTexture) {
+VkResult MVKImage::setMTLTexture(uint8_t planeIndex, id<MTLTexture> mtlTexture) {
 	lock_guard<mutex> lock(_lock);
 
-	releaseMTLTexture();
 	releaseIOSurface();
+    _planes[planeIndex]->releaseMTLTexture();
+	_planes[planeIndex]->_mtlTexture = [mtlTexture retain];		// retained
 
-	_mtlTexture = [mtlTexture retain];		// retained
-
-	_mtlPixelFormat = mtlTexture.pixelFormat;
+    _vkFormat = getPixelFormats()->getVkFormat(mtlTexture.pixelFormat);
 	_mtlTextureType = mtlTexture.textureType;
 	_extent.width = uint32_t(mtlTexture.width);
 	_extent.height = uint32_t(mtlTexture.height);
@@ -336,7 +612,7 @@
 	_mipLevels = uint32_t(mtlTexture.mipmapLevelCount);
 	_samples = mvkVkSampleCountFlagBitsFromSampleCount(mtlTexture.sampleCount);
 	_arrayLayers = uint32_t(mtlTexture.arrayLength);
-	_usage = getPixelFormats()->getVkImageUsageFlags(mtlTexture.usage, _mtlPixelFormat);
+	_usage = getPixelFormats()->getVkImageUsageFlags(mtlTexture.usage, mtlTexture.pixelFormat);
 
 	if (_device->_pMetalFeatures->ioSurfaces) {
 		_ioSurface = mtlTexture.iosurface;
@@ -346,14 +622,6 @@
 	return VK_SUCCESS;
 }
 
-// Removes and releases the MTLTexture object, and all associated texture views
-void MVKImage::releaseMTLTexture() {
-	[_mtlTexture release];
-	_mtlTexture = nil;
-	for (auto elem : _mtlTextureViews) { [elem.second release]; }
-	_mtlTextureViews.clear();
-}
-
 void MVKImage::releaseIOSurface() {
     if (_ioSurface) {
         CFRelease(_ioSurface);
@@ -370,35 +638,60 @@
 
 #if MVK_SUPPORT_IOSURFACE_BOOL
 
-    releaseMTLTexture();
+    for (uint8_t planeIndex = 0; planeIndex < _planes.size(); planeIndex++) {
+        _planes[planeIndex]->releaseMTLTexture();
+    }
     releaseIOSurface();
 
-	MVKPixelFormats* pixFmts = getPixelFormats();
+    MVKPixelFormats* pixFmts = getPixelFormats();
 
 	if (ioSurface) {
 		if (IOSurfaceGetWidth(ioSurface) != _extent.width) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface width %zu does not match VkImage width %d.", IOSurfaceGetWidth(ioSurface), _extent.width); }
 		if (IOSurfaceGetHeight(ioSurface) != _extent.height) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface height %zu does not match VkImage height %d.", IOSurfaceGetHeight(ioSurface), _extent.height); }
-		if (IOSurfaceGetBytesPerElement(ioSurface) != pixFmts->getBytesPerBlock(_mtlPixelFormat)) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface bytes per element %zu does not match VkImage bytes per element %d.", IOSurfaceGetBytesPerElement(ioSurface), pixFmts->getBytesPerBlock(_mtlPixelFormat)); }
-		if (IOSurfaceGetElementWidth(ioSurface) != pixFmts->getBlockTexelSize(_mtlPixelFormat).width) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element width %zu does not match VkImage element width %d.", IOSurfaceGetElementWidth(ioSurface), pixFmts->getBlockTexelSize(_mtlPixelFormat).width); }
-		if (IOSurfaceGetElementHeight(ioSurface) != pixFmts->getBlockTexelSize(_mtlPixelFormat).height) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element height %zu does not match VkImage element height %d.", IOSurfaceGetElementHeight(ioSurface), pixFmts->getBlockTexelSize(_mtlPixelFormat).height); }
+		if (IOSurfaceGetBytesPerElement(ioSurface) != pixFmts->getBytesPerBlock(_vkFormat)) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface bytes per element %zu does not match VkImage bytes per element %d.", IOSurfaceGetBytesPerElement(ioSurface), pixFmts->getBytesPerBlock(_vkFormat)); }
+		if (IOSurfaceGetElementWidth(ioSurface) != pixFmts->getBlockTexelSize(_vkFormat).width) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element width %zu does not match VkImage element width %d.", IOSurfaceGetElementWidth(ioSurface), pixFmts->getBlockTexelSize(_vkFormat).width); }
+		if (IOSurfaceGetElementHeight(ioSurface) != pixFmts->getBlockTexelSize(_vkFormat).height) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element height %zu does not match VkImage element height %d.", IOSurfaceGetElementHeight(ioSurface), pixFmts->getBlockTexelSize(_vkFormat).height); }
+        if (IOSurfaceGetPlaneCount(ioSurface) != _planes.size()) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface plane count %zu does not match VkImage plane count %lu.", IOSurfaceGetPlaneCount(ioSurface), _planes.size()); }
+        if (_hasChromaSubsampling) {
+            for (uint8_t planeIndex = 0; planeIndex < _planes.size(); ++planeIndex) {
+                if (IOSurfaceGetWidthOfPlane(ioSurface, planeIndex) != getExtent3D(planeIndex, 0).width) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface width %zu of plane %d does not match VkImage width %d.", IOSurfaceGetWidthOfPlane(ioSurface, planeIndex), planeIndex, getExtent3D(planeIndex, 0).width); }
+                if (IOSurfaceGetHeightOfPlane(ioSurface, planeIndex) != getExtent3D(planeIndex, 0).height) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface height %zu of plane %d does not match VkImage height %d.", IOSurfaceGetHeightOfPlane(ioSurface, planeIndex), planeIndex, getExtent3D(planeIndex, 0).height); }
+                if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, planeIndex) != _planes[planeIndex]->_bytesPerBlock) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface bytes per element %zu of plane %d does not match VkImage bytes per element %d.", IOSurfaceGetBytesPerElementOfPlane(ioSurface, planeIndex), planeIndex, _planes[planeIndex]->_bytesPerBlock); }
+                if (IOSurfaceGetElementWidthOfPlane(ioSurface, planeIndex) != _planes[planeIndex]->_blockTexelSize.width) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element width %zu of plane %d does not match VkImage element width %d.", IOSurfaceGetElementWidthOfPlane(ioSurface, planeIndex), planeIndex, _planes[planeIndex]->_blockTexelSize.width); }
+                if (IOSurfaceGetElementHeightOfPlane(ioSurface, planeIndex) != _planes[planeIndex]->_blockTexelSize.height) { return reportError(VK_ERROR_INITIALIZATION_FAILED, "vkUseIOSurfaceMVK() : IOSurface element height %zu of plane %d does not match VkImage element height %d.", IOSurfaceGetElementHeightOfPlane(ioSurface, planeIndex), planeIndex, _planes[planeIndex]->_blockTexelSize.height); }
+            }
+        }
 
         _ioSurface = ioSurface;
         CFRetain(_ioSurface);
     } else {
+        @autoreleasepool {
+            CFMutableDictionaryRef properties = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)@{
+			    (id)kIOSurfaceWidth: @(_extent.width),
+			    (id)kIOSurfaceHeight: @(_extent.height),
+			    (id)kIOSurfaceBytesPerElement: @(pixFmts->getBytesPerBlock(_vkFormat)),
+			    (id)kIOSurfaceElementWidth: @(pixFmts->getBlockTexelSize(_vkFormat).width),
+			    (id)kIOSurfaceElementHeight: @(pixFmts->getBlockTexelSize(_vkFormat).height),
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-		@autoreleasepool {
-			_ioSurface = IOSurfaceCreate((CFDictionaryRef)@{
-															(id)kIOSurfaceWidth: @(_extent.width),
-															(id)kIOSurfaceHeight: @(_extent.height),
-															(id)kIOSurfaceBytesPerElement: @(pixFmts->getBytesPerBlock(_mtlPixelFormat)),
-															(id)kIOSurfaceElementWidth: @(pixFmts->getBlockTexelSize(_mtlPixelFormat).width),
-															(id)kIOSurfaceElementHeight: @(pixFmts->getBlockTexelSize(_mtlPixelFormat).height),
-															(id)kIOSurfaceIsGlobal: @(true),    // Deprecated but needed for interprocess transfers
-															});
-		}
+			    (id)kIOSurfaceIsGlobal: @(true), // Deprecated but needed for interprocess transfers
 #pragma clang diagnostic pop
-
+            });
+            if(_hasChromaSubsampling) {
+                CFMutableArrayRef planeProperties = CFArrayCreateMutable(NULL, _planes.size(), NULL);
+                for (uint8_t planeIndex = 0; planeIndex < _planes.size(); ++planeIndex) {
+                    CFArrayAppendValue(planeProperties, (CFDictionaryRef)@{
+                        (id)kIOSurfacePlaneWidth: @(getExtent3D(planeIndex, 0).width),
+                        (id)kIOSurfacePlaneHeight: @(getExtent3D(planeIndex, 0).height),
+                        (id)kIOSurfacePlaneBytesPerElement: @(_planes[planeIndex]->_bytesPerBlock),
+                        (id)kIOSurfacePlaneElementWidth: @(_planes[planeIndex]->_blockTexelSize.width),
+                        (id)kIOSurfacePlaneElementHeight: @(_planes[planeIndex]->_blockTexelSize.height),
+                    });
+                }
+                CFDictionaryAddValue(properties, (id)kIOSurfacePlaneInfo, planeProperties);
+            }
+            _ioSurface = IOSurfaceCreate(properties);
+        }
     }
 
 #endif
@@ -406,40 +699,10 @@
     return VK_SUCCESS;
 }
 
-// Returns a Metal texture descriptor constructed from the properties of this image.
-// It is the caller's responsibility to release the returned descriptor object.
-MTLTextureDescriptor* MVKImage::newMTLTextureDescriptor() {
-	MTLPixelFormat mtlPixFmt = _mtlPixelFormat;
-	MTLTextureUsage minUsage = MTLTextureUsageUnknown;
-#if MVK_MACOS
-	if (_is3DCompressed) {
-		// Metal before 3.0 doesn't support 3D compressed textures, so we'll decompress
-		// the texture ourselves. This, then, is the *uncompressed* format.
-		mtlPixFmt = MTLPixelFormatBGRA8Unorm;
-		minUsage = MTLTextureUsageShaderWrite;
-	}
-#endif
-
-	MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor new];	// retained
-	mtlTexDesc.pixelFormat = mtlPixFmt;
-	mtlTexDesc.textureType = _mtlTextureType;
-	mtlTexDesc.width = _extent.width;
-	mtlTexDesc.height = _extent.height;
-	mtlTexDesc.depth = _extent.depth;
-	mtlTexDesc.mipmapLevelCount = _mipLevels;
-	mtlTexDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_samples);
-	mtlTexDesc.arrayLength = _arrayLayers;
-	mtlTexDesc.usageMVK = getPixelFormats()->getMTLTextureUsage(_usage, mtlPixFmt, minUsage);
-	mtlTexDesc.storageModeMVK = getMTLStorageMode();
-	mtlTexDesc.cpuCacheMode = getMTLCPUCacheMode();
-
-	return mtlTexDesc;
-}
-
 MTLStorageMode MVKImage::getMTLStorageMode() {
-    if ( !_deviceMemory ) return MTLStorageModePrivate;
+    if ( !_memoryBindings[0]->_deviceMemory ) return MTLStorageModePrivate;
 
-    MTLStorageMode stgMode = _deviceMemory->getMTLStorageMode();
+    MTLStorageMode stgMode = _memoryBindings[0]->_deviceMemory->getMTLStorageMode();
 
     if (_ioSurface && stgMode == MTLStorageModePrivate) { stgMode = MTLStorageModeShared; }
 
@@ -451,121 +714,17 @@
 }
 
 MTLCPUCacheMode MVKImage::getMTLCPUCacheMode() {
-	return _deviceMemory ? _deviceMemory->getMTLCPUCacheMode() : MTLCPUCacheModeDefaultCache;
+	return _memoryBindings[0]->_deviceMemory ? _memoryBindings[0]->_deviceMemory->getMTLCPUCacheMode() : MTLCPUCacheModeDefaultCache;
 }
 
 bool MVKImage::isMemoryHostCoherent() {
     return (getMTLStorageMode() == MTLStorageModeShared);
 }
 
-// Updates the contents of the underlying MTLTexture, corresponding to the
-// specified subresource definition, from the underlying memory buffer.
-void MVKImage::updateMTLTextureContent(MVKImageSubresource& subresource,
-                                       VkDeviceSize offset, VkDeviceSize size) {
-
-	VkImageSubresource& imgSubRez = subresource.subresource;
-	VkSubresourceLayout& imgLayout = subresource.layout;
-
-	// Check if subresource overlaps the memory range.
-    VkDeviceSize memStart = offset;
-    VkDeviceSize memEnd = offset + size;
-    VkDeviceSize imgStart = imgLayout.offset;
-    VkDeviceSize imgEnd = imgLayout.offset + imgLayout.size;
-    if (imgStart >= memEnd || imgEnd <= memStart) { return; }
-
-	// Don't update if host memory has not been mapped yet.
-	void* pHostMem = getHostMemoryAddress();
-	if ( !pHostMem ) { return; }
-
-    VkExtent3D mipExtent = getExtent3D(imgSubRez.mipLevel);
-    VkImageType imgType = getImageType();
-    void* pImgBytes = (void*)((uintptr_t)pHostMem + imgLayout.offset);
-
-    MTLRegion mtlRegion;
-    mtlRegion.origin = MTLOriginMake(0, 0, 0);
-    mtlRegion.size = mvkMTLSizeFromVkExtent3D(mipExtent);
-
-#if MVK_MACOS
-    std::unique_ptr<char[]> decompBuffer;
-    if (_is3DCompressed) {
-        // We cannot upload the texture data directly in this case. But we
-        // can upload the decompressed image data.
-        std::unique_ptr<MVKCodec> codec = mvkCreateCodec(getVkFormat());
-        if (!codec) {
-            reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "A 3D texture used a compressed format that MoltenVK does not yet support.");
-            return;
-        }
-        VkSubresourceLayout destLayout;
-        destLayout.rowPitch = 4 * mipExtent.width;
-        destLayout.depthPitch = destLayout.rowPitch * mipExtent.height;
-        destLayout.size = destLayout.depthPitch * mipExtent.depth;
-        decompBuffer = std::unique_ptr<char[]>(new char[destLayout.size]);
-        codec->decompress(decompBuffer.get(), pImgBytes, destLayout, imgLayout, mipExtent);
-        pImgBytes = decompBuffer.get();
-        imgLayout = destLayout;
-    }
-#endif
-
-	VkDeviceSize bytesPerRow = (imgType != VK_IMAGE_TYPE_1D) ? imgLayout.rowPitch : 0;
-	VkDeviceSize bytesPerImage = (imgType == VK_IMAGE_TYPE_3D) ? imgLayout.depthPitch : 0;
-
-	id<MTLTexture> mtlTex = getMTLTexture();
-	if (getPixelFormats()->isPVRTCFormat(mtlTex.pixelFormat)) {
-		bytesPerRow = 0;
-		bytesPerImage = 0;
-	}
-
-	[mtlTex replaceRegion: mtlRegion
-			  mipmapLevel: imgSubRez.mipLevel
-					slice: imgSubRez.arrayLayer
-				withBytes: pImgBytes
-			  bytesPerRow: bytesPerRow
-			bytesPerImage: bytesPerImage];
-}
-
-// Updates the contents of the underlying memory buffer from the contents of
-// the underlying MTLTexture, corresponding to the specified subresource definition.
-void MVKImage::getMTLTextureContent(MVKImageSubresource& subresource,
-                                    VkDeviceSize offset, VkDeviceSize size) {
-
-	VkImageSubresource& imgSubRez = subresource.subresource;
-	VkSubresourceLayout& imgLayout = subresource.layout;
-
-	// Check if subresource overlaps the memory range.
-    VkDeviceSize memStart = offset;
-    VkDeviceSize memEnd = offset + size;
-    VkDeviceSize imgStart = imgLayout.offset;
-    VkDeviceSize imgEnd = imgLayout.offset + imgLayout.size;
-    if (imgStart >= memEnd || imgEnd <= memStart) { return; }
-
-	// Don't update if host memory has not been mapped yet.
-	void* pHostMem = getHostMemoryAddress();
-	if ( !pHostMem ) { return; }
-
-    VkExtent3D mipExtent = getExtent3D(imgSubRez.mipLevel);
-    VkImageType imgType = getImageType();
-    void* pImgBytes = (void*)((uintptr_t)pHostMem + imgLayout.offset);
-
-    MTLRegion mtlRegion;
-    mtlRegion.origin = MTLOriginMake(0, 0, 0);
-    mtlRegion.size = mvkMTLSizeFromVkExtent3D(mipExtent);
-
-    [getMTLTexture() getBytes: pImgBytes
-                  bytesPerRow: (imgType != VK_IMAGE_TYPE_1D ? imgLayout.rowPitch : 0)
-                bytesPerImage: (imgType == VK_IMAGE_TYPE_3D ? imgLayout.depthPitch : 0)
-                   fromRegion: mtlRegion
-                  mipmapLevel: imgSubRez.mipLevel
-                        slice: imgSubRez.arrayLayer];
-}
-
-
 #pragma mark Construction
 
-MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MVKResource(device) {
-
-	_mtlTexture = nil;
+MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
 	_ioSurface = nil;
-	_usesTexelBuffer = false;
 
     // Adjust the info components to be compatible with Metal, then use the modified versions to set other
 	// config info. Vulkan allows unused extent dimensions to be zero, but Metal requires minimum of one.
@@ -589,32 +748,65 @@
 	_isLinear = validateLinear(pCreateInfo, isAttachment);
 
 	MVKPixelFormats* pixFmts = getPixelFormats();
-	_mtlPixelFormat = pixFmts->getMTLPixelFormat(pCreateInfo->format);
+    _vkFormat = pCreateInfo->format;
 	_usage = pCreateInfo->usage;
 
 	_is3DCompressed = (getImageType() == VK_IMAGE_TYPE_3D) && (pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatCompressed) && !_device->_pMetalFeatures->native3DCompressedTextures;
 	_isDepthStencilAttachment = (mvkAreAllFlagsEnabled(pCreateInfo->usage, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
 								 mvkAreAllFlagsEnabled(pixFmts->getVkFormatProperties(pCreateInfo->format).optimalTilingFeatures, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT));
 	_canSupportMTLTextureView = !_isDepthStencilAttachment || _device->_pMetalFeatures->stencilViews;
-	_hasExpectedTexelSize = (pixFmts->getBytesPerBlock(_mtlPixelFormat) == pixFmts->getBytesPerBlock(pCreateInfo->format));
-
 	_rowByteAlignment = _isLinear ? _device->getVkFormatTexelBufferAlignment(pCreateInfo->format, this) : mvkEnsurePowerOfTwo(pixFmts->getBytesPerBlock(pCreateInfo->format));
-	if (!_isLinear && _device->_pMetalFeatures->placementHeaps) {
-		MTLTextureDescriptor *mtlTexDesc = newMTLTextureDescriptor();	// temp retain
-		MTLSizeAndAlign sizeAndAlign = [_device->getMTLDevice() heapTextureSizeAndAlignWithDescriptor: mtlTexDesc];
-		[mtlTexDesc release];
-		_byteCount = sizeAndAlign.size;
-		_byteAlignment = sizeAndAlign.align;
-		_isAliasable = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_ALIAS_BIT);
-	} else {
-		// Calc _byteCount after _rowByteAlignment
-		_byteAlignment = _rowByteAlignment;
-		for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
-			_byteCount += getBytesPerLayer(mipLvl) * _extent.depth * _arrayLayers;
+
+    VkExtent2D blockTexelSizeOfPlane[3];
+    uint32_t bytesPerBlockOfPlane[3];
+    MTLPixelFormat mtlPixFmtOfPlane[3];
+    uint8_t subsamplingPlaneCount = pixFmts->getChromaSubsamplingPlanes(_vkFormat, blockTexelSizeOfPlane, bytesPerBlockOfPlane, mtlPixFmtOfPlane),
+            planeCount = std::max(subsamplingPlaneCount, (uint8_t)1),
+            memoryBindingCount = (pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT) ? planeCount : 1;
+    _hasChromaSubsampling = (subsamplingPlaneCount > 0);
+
+    for (uint8_t planeIndex = 0; planeIndex < memoryBindingCount; ++planeIndex) {
+        _memoryBindings.push_back(std::unique_ptr<MVKImageMemoryBinding>(new MVKImageMemoryBinding(device, this, planeIndex)));
+    }
+
+    for (uint8_t planeIndex = 0; planeIndex < planeCount; ++planeIndex) {
+        _planes.push_back(std::unique_ptr<MVKImagePlane>(new MVKImagePlane(this, planeIndex)));
+        if (_hasChromaSubsampling) {
+            _planes[planeIndex]->_blockTexelSize = blockTexelSizeOfPlane[planeIndex];
+            _planes[planeIndex]->_bytesPerBlock = bytesPerBlockOfPlane[planeIndex];
+            _planes[planeIndex]->_mtlPixFmt = mtlPixFmtOfPlane[planeIndex];
+        } else {
+            _planes[planeIndex]->_mtlPixFmt = getPixelFormats()->getMTLPixelFormat(_vkFormat);
+        }
+        _planes[planeIndex]->initSubresources(pCreateInfo);
+        MVKImageMemoryBinding* memoryBinding = _planes[planeIndex]->getMemoryBinding();
+        if (!_isLinear && _device->_pMetalFeatures->placementHeaps) {
+            MTLTextureDescriptor* mtlTexDesc = _planes[planeIndex]->newMTLTextureDescriptor();    // temp retain
+            MTLSizeAndAlign sizeAndAlign = [_device->getMTLDevice() heapTextureSizeAndAlignWithDescriptor: mtlTexDesc];
+            [mtlTexDesc release];
+            memoryBinding->_byteCount += sizeAndAlign.size;
+            memoryBinding->_byteAlignment = std::max(memoryBinding->_byteAlignment, (VkDeviceSize)sizeAndAlign.align);
+            _isAliasable = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_ALIAS_BIT);
+        } else {
+            for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
+                memoryBinding->_byteCount += getBytesPerLayer(planeIndex, mipLvl) * _extent.depth * _arrayLayers;
+            }
+            memoryBinding->_byteAlignment = std::max(memoryBinding->_byteAlignment, _rowByteAlignment);
+        }
+    }
+    _hasExpectedTexelSize = _hasChromaSubsampling || (pixFmts->getBytesPerBlock(_planes[0]->_mtlPixFmt) == pixFmts->getBytesPerBlock(_vkFormat));
+
+	for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+		switch (next->sType) {
+			case VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO: {
+				auto* pExtMemInfo = (const VkExternalMemoryImageCreateInfo*)next;
+				initExternalMemory(pExtMemInfo->handleTypes);
+				break;
+			}
+			default:
+				break;
 		}
 	}
-
-    initSubresources(pCreateInfo);
 }
 
 VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
@@ -741,52 +933,19 @@
 	return isLin;
 }
 
-
-// Initializes the subresource definitions.
-void MVKImage::initSubresources(const VkImageCreateInfo* pCreateInfo) {
-	_subresources.reserve(_mipLevels * _arrayLayers);
-
-	MVKImageSubresource subRez;
-	subRez.layoutState = pCreateInfo->initialLayout;
-
-	for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
-		subRez.subresource.mipLevel = mipLvl;
-
-		for (uint32_t layer = 0; layer < _arrayLayers; layer++) {
-			subRez.subresource.arrayLayer = layer;
-			initSubresourceLayout(subRez);
-			_subresources.push_back(subRez);
-		}
+void MVKImage::initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes) {
+	if (mvkIsOnlyAnyFlagEnabled(handleTypes, VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR)) {
+        auto& xmProps = _device->getPhysicalDevice()->getExternalImageProperties(VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR);
+        for(auto& memoryBinding : _memoryBindings) {
+            memoryBinding->_externalMemoryHandleTypes = handleTypes;
+            memoryBinding->_requiresDedicatedMemoryAllocation = memoryBinding->_requiresDedicatedMemoryAllocation || mvkIsAnyFlagEnabled(xmProps.externalMemoryFeatures, VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT);
+        }
+	} else {
+		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage(): Only external memory handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLTEXTURE_BIT_KHR is supported."));
 	}
 }
 
-// Initializes the layout element of the specified image subresource.
-void MVKImage::initSubresourceLayout(MVKImageSubresource& imgSubRez) {
-	VkImageSubresource subresource = imgSubRez.subresource;
-	uint32_t currMipLevel = subresource.mipLevel;
-	uint32_t currArrayLayer = subresource.arrayLayer;
-
-	VkDeviceSize bytesPerLayerCurrLevel = getBytesPerLayer(currMipLevel);
-
-	// Accumulate the byte offset for the specified sub-resource.
-	// This is the sum of the bytes consumed by all layers in all mipmap levels before the
-	// desired level, plus the layers before the desired layer at the desired level.
-	VkDeviceSize offset = 0;
-	for (uint32_t mipLvl = 0; mipLvl < currMipLevel; mipLvl++) {
-		offset += (getBytesPerLayer(mipLvl) * _extent.depth * _arrayLayers);
-	}
-	offset += (bytesPerLayerCurrLevel * currArrayLayer);
-
-	VkSubresourceLayout& layout = imgSubRez.layout;
-	layout.offset = offset;
-	layout.size = bytesPerLayerCurrLevel;
-	layout.rowPitch = getBytesPerRow(currMipLevel);
-	layout.depthPitch = bytesPerLayerCurrLevel;
-}
-
 MVKImage::~MVKImage() {
-	if (_deviceMemory) { _deviceMemory->removeImage(this); }
-	releaseMTLTexture();
     releaseIOSurface();
 }
 
@@ -794,7 +953,7 @@
 #pragma mark -
 #pragma mark MVKSwapchainImage
 
-VkResult MVKSwapchainImage::bindDeviceMemory(MVKDeviceMemory*, VkDeviceSize) {
+VkResult MVKSwapchainImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) {
 	return VK_ERROR_OUT_OF_DEVICE_MEMORY;
 }
 
@@ -802,7 +961,7 @@
 #pragma mark Metal
 
 // Overridden to always retrieve the MTLTexture directly from the CAMetalDrawable.
-id<MTLTexture> MVKSwapchainImage::getMTLTexture() { return [getCAMetalDrawable() texture]; }
+id<MTLTexture> MVKSwapchainImage::getMTLTexture(uint8_t planeIndex) { return [getCAMetalDrawable() texture]; }
 
 
 #pragma mark Construction
@@ -848,7 +1007,7 @@
 		// If this image is available, signal the semaphore and fence that were associated
 		// with the last time this image was acquired while available. This is a workaround for
 		// when an app uses a single semaphore or fence for more than one swapchain image.
-		// Becuase the semaphore or fence will be signaled by more than one image, it will
+		// Because the semaphore or fence will be signaled by more than one image, it will
 		// get out of sync, and the final use of the image would not be signaled as a result.
 		signaler = _preSignaler;
 	} else {
@@ -943,12 +1102,19 @@
 }
 
 // Present the drawable and make myself available only once the command buffer has completed.
-void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff) {
-	_swapchain->willPresentSurface(getMTLTexture(), mtlCmdBuff);
+void MVKPresentableSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff, bool hasPresentTime, uint32_t presentID, uint64_t desiredPresentTime) {
+	_swapchain->willPresentSurface(getMTLTexture(0), mtlCmdBuff);
 
 	NSString* scName = _swapchain->getDebugName();
 	if (scName) { mvkPushDebugGroup(mtlCmdBuff, scName); }
-	[mtlCmdBuff presentDrawable: getCAMetalDrawable()];
+	if (!hasPresentTime) {
+		[mtlCmdBuff presentDrawable: getCAMetalDrawable()];
+	}
+	else {
+		// Convert from nsecs to seconds
+		CFTimeInterval presentTimeSeconds = ( double ) desiredPresentTime * 1.0e-9;
+		[mtlCmdBuff presentDrawable: getCAMetalDrawable() atTime:(CFTimeInterval)presentTimeSeconds];
+	}
 	if (scName) { mvkPopDebugGroup(mtlCmdBuff); }
 
 	signalPresentationSemaphore(mtlCmdBuff);
@@ -958,12 +1124,29 @@
 		makeAvailable();
 		release();
 	}];
+	
+	if (hasPresentTime) {
+		if ([_mtlDrawable respondsToSelector: @selector(addPresentedHandler:)]) {
+			[_mtlDrawable addPresentedHandler: ^(id<MTLDrawable> drawable) {
+				// Record the presentation time
+				CFTimeInterval presentedTimeSeconds = drawable.presentedTime;
+				uint64_t presentedTimeNanoseconds = (uint64_t)(presentedTimeSeconds * 1.0e9);
+				_swapchain->recordPresentTime(presentID, desiredPresentTime, presentedTimeNanoseconds);
+			}];
+		} else {
+			// If MTLDrawable.presentedTime/addPresentedHandler isn't supported, just treat it as if the
+			// present happened when requested
+			_swapchain->recordPresentTime(presentID, desiredPresentTime, desiredPresentTime);
+		}
+	}
 }
 
 // Resets the MTLTexture and CAMetalDrawable underlying this image.
 void MVKPresentableSwapchainImage::releaseMetalDrawable() {
-	releaseMTLTexture();			// Release texture first so drawable will be last to release it
-	[_mtlDrawable release];
+    for (uint8_t planeIndex = 0; planeIndex < _planes.size(); ++planeIndex) {
+        _planes[planeIndex]->releaseMTLTexture();
+    }
+    [_mtlDrawable release];
 	_mtlDrawable = nil;
 }
 
@@ -991,10 +1174,9 @@
 #pragma mark -
 #pragma mark MVKPeerSwapchainImage
 
-VkResult MVKPeerSwapchainImage::bindDeviceMemory2(const void* pBindInfo) {
-	const auto* imageInfo = (const VkBindImageMemoryInfo*)pBindInfo;
+VkResult MVKPeerSwapchainImage::bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) {
 	const VkBindImageMemorySwapchainInfoKHR* swapchainInfo = nullptr;
-	for (const auto* next = (const VkBaseInStructure*)imageInfo->pNext; next; next = next->pNext) {
+	for (const auto* next = (const VkBaseInStructure*)pBindInfo->pNext; next; next = next->pNext) {
 		switch (next->sType) {
 			case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR:
 				swapchainInfo = (const VkBindImageMemorySwapchainInfoKHR*)next;
@@ -1002,11 +1184,9 @@
 			default:
 				break;
 		}
-		if (swapchainInfo) { break; }
 	}
-	if (!swapchainInfo) {
-		return VK_ERROR_OUT_OF_DEVICE_MEMORY;
-	}
+	if (!swapchainInfo) { return VK_ERROR_OUT_OF_DEVICE_MEMORY; }
+
 	_swapchainIndex = swapchainInfo->imageIndex;
 	return VK_SUCCESS;
 }
@@ -1030,82 +1210,138 @@
 
 
 #pragma mark -
+#pragma mark MVKImageViewPlane
+
+void MVKImageViewPlane::propagateDebugName() { setLabelIfNotNil(_mtlTexture, _imageView->_debugName); }
+
+
+#pragma mark Metal
+
+id<MTLTexture> MVKImageViewPlane::getMTLTexture() {
+    // If we can use a Metal texture view, lazily create it, otherwise use the image texture directly.
+    if (_useMTLTextureView) {
+        if ( !_mtlTexture && _mtlPixFmt ) {
+
+            // Lock and check again in case another thread created the texture view
+            lock_guard<mutex> lock(_imageView->_lock);
+            if (_mtlTexture) { return _mtlTexture; }
+
+            _mtlTexture = newMTLTexture(); // retained
+
+            propagateDebugName();
+        }
+        return _mtlTexture;
+    } else {
+        return _imageView->_image->getMTLTexture(_planeIndex);
+    }
+}
+
+// Creates and returns a retained Metal texture as an
+// overlay on the Metal texture of the underlying image.
+id<MTLTexture> MVKImageViewPlane::newMTLTexture() {
+    MTLTextureType mtlTextureType = _imageView->_mtlTextureType;
+    NSRange sliceRange = NSMakeRange(_imageView->_subresourceRange.baseArrayLayer, _imageView->_subresourceRange.layerCount);
+    // Fake support for 2D views of 3D textures.
+    if (_imageView->_image->getImageType() == VK_IMAGE_TYPE_3D &&
+        (mtlTextureType == MTLTextureType2D || mtlTextureType == MTLTextureType2DArray)) {
+        mtlTextureType = MTLTextureType3D;
+        sliceRange = NSMakeRange(0, 1);
+    }
+    id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(MVKImage::getPlaneFromVkImageAspectFlags(_imageView->_subresourceRange.aspectMask));
+    if (_imageView->_device->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
+        return [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
+                                         textureType: mtlTextureType
+                                              levels: NSMakeRange(_imageView->_subresourceRange.baseMipLevel, _imageView->_subresourceRange.levelCount)
+                                              slices: sliceRange
+                                             swizzle: mvkMTLTextureSwizzleChannelsFromVkComponentMapping(mvkUnpackSwizzle(_packedSwizzle))];    // retained
+    } else {
+        return [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
+                                         textureType: mtlTextureType
+                                              levels: NSMakeRange(_imageView->_subresourceRange.baseMipLevel, _imageView->_subresourceRange.levelCount)
+                                              slices: sliceRange];    // retained
+    }
+}
+
+
+#pragma mark Construction
+
+MVKImageViewPlane::MVKImageViewPlane(MVKImageView* imageView, uint8_t planeIndex, MTLPixelFormat mtlPixFmt, const VkImageViewCreateInfo* pCreateInfo) {
+    _imageView = imageView;
+    _planeIndex = planeIndex;
+    _mtlPixFmt = mtlPixFmt;
+    _mtlTexture = nil;
+
+    bool useSwizzle;
+    _imageView->setConfigurationResult(MVKImageView::validateSwizzledMTLPixelFormat(
+        pCreateInfo,
+        _imageView,
+        _imageView->_device->_pMetalFeatures->nativeTextureSwizzle,
+        _imageView->_device->_pMVKConfig->fullImageViewSwizzle,
+        mtlPixFmt,
+        useSwizzle
+    ));
+    _packedSwizzle = (useSwizzle) ? mvkPackSwizzle(pCreateInfo->components) : 0;
+
+    // Determine whether this image view should use a Metal texture view,
+    // and set the _useMTLTextureView variable appropriately.
+    if ( _imageView->_image ) {
+        _useMTLTextureView = _imageView->_image->_canSupportMTLTextureView;
+        bool is3D = _imageView->_image->_mtlTextureType == MTLTextureType3D;
+        // If the view is identical to underlying image, don't bother using a Metal view
+        if (_mtlPixFmt == _imageView->_image->getMTLPixelFormat(planeIndex) &&
+            (_imageView->_mtlTextureType == _imageView->_image->_mtlTextureType ||
+             ((_imageView->_mtlTextureType == MTLTextureType2D || _imageView->_mtlTextureType == MTLTextureType2DArray) && is3D)) &&
+            _imageView->_subresourceRange.levelCount == _imageView->_image->_mipLevels &&
+            (is3D || _imageView->_subresourceRange.layerCount == _imageView->_image->_arrayLayers) &&
+            (!_imageView->_device->_pMetalFeatures->nativeTextureSwizzle || !_packedSwizzle)) {
+            _useMTLTextureView = false;
+        }
+    } else {
+        _useMTLTextureView = false;
+    }
+}
+
+MVKImageViewPlane::~MVKImageViewPlane() {
+    [_mtlTexture release];
+}
+
+
+#pragma mark -
 #pragma mark MVKImageView
 
-void MVKImageView::propogateDebugName() { setLabelIfNotNil(_mtlTexture, _debugName); }
+void MVKImageView::propagateDebugName() {
+    for (uint8_t planeIndex = 0; planeIndex < _planes.size(); planeIndex++) {
+        _planes[planeIndex]->propagateDebugName();
+    }
+}
 
 void MVKImageView::populateMTLRenderPassAttachmentDescriptor(MTLRenderPassAttachmentDescriptor* mtlAttDesc) {
-    mtlAttDesc.texture = getMTLTexture();           // Use image view, necessary if image view format differs from image format
-    mtlAttDesc.level = _useMTLTextureView ? 0 : _subresourceRange.baseMipLevel;
+    MVKImageViewPlane* plane = _planes[0].get();
+    mtlAttDesc.texture = plane->getMTLTexture();           // Use image view, necessary if image view format differs from image format
+    mtlAttDesc.level = plane->_useMTLTextureView ? 0 : _subresourceRange.baseMipLevel;
     if (mtlAttDesc.texture.textureType == MTLTextureType3D) {
         mtlAttDesc.slice = 0;
-        mtlAttDesc.depthPlane = _useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
+        mtlAttDesc.depthPlane = plane->_useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
     } else {
-        mtlAttDesc.slice = _useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
+        mtlAttDesc.slice = plane->_useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
         mtlAttDesc.depthPlane = 0;
     }
 }
 
 void MVKImageView::populateMTLRenderPassAttachmentDescriptorResolve(MTLRenderPassAttachmentDescriptor* mtlAttDesc) {
-    mtlAttDesc.resolveTexture = getMTLTexture();    // Use image view, necessary if image view format differs from image format
-    mtlAttDesc.resolveLevel = _useMTLTextureView ? 0 : _subresourceRange.baseMipLevel;
+    MVKImageViewPlane* plane = _planes[0].get();
+    mtlAttDesc.resolveTexture = plane->getMTLTexture();    // Use image view, necessary if image view format differs from image format
+    mtlAttDesc.resolveLevel = plane->_useMTLTextureView ? 0 : _subresourceRange.baseMipLevel;
     if (mtlAttDesc.resolveTexture.textureType == MTLTextureType3D) {
         mtlAttDesc.resolveSlice = 0;
-        mtlAttDesc.resolveDepthPlane = _useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
+        mtlAttDesc.resolveDepthPlane = plane->_useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
     } else {
-        mtlAttDesc.resolveSlice = _useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
+        mtlAttDesc.resolveSlice = plane->_useMTLTextureView ? 0 : _subresourceRange.baseArrayLayer;
         mtlAttDesc.resolveDepthPlane = 0;
     }
 }
 
 
-#pragma mark Metal
-
-id<MTLTexture> MVKImageView::getMTLTexture() {
-	// If we can use a Metal texture view, lazily create it, otherwise use the image texture directly.
-	if (_useMTLTextureView) {
-		if ( !_mtlTexture && _mtlPixelFormat ) {
-
-			// Lock and check again in case another thread created the texture view
-			lock_guard<mutex> lock(_lock);
-			if (_mtlTexture) { return _mtlTexture; }
-
-			_mtlTexture = newMTLTexture(); // retained
-
-			propogateDebugName();
-		}
-		return _mtlTexture;
-	} else {
-		return _image->getMTLTexture();
-	}
-}
-
-// Creates and returns a retained Metal texture as an
-// overlay on the Metal texture of the underlying image.
-id<MTLTexture> MVKImageView::newMTLTexture() {
-    MTLTextureType mtlTextureType = _mtlTextureType;
-    NSRange sliceRange = NSMakeRange(_subresourceRange.baseArrayLayer, _subresourceRange.layerCount);
-    // Fake support for 2D views of 3D textures.
-    if (_image->getImageType() == VK_IMAGE_TYPE_3D &&
-        (mtlTextureType == MTLTextureType2D || mtlTextureType == MTLTextureType2DArray)) {
-        mtlTextureType = MTLTextureType3D;
-        sliceRange = NSMakeRange(0, 1);
-    }
-    if (_device->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
-        return [_image->getMTLTexture() newTextureViewWithPixelFormat: _mtlPixelFormat
-                                                          textureType: mtlTextureType
-                                                               levels: NSMakeRange(_subresourceRange.baseMipLevel, _subresourceRange.levelCount)
-                                                               slices: sliceRange
-                                                              swizzle: mvkMTLTextureSwizzleChannelsFromVkComponentMapping(mvkUnpackSwizzle(_packedSwizzle))];	// retained
-    } else {
-        return [_image->getMTLTexture() newTextureViewWithPixelFormat: _mtlPixelFormat
-                                                          textureType: mtlTextureType
-                                                               levels: NSMakeRange(_subresourceRange.baseMipLevel, _subresourceRange.levelCount)
-                                                               slices: sliceRange];	// retained
-    }
-}
-
-
 #pragma mark Construction
 
 MVKImageView::MVKImageView(MVKDevice* device,
@@ -1113,23 +1349,42 @@
 						   const MVKConfiguration* pAltMVKConfig) : MVKVulkanAPIDeviceObject(device) {
 	_image = (MVKImage*)pCreateInfo->image;
 	_usage = _image->_usage;
+    _mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType,
+    _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT);
 
-	auto* next = (MVKVkAPIStructHeader*)pCreateInfo->pNext;
-	while (next) {
-		switch ((uint32_t)next->sType) {
+	for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+		switch (next->sType) {
 			case VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO: {
 				auto* pViewUsageInfo = (VkImageViewUsageCreateInfo*)next;
 				if (!(pViewUsageInfo->usage & ~_usage)) { _usage = pViewUsageInfo->usage; }
-				next = (MVKVkAPIStructHeader*)next->pNext;
 				break;
 			}
+            /* case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR: {
+                const VkSamplerYcbcrConversionInfoKHR* sampConvInfo = (const VkSamplerYcbcrConversionInfoKHR*)next;
+                break;
+            } */
 			default:
-				next = (MVKVkAPIStructHeader*)next->pNext;
 				break;
 		}
 	}
 
-	validateImageViewConfig(pCreateInfo);
+    // Validate whether the image view configuration can be supported
+    if ( _image ) {
+        VkImageType imgType = _image->getImageType();
+        VkImageViewType viewType = pCreateInfo->viewType;
+
+        // VK_KHR_maintenance1 supports taking 2D image views of 3D slices. No dice in Metal.
+        if ((viewType == VK_IMAGE_VIEW_TYPE_2D || viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && (imgType == VK_IMAGE_TYPE_3D)) {
+            if (pCreateInfo->subresourceRange.layerCount != _image->_extent.depth) {
+                reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): Metal does not fully support views on a subset of a 3D texture.");
+            }
+            if ( !mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) ) {
+                setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments."));
+            } else if (mvkIsOnlyAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
+                reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments.");
+            }
+        }
+    }
 
 	// Remember the subresource range, and determine the actual number of mip levels and texture slices
     _subresourceRange = pCreateInfo->subresourceRange;
@@ -1140,50 +1395,40 @@
 		_subresourceRange.layerCount = _image->getLayerCount() - _subresourceRange.baseArrayLayer;
 	}
 
-	_mtlTexture = nil;
-	bool useSwizzle;
-	setConfigurationResult(validateSwizzledMTLPixelFormat(pCreateInfo, getPixelFormats(), this,
-														  _device->_pMetalFeatures->nativeTextureSwizzle,
-														  _device->_pMVKConfig->fullImageViewSwizzle,
-														  _mtlPixelFormat, useSwizzle));
-	_packedSwizzle = useSwizzle ? mvkPackSwizzle(pCreateInfo->components) : 0;
-	_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType,
-														   _image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT);
-	initMTLTextureViewSupport();
-}
-
-// Validate whether the image view configuration can be supported
-void MVKImageView::validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo) {
-
-	// No image if we are just validating view config
-	MVKImage* image = (MVKImage*)pCreateInfo->image;
-	if ( !image ) { return; }
-
-	VkImageType imgType = image->getImageType();
-	VkImageViewType viewType = pCreateInfo->viewType;
-
-	// VK_KHR_maintenance1 supports taking 2D image views of 3D slices. No dice in Metal.
-	if ((viewType == VK_IMAGE_VIEW_TYPE_2D || viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && (imgType == VK_IMAGE_TYPE_3D)) {
-		if (pCreateInfo->subresourceRange.layerCount != image->_extent.depth) {
-			reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): Metal does not fully support views on a subset of a 3D texture.");
-		}
-		if ( !mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) ) {
-			setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments."));
-		} else if (mvkIsOnlyAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
-			reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments.");
-		}
-	}
+    VkExtent2D blockTexelSizeOfPlane[3];
+    uint32_t bytesPerBlockOfPlane[3];
+    MTLPixelFormat mtlPixFmtOfPlane[3];
+    uint8_t subsamplingPlaneCount = getPixelFormats()->getChromaSubsamplingPlanes(pCreateInfo->format, blockTexelSizeOfPlane, bytesPerBlockOfPlane, mtlPixFmtOfPlane),
+            beginPlaneIndex = 0,
+            endPlaneIndex = subsamplingPlaneCount;
+    if (subsamplingPlaneCount == 0) {
+        endPlaneIndex = 1;
+        mtlPixFmtOfPlane[0] = getPixelFormats()->getMTLPixelFormat(pCreateInfo->format);
+    } else {
+        if (!mvkVkComponentMappingsMatch(pCreateInfo->components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A})) {
+            setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Image view swizzling for multi planar formats is not supported."));
+        }
+        if (_subresourceRange.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
+            beginPlaneIndex = endPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(_subresourceRange.aspectMask);
+        }
+    }
+    for (uint8_t planeIndex = beginPlaneIndex; planeIndex < endPlaneIndex; planeIndex++) {
+        _planes.push_back(std::unique_ptr<MVKImageViewPlane>(new MVKImageViewPlane(
+            this,
+            planeIndex,
+            mtlPixFmtOfPlane[planeIndex],
+            pCreateInfo
+        )));
+    }
 }
 
 VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
-													  MVKPixelFormats* mvkPixFmts,
 													  MVKVulkanAPIObject* apiObject,
 													  bool hasNativeSwizzleSupport,
 													  bool hasShaderSwizzleSupport,
 													  MTLPixelFormat& mtlPixFmt,
 													  bool& useSwizzle) {
 	useSwizzle = false;
-	mtlPixFmt = mvkPixFmts->getMTLPixelFormat(pCreateInfo->format);
 	VkComponentMapping components = pCreateInfo->components;
 
 	#define SWIZZLE_MATCHES(R, G, B, A)    mvkVkComponentMappingsMatch(components, {VK_COMPONENT_SWIZZLE_ ##R, VK_COMPONENT_SWIZZLE_ ##G, VK_COMPONENT_SWIZZLE_ ##B, VK_COMPONENT_SWIZZLE_ ##A} )
@@ -1191,6 +1436,16 @@
 
 	// If we have an identity swizzle, we're all good.
 	if (SWIZZLE_MATCHES(R, G, B, A)) {
+		// Change to stencil-only format if only stencil aspect is requested
+		if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+			if (mtlPixFmt == MTLPixelFormatDepth32Float_Stencil8)
+				mtlPixFmt = MTLPixelFormatX32_Stencil8;
+#if MVK_MACOS
+			else if (mtlPixFmt == MTLPixelFormatDepth24Unorm_Stencil8)
+				mtlPixFmt = MTLPixelFormatX24_Stencil8;
+#endif
+		}
+
 		return VK_SUCCESS;
 	}
 
@@ -1279,32 +1534,90 @@
 								  mvkVkComponentSwizzleName(components.b), mvkVkComponentSwizzleName(components.a));
 }
 
-// Determine whether this image view should use a Metal texture view,
-// and set the _useMTLTextureView variable appropriately.
-void MVKImageView::initMTLTextureViewSupport() {
 
-	// If no image we're just validating image iview config
-	if ( !_image ) {
-		_useMTLTextureView = false;
-		return;
-	}
+#pragma mark -
+#pragma mark MVKSamplerYcbcrConversion
 
-	_useMTLTextureView = _image->_canSupportMTLTextureView;
+void MVKSamplerYcbcrConversion::updateConstExprSampler(MSLConstexprSampler& constExprSampler) const {
+	constExprSampler.planes = _planes;
+	constExprSampler.resolution = _resolution;
+	constExprSampler.chroma_filter = _chroma_filter;
+	constExprSampler.x_chroma_offset = _x_chroma_offset;
+	constExprSampler.y_chroma_offset = _y_chroma_offset;
+    for (uint32_t i = 0; i < 4; ++i) {
+		constExprSampler.swizzle[i] = _swizzle[i];
+    }
+	constExprSampler.ycbcr_model = _ycbcr_model;
+	constExprSampler.ycbcr_range = _ycbcr_range;
+    constExprSampler.bpc = _bpc;
+	constExprSampler.ycbcr_conversion_enable = true;
+}
 
-	bool is3D = _image->_mtlTextureType == MTLTextureType3D;
-	// If the view is identical to underlying image, don't bother using a Metal view
-	if (_mtlPixelFormat == _image->_mtlPixelFormat &&
-		(_mtlTextureType == _image->_mtlTextureType ||
-		 ((_mtlTextureType == MTLTextureType2D || _mtlTextureType == MTLTextureType2DArray) && is3D)) &&
-		_subresourceRange.levelCount == _image->_mipLevels &&
-		(is3D || _subresourceRange.layerCount == _image->_arrayLayers) &&
-		(!_device->_pMetalFeatures->nativeTextureSwizzle || !_packedSwizzle)) {
-		_useMTLTextureView = false;
+static MSLSamplerFilter getSpvMinMagFilterFromVkFilter(VkFilter vkFilter) {
+    switch (vkFilter) {
+        case VK_FILTER_LINEAR:    return MSL_SAMPLER_FILTER_LINEAR;
+
+        case VK_FILTER_NEAREST:
+        default:
+            return MSL_SAMPLER_FILTER_NEAREST;
+    }
+}
+
+static MSLChromaLocation getSpvChromaLocationFromVkChromaLocation(VkChromaLocation vkChromaLocation) {
+	switch (vkChromaLocation) {
+		default:
+		case VK_CHROMA_LOCATION_COSITED_EVEN:   return MSL_CHROMA_LOCATION_COSITED_EVEN;
+		case VK_CHROMA_LOCATION_MIDPOINT:       return MSL_CHROMA_LOCATION_MIDPOINT;
 	}
 }
 
-MVKImageView::~MVKImageView() {
-	[_mtlTexture release];
+static MSLComponentSwizzle getSpvComponentSwizzleFromVkComponentMapping(VkComponentSwizzle vkComponentSwizzle) {
+	switch (vkComponentSwizzle) {
+		default:
+		case VK_COMPONENT_SWIZZLE_IDENTITY:     return MSL_COMPONENT_SWIZZLE_IDENTITY;
+		case VK_COMPONENT_SWIZZLE_ZERO:         return MSL_COMPONENT_SWIZZLE_ZERO;
+		case VK_COMPONENT_SWIZZLE_ONE:          return MSL_COMPONENT_SWIZZLE_ONE;
+		case VK_COMPONENT_SWIZZLE_R:            return MSL_COMPONENT_SWIZZLE_R;
+		case VK_COMPONENT_SWIZZLE_G:            return MSL_COMPONENT_SWIZZLE_G;
+		case VK_COMPONENT_SWIZZLE_B:            return MSL_COMPONENT_SWIZZLE_B;
+		case VK_COMPONENT_SWIZZLE_A:            return MSL_COMPONENT_SWIZZLE_A;
+	}
+}
+
+static MSLSamplerYCbCrModelConversion getSpvSamplerYCbCrModelConversionFromVkSamplerYcbcrModelConversion(VkSamplerYcbcrModelConversion vkSamplerYcbcrModelConversion) {
+	switch (vkSamplerYcbcrModelConversion) {
+		default:
+		case VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:   return MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
+		case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY: return MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY;
+		case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:      return MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709;
+		case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:      return MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601;
+		case VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:     return MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020;
+	}
+}
+
+static MSLSamplerYCbCrRange getSpvSamplerYcbcrRangeFromVkSamplerYcbcrRange(VkSamplerYcbcrRange vkSamplerYcbcrRange) {
+	switch (vkSamplerYcbcrRange) {
+		default:
+		case VK_SAMPLER_YCBCR_RANGE_ITU_FULL:   return MSL_SAMPLER_YCBCR_RANGE_ITU_FULL;
+		case VK_SAMPLER_YCBCR_RANGE_ITU_NARROW: return MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW;
+	}
+}
+
+MVKSamplerYcbcrConversion::MVKSamplerYcbcrConversion(MVKDevice* device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
+	MVKPixelFormats* pixFmts = getPixelFormats();
+	_planes = pixFmts->getChromaSubsamplingPlaneCount(pCreateInfo->format);
+	_bpc = pixFmts->getChromaSubsamplingComponentBits(pCreateInfo->format);
+	_resolution = pixFmts->getChromaSubsamplingResolution(pCreateInfo->format);
+	_chroma_filter = getSpvMinMagFilterFromVkFilter(pCreateInfo->chromaFilter);
+	_x_chroma_offset = getSpvChromaLocationFromVkChromaLocation(pCreateInfo->xChromaOffset);
+	_y_chroma_offset = getSpvChromaLocationFromVkChromaLocation(pCreateInfo->yChromaOffset);
+	_swizzle[0] = getSpvComponentSwizzleFromVkComponentMapping(pCreateInfo->components.r);
+	_swizzle[1] = getSpvComponentSwizzleFromVkComponentMapping(pCreateInfo->components.g);
+	_swizzle[2] = getSpvComponentSwizzleFromVkComponentMapping(pCreateInfo->components.b);
+	_swizzle[3] = getSpvComponentSwizzleFromVkComponentMapping(pCreateInfo->components.a);
+	_ycbcr_model = getSpvSamplerYCbCrModelConversionFromVkSamplerYcbcrModelConversion(pCreateInfo->ycbcrModel);
+	_ycbcr_range = getSpvSamplerYcbcrRangeFromVkSamplerYcbcrRange(pCreateInfo->ycbcrRange);
+	_forceExplicitReconstruction = pCreateInfo->forceExplicitReconstruction;
 }
 
 
@@ -1365,7 +1678,20 @@
 }
 
 MVKSampler::MVKSampler(MVKDevice* device, const VkSamplerCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
-	_requiresConstExprSampler = pCreateInfo->compareEnable && !_device->_pMetalFeatures->depthSampleCompare;
+    _ycbcrConversion = NULL;
+    for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+		switch (next->sType) {
+			case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR: {
+				const VkSamplerYcbcrConversionInfoKHR* sampConvInfo = (const VkSamplerYcbcrConversionInfoKHR*)next;
+				_ycbcrConversion = (MVKSamplerYcbcrConversion*)(sampConvInfo->conversion);
+				break;
+			}
+			default:
+				break;
+		}
+	}
+
+	_requiresConstExprSampler = (pCreateInfo->compareEnable && !_device->_pMetalFeatures->depthSampleCompare) || _ycbcrConversion;
 
 	MTLSamplerDescriptor* mtlSampDesc = newMTLSamplerDescriptor(pCreateInfo);	// temp retain
     _mtlSamplerState = [getMTLDevice() newSamplerStateWithDescriptor: mtlSampDesc];
@@ -1374,16 +1700,6 @@
 	initConstExprSampler(pCreateInfo);
 }
 
-static MSLSamplerFilter getSpvMinMagFilterFromVkFilter(VkFilter vkFilter) {
-	switch (vkFilter) {
-		case VK_FILTER_LINEAR:	return MSL_SAMPLER_FILTER_LINEAR;
-
-		case VK_FILTER_NEAREST:
-		default:
-			return MSL_SAMPLER_FILTER_NEAREST;
-	}
-}
-
 static MSLSamplerMipFilter getSpvMipFilterFromVkMipMode(VkSamplerMipmapMode vkMipMode) {
 	switch (vkMipMode) {
 		case VK_SAMPLER_MIPMAP_MODE_LINEAR:		return MSL_SAMPLER_MIP_FILTER_LINEAR;
@@ -1439,7 +1755,7 @@
 			return MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK;
 	}
 }
-\
+
 void MVKSampler::initConstExprSampler(const VkSamplerCreateInfo* pCreateInfo) {
 	if ( !_requiresConstExprSampler ) { return; }
 
@@ -1458,6 +1774,9 @@
 	_constExprSampler.compare_enable = pCreateInfo->compareEnable;
 	_constExprSampler.lod_clamp_enable = false;
 	_constExprSampler.anisotropy_enable = pCreateInfo->anisotropyEnable;
+    if (_ycbcrConversion) {
+        _ycbcrConversion->updateConstExprSampler(_constExprSampler);
+    }
 }
 
 MVKSampler::~MVKSampler() {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
index 3a3018d..6195691 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
@@ -19,15 +19,16 @@
 #pragma once
 
 #include "MVKEnvironment.h"
-#include "MVKDevice.h"
 #include "MVKLayers.h"
 #include "MVKVulkanAPIObject.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include "vk_mvk_moltenvk.h"
 #include <unordered_map>
 #include <string>
 #include <mutex>
 
+class MVKPhysicalDevice;
+class MVKDevice;
 class MVKSurface;
 class MVKDebugReportCallback;
 class MVKDebugUtilsMessenger;
@@ -177,7 +178,7 @@
 protected:
 	friend MVKDevice;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	void initProcAddrs();
 	void initDebugCallbacks(const VkInstanceCreateInfo* pCreateInfo);
 	VkDebugReportFlagsEXT getVkDebugReportFlagsFromASLLevel(int aslLvl);
@@ -189,9 +190,9 @@
 
 	MVKConfiguration _mvkConfig;
 	VkApplicationInfo _appInfo;
-	MVKVectorInline<MVKPhysicalDevice, 2> _physicalDevices;
-	MVKVectorDefault<MVKDebugReportCallback*> _debugReportCallbacks;
-	MVKVectorDefault<MVKDebugUtilsMessenger*> _debugUtilMessengers;
+	MVKSmallVector<MVKPhysicalDevice*, 2> _physicalDevices;
+	MVKSmallVector<MVKDebugReportCallback*> _debugReportCallbacks;
+	MVKSmallVector<MVKDebugUtilsMessenger*> _debugUtilMessengers;
 	std::unordered_map<std::string, MVKEntryPoint> _entryPoints;
 	std::mutex _dcbLock;
 	bool _hasDebugReportCallbacks;
@@ -233,7 +234,7 @@
 protected:
 	friend MVKInstance;
 	
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 	MVKInstance* _mvkInstance;
 	VkDebugReportCallbackCreateInfoEXT _info;
@@ -271,7 +272,7 @@
 protected:
 	friend MVKInstance;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 	MVKInstance* _mvkInstance;
 	VkDebugUtilsMessengerCreateInfoEXT _info;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index aa08efa..7e466d6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -18,6 +18,7 @@
 
 
 #include "MVKInstance.h"
+#include "MVKDevice.h"
 #include "MVKFoundation.h"
 #include "MVKSurface.h"
 #include "MVKOSExtensions.h"
@@ -62,7 +63,7 @@
 
 	// Now populate the devices
 	for (uint32_t pdIdx = 0; pdIdx < *pCount; pdIdx++) {
-		pPhysicalDevices[pdIdx] = _physicalDevices[pdIdx].getVkPhysicalDevice();
+		pPhysicalDevices[pdIdx] = _physicalDevices[pdIdx]->getVkPhysicalDevice();
 	}
 
 	return result;
@@ -89,7 +90,7 @@
 	// Now populate the device groups
 	for (uint32_t pdIdx = 0; pdIdx < *pCount; pdIdx++) {
 		pPhysicalDeviceGroupProps[pdIdx].physicalDeviceCount = 1;
-		pPhysicalDeviceGroupProps[pdIdx].physicalDevices[0] = _physicalDevices[pdIdx].getVkPhysicalDevice();
+		pPhysicalDeviceGroupProps[pdIdx].physicalDevices[0] = _physicalDevices[pdIdx]->getVkPhysicalDevice();
 		pPhysicalDeviceGroupProps[pdIdx].subsetAllocation = VK_FALSE;
 	}
 
@@ -108,7 +109,7 @@
 
 void MVKInstance::destroySurface(MVKSurface* mvkSrfc,
 								const VkAllocationCallbacks* pAllocator) {
-	mvkSrfc->destroy();
+	if (mvkSrfc) { mvkSrfc->destroy(); }
 }
 
 MVKDebugReportCallback* MVKInstance::createDebugReportCallback(const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
@@ -123,6 +124,8 @@
 
 void MVKInstance::destroyDebugReportCallback(MVKDebugReportCallback* mvkDRCB,
 								const VkAllocationCallbacks* pAllocator) {
+	if ( !mvkDRCB ) { return; }
+
 	lock_guard<mutex> lock(_dcbLock);
 
 	mvkRemoveAllOccurances(_debugReportCallbacks, mvkDRCB);
@@ -166,6 +169,8 @@
 
 void MVKInstance::destroyDebugUtilsMessenger(MVKDebugUtilsMessenger* mvkDUM,
 											 const VkAllocationCallbacks* pAllocator) {
+	if ( !mvkDUM ) { return; }
+
 	lock_guard<mutex> lock(_dcbLock);
 
 	mvkRemoveAllOccurances(_debugUtilMessengers, mvkDUM);
@@ -361,8 +366,9 @@
 	// and other Obj-C classes, so wrap it all in an autorelease pool.
 	@autoreleasepool {
 		NSArray<id<MTLDevice>>* mtlDevices = availableMTLDevicesArray();
+		_physicalDevices.reserve(mtlDevices.count);
 		for (id<MTLDevice> mtlDev in mtlDevices) {
-			_physicalDevices.emplace_back(this, mtlDev);
+			_physicalDevices.push_back(new MVKPhysicalDevice(this, mtlDev));
 		}
 	}
 
@@ -383,8 +389,7 @@
 	_hasDebugUtilsMessengers = false;
 	_debugReportCallbackLayerPrefix = getDriverLayer()->getName();
 
-	MVKVkAPIStructHeader* next = (MVKVkAPIStructHeader*)pCreateInfo->pNext;
-	while (next) {
+	for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
 		switch (next->sType) {
 			case VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT:
 				createDebugReportCallback((VkDebugReportCallbackCreateInfoEXT*)next, nullptr);
@@ -395,7 +400,6 @@
 			default:
 				break;
 		}
-		next = (MVKVkAPIStructHeader*)next->pNext;
 	}
 }
 
@@ -618,6 +622,8 @@
 	ADD_DVC_EXT_ENTRY_POINT(vkGetDescriptorSetLayoutSupportKHR, KHR_MAINTENANCE3);
 	ADD_DVC_EXT_ENTRY_POINT(vkCmdPushDescriptorSetKHR, KHR_PUSH_DESCRIPTOR);
 	ADD_DVC_EXT2_ENTRY_POINT(vkCmdPushDescriptorSetWithTemplateKHR, KHR_PUSH_DESCRIPTOR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
+	ADD_DVC_EXT_ENTRY_POINT(vkCreateSamplerYcbcrConversionKHR, KHR_SAMPLER_YCBCR_CONVERSION);
+	ADD_DVC_EXT_ENTRY_POINT(vkDestroySamplerYcbcrConversionKHR, KHR_SAMPLER_YCBCR_CONVERSION);
 	ADD_DVC_EXT_ENTRY_POINT(vkCreateSwapchainKHR, KHR_SWAPCHAIN);
 	ADD_DVC_EXT_ENTRY_POINT(vkDestroySwapchainKHR, KHR_SWAPCHAIN);
 	ADD_DVC_EXT_ENTRY_POINT(vkGetSwapchainImagesKHR, KHR_SWAPCHAIN);
@@ -634,7 +640,8 @@
 	ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerBeginEXT, EXT_DEBUG_MARKER);
 	ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerEndEXT, EXT_DEBUG_MARKER);
 	ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerInsertEXT, EXT_DEBUG_MARKER);
-
+	ADD_DVC_EXT_ENTRY_POINT(vkGetRefreshCycleDurationGOOGLE, GOOGLE_DISPLAY_TIMING);
+	ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING);
 }
 
 void MVKInstance::logVersions() {
@@ -680,8 +687,10 @@
 }
 
 MVKInstance::~MVKInstance() {
-	lock_guard<mutex> lock(_dcbLock);
 	_useCreationCallbacks = true;
+	mvkDestroyContainerContents(_physicalDevices);
+
+	lock_guard<mutex> lock(_dcbLock);
 	mvkDestroyContainerContents(_debugReportCallbacks);
 }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 431f02f..5f01d27 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -22,7 +22,7 @@
 #include "MVKDescriptorSet.h"
 #include "MVKShaderModule.h"
 #include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <MoltenVKSPIRVToMSLConverter/SPIRVReflection.h>
 #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
 #include <unordered_set>
@@ -54,13 +54,13 @@
 
 	/** Binds descriptor sets to a command encoder. */
     void bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
-                            MVKVector<MVKDescriptorSet*>& descriptorSets,
+                            MVKArrayRef<MVKDescriptorSet*> descriptorSets,
                             uint32_t firstSet,
-                            MVKVector<uint32_t>& dynamicOffsets);
+                            MVKArrayRef<uint32_t> dynamicOffsets);
 
 	/** Updates a descriptor set in a command encoder. */
 	void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
-						   MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+						   MVKArrayRef<VkWriteDescriptorSet> descriptorWrites,
 						   uint32_t set);
 
 	/** Updates a descriptor set from a template in a command encoder. */
@@ -105,11 +105,11 @@
 	~MVKPipelineLayout() override;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
-	MVKVectorInline<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
-	MVKVectorInline<MVKShaderResourceBinding, 1> _dslMTLResourceIndexOffsets;
-	MVKVectorDefault<VkPushConstantRange> _pushConstants;
+	MVKSmallVector<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
+	MVKSmallVector<MVKShaderResourceBinding, 1> _dslMTLResourceIndexOffsets;
+	MVKSmallVector<VkPushConstantRange> _pushConstants;
 	MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
 	MVKShaderImplicitRezBinding _swizzleBufferIndex;
 	MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
@@ -143,9 +143,6 @@
 	/** Returns the debug report object type of this object. */
 	VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT; }
 
-	/** Returns the order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
-	virtual void getStages(MVKVector<uint32_t>& stages) = 0;
-
 	/** Binds this pipeline to the specified command encoder. */
 	virtual void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) = 0;
 
@@ -171,7 +168,7 @@
 	MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipelineLayout* layout, MVKPipeline* parent);
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 	MVKPipelineCache* _pipelineCache;
 	MVKShaderImplicitRezBinding _swizzleBufferIndex;
@@ -187,6 +184,15 @@
 #pragma mark -
 #pragma mark MVKGraphicsPipeline
 
+/** Describes a buffer binding to accommodate vertex attributes with offsets greater than the stride. */
+struct MVKTranslatedVertexBinding {
+	uint16_t binding;
+	uint16_t translationBinding;
+	uint32_t translationOffset;
+};
+
+typedef MVKSmallVector<MVKGraphicsStage, 4> MVKPiplineStages;
+
 /** The number of dynamic states possible in Vulkan. */
 static const uint32_t kMVKVkDynamicStateCount = 32;
 
@@ -195,8 +201,8 @@
 
 public:
 
-	/** Returns the number and order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
-	void getStages(MVKVector<uint32_t>& stages) override;
+	/** Returns the number and order of stages in this pipeline. Draws commands must encode this pipeline once per stage. */
+	void getStages(MVKPiplineStages& stages);
 
 	/** Binds this pipeline to the specified command encoder. */
 	void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override;
@@ -231,6 +237,12 @@
 	/** Returns true if the tessellation control shader needs a buffer to store its per-patch output. */
 	bool needsTessCtlPatchOutputBuffer() { return _needsTessCtlPatchOutputBuffer; }
 
+	/** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number.  */
+	uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); }
+
+	/** Returns the collection of translated vertex bindings. */
+	MVKArrayRef<MVKTranslatedVertexBinding> getTranslatedVertexBindings() { return _translatedVertexBindings.contents(); }
+
 	/** Constructs an instance for the device and parent (which may be NULL). */
 	MVKGraphicsPipeline(MVKDevice* device,
 						MVKPipelineCache* pipelineCache,
@@ -240,25 +252,28 @@
 	~MVKGraphicsPipeline() override;
 
 protected:
+	typedef MVKSmallVector<SPIRVShaderOutput, 32> SPIRVShaderOutputs;
+
     id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState);
     id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType);
     void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
     void initMVKShaderConverterContext(SPIRVToMSLConversionConfiguration& _shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
     void addVertexInputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo);
-    void addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& outputs);
+    void addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& outputs);
     MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
     MTLRenderPipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
 	MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
 	MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
 	bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext);
-	bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
-	bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
+	bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
+	bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
     bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext);
 	bool addVertexInputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderContext);
     void addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS);
     void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkGraphicsPipelineCreateInfo* pCreateInfo, bool isTessellationVertexPipeline = false);
     bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
 	bool verifyImplicitBuffer(bool needsBuffer, MVKShaderImplicitRezBinding& index, MVKShaderStage stage, const char* name, uint32_t reservedBuffers);
+	uint32_t getTranslatedVertexBinding(uint32_t binding, uint32_t translationOffset, uint32_t maxBinding);
 
 	const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr;
 	const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr;
@@ -269,8 +284,9 @@
 	VkPipelineRasterizationStateCreateInfo _rasterInfo;
 	VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
 
-	MVKVectorInline<VkViewport, kMVKCachedViewportScissorCount> _viewports;
-	MVKVectorInline<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
+	MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
+	MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
+	MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
 
 	MTLComputePipelineDescriptor* _mtlTessControlStageDesc = nil;
 
@@ -316,9 +332,6 @@
 
 public:
 
-	/** Returns the number and order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
-	void getStages(MVKVector<uint32_t>& stages) override;
-
 	/** Binds this pipeline to the specified command encoder. */
 	void encode(MVKCommandEncoder* cmdEncoder, uint32_t = 0) override;
 
@@ -380,7 +393,7 @@
 	~MVKPipelineCache() override;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	MVKShaderLibraryCache* getShaderLibraryCache(MVKShaderModuleKey smKey);
 	void readData(const VkPipelineCacheCreateInfo* pCreateInfo);
 	void writeData(std::ostream& outstream, bool isCounting = false);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 727f02b..2afcc78 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -38,12 +38,12 @@
 
 // A null cmdEncoder can be passed to perform a validation pass
 void MVKPipelineLayout::bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
-                                           MVKVector<MVKDescriptorSet*>& descriptorSets,
+                                           MVKArrayRef<MVKDescriptorSet*> descriptorSets,
                                            uint32_t firstSet,
-                                           MVKVector<uint32_t>& dynamicOffsets) {
+                                           MVKArrayRef<uint32_t> dynamicOffsets) {
 	clearConfigurationResult();
 	uint32_t pDynamicOffsetIndex = 0;
-	uint32_t dsCnt = (uint32_t)descriptorSets.size();
+	size_t dsCnt = descriptorSets.size;
 	for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
 		MVKDescriptorSet* descSet = descriptorSets[dsIdx];
 		uint32_t dslIdx = firstSet + dsIdx;
@@ -57,7 +57,7 @@
 
 // A null cmdEncoder can be passed to perform a validation pass
 void MVKPipelineLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
-                                          MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+                                          MVKArrayRef<VkWriteDescriptorSet> descriptorWrites,
                                           uint32_t set) {
 	clearConfigurationResult();
 	MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[set];
@@ -176,7 +176,7 @@
 #pragma mark -
 #pragma mark MVKGraphicsPipeline
 
-void MVKGraphicsPipeline::getStages(MVKVector<uint32_t>& stages) {
+void MVKGraphicsPipeline::getStages(MVKPiplineStages& stages) {
     if (isTessellationPipeline()) {
         stages.push_back(kMVKGraphicsStageVertex);
         stages.push_back(kMVKGraphicsStageTessControl);
@@ -254,8 +254,8 @@
             cmdEncoder->_blendColorState.setBlendColor(_blendConstants[0], _blendConstants[1],
                                                        _blendConstants[2], _blendConstants[3], false);
             cmdEncoder->_depthBiasState.setDepthBias(_rasterInfo);
-            cmdEncoder->_viewportState.setViewports(_viewports, 0, false);
-            cmdEncoder->_scissorState.setScissors(_scissors, 0, false);
+            cmdEncoder->_viewportState.setViewports(_viewports.contents(), 0, false);
+            cmdEncoder->_scissorState.setScissors(_scissors.contents(), 0, false);
             cmdEncoder->_mtlPrimitiveType = _mtlPrimitiveType;
 
             [mtlCmdEnc setCullMode: _mtlCullMode];
@@ -606,9 +606,8 @@
 																					SPIRVToMSLConversionConfiguration& shaderContext) {
 	MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new];		// retained
 
-	std::vector<SPIRVShaderOutput> vtxOutputs;
+	SPIRVShaderOutputs vtxOutputs;
 	std::string errorLog;
-	// Unfortunately, MoltenVKShaderConverter doesn't know about MVKVector, so we can't use that here.
 	if (!getShaderOutputs(((MVKShaderModule*)_pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, _pVertexSS->pName, vtxOutputs, errorLog) ) {
 		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str()));
 		return nil;
@@ -654,7 +653,7 @@
 																				  SPIRVToMSLConversionConfiguration& shaderContext) {
 	MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new];	// retained
 
-	std::vector<SPIRVShaderOutput> tcOutputs;
+	SPIRVShaderOutputs tcOutputs;
 	std::string errorLog;
 	if (!getShaderOutputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcOutputs, errorLog) ) {
 		setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control outputs: %s", errorLog.c_str()));
@@ -823,7 +822,7 @@
 bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc,
 													 const VkGraphicsPipelineCreateInfo* pCreateInfo,
 													 SPIRVToMSLConversionConfiguration& shaderContext,
-													 std::vector<SPIRVShaderOutput>& vtxOutputs) {
+													 SPIRVShaderOutputs& vtxOutputs) {
 	shaderContext.options.entryPointStage = spv::ExecutionModelTessellationControl;
 	shaderContext.options.entryPointName = _pTessCtlSS->pName;
 	shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessCtl];
@@ -876,7 +875,7 @@
 bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc,
 													  const VkGraphicsPipelineCreateInfo* pCreateInfo,
 													  SPIRVToMSLConversionConfiguration& shaderContext,
-													  std::vector<SPIRVShaderOutput>& tcOutputs) {
+													  SPIRVShaderOutputs& tcOutputs) {
 	shaderContext.options.entryPointStage = spv::ExecutionModelTessellationEvaluation;
 	shaderContext.options.entryPointName = _pTessEvalSS->pName;
 	shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessEval];
@@ -944,53 +943,22 @@
 												   const SPIRVToMSLConversionConfiguration& shaderContext) {
     // Collect extension structures
     VkPipelineVertexInputDivisorStateCreateInfoEXT* pVertexInputDivisorState = nullptr;
-    auto* next = (MVKVkAPIStructHeader*)pVI->pNext;
-    while (next) {
+	for (const auto* next = (VkBaseInStructure*)pVI->pNext; next; next = next->pNext) {
         switch (next->sType) {
         case VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT:
             pVertexInputDivisorState = (VkPipelineVertexInputDivisorStateCreateInfoEXT*)next;
-            next = (MVKVkAPIStructHeader*)pVertexInputDivisorState->pNext;
             break;
         default:
-            next = (MVKVkAPIStructHeader*)next->pNext;
             break;
         }
     }
 
-    // Vertex attributes
-    uint32_t vaCnt = pVI->vertexAttributeDescriptionCount;
-	uint32_t vbCnt = pVI->vertexBindingDescriptionCount;
-    for (uint32_t i = 0; i < vaCnt; i++) {
-        const VkVertexInputAttributeDescription* pVKVA = &pVI->pVertexAttributeDescriptions[i];
-        if (shaderContext.isVertexAttributeLocationUsed(pVKVA->location)) {
-
-      // Vulkan allows offsets to exceed the buffer stride, but Metal doesn't.
-			// Only check non-zero offsets, as it's common for both to be zero when step rate is instance.
-			if (pVKVA->offset > 0) {
-				const VkVertexInputBindingDescription* pVKVB = pVI->pVertexBindingDescriptions;
-				for (uint32_t j = 0; j < vbCnt; j++, pVKVB++) {
-					if (pVKVB->binding == pVKVA->binding) {
-						if (pVKVA->offset >= pVKVB->stride) {
-							setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Under Metal, vertex attribute offsets must not exceed the vertex buffer stride."));
-							return false;
-						}
-						break;
-					}
-				}
-			}
-
-			MTLVertexAttributeDescriptor* vaDesc = plDesc.vertexDescriptor.attributes[pVKVA->location];
-            vaDesc.format = getPixelFormats()->getMTLVertexFormat(pVKVA->format);
-            vaDesc.bufferIndex = _device->getMetalBufferIndexForVertexAttributeBinding(pVKVA->binding);
-            vaDesc.offset = pVKVA->offset;
-        }
-    }
-
     // Vertex buffer bindings
+	uint32_t vbCnt = pVI->vertexBindingDescriptionCount;
+	uint32_t maxBinding = 0;
     for (uint32_t i = 0; i < vbCnt; i++) {
         const VkVertexInputBindingDescription* pVKVB = &pVI->pVertexBindingDescriptions[i];
-        uint32_t vbIdx = _device->getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
-        if (shaderContext.isVertexBufferUsed(vbIdx)) {
+        if (shaderContext.isVertexBufferUsed(pVKVB->binding)) {
 
 			// Vulkan allows any stride, but Metal only allows multiples of 4.
             // TODO: We should try to expand the buffer to the required alignment in that case.
@@ -999,10 +967,20 @@
                 return false;
             }
 
+			maxBinding = max(pVKVB->binding, maxBinding);
+			uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
 			MTLVertexBufferLayoutDescriptor* vbDesc = plDesc.vertexDescriptor.layouts[vbIdx];
-			vbDesc.stride = (pVKVB->stride == 0) ? sizeof(simd::float4) : pVKVB->stride;      // Vulkan allows zero stride but Metal doesn't. Default to float4
-            vbDesc.stepFunction = mvkMTLVertexStepFunctionFromVkVertexInputRate(pVKVB->inputRate);
-            vbDesc.stepRate = 1;
+			if (pVKVB->stride == 0) {
+				// Stride can't be 0, it will be set later to attributes' maximum offset + size
+				// to prevent it from being larger than the underlying buffer permits.
+				vbDesc.stride = 0;
+				vbDesc.stepFunction = MTLVertexStepFunctionConstant;
+				vbDesc.stepRate = 0;
+			} else {
+				vbDesc.stride = pVKVB->stride;
+				vbDesc.stepFunction = mvkMTLVertexStepFunctionFromVkVertexInputRate(pVKVB->inputRate);
+				vbDesc.stepRate = 1;
+			}
         }
     }
 
@@ -1011,7 +989,7 @@
         vbCnt = pVertexInputDivisorState->vertexBindingDivisorCount;
         for (uint32_t i = 0; i < vbCnt; i++) {
             const VkVertexInputBindingDivisorDescriptionEXT* pVKVB = &pVertexInputDivisorState->pVertexBindingDivisors[i];
-            uint32_t vbIdx = _device->getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
+            uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
             if (shaderContext.isVertexBufferUsed(vbIdx)) {
                 MTLVertexBufferLayoutDescriptor* vbDesc = plDesc.vertexDescriptor.layouts[vbIdx];
                 if (vbDesc.stepFunction == MTLVertexStepFunctionPerInstance) {
@@ -1023,24 +1001,110 @@
         }
     }
 
+	// Vertex attributes
+	uint32_t vaCnt = pVI->vertexAttributeDescriptionCount;
+	for (uint32_t i = 0; i < vaCnt; i++) {
+		const VkVertexInputAttributeDescription* pVKVA = &pVI->pVertexAttributeDescriptions[i];
+		if (shaderContext.isVertexAttributeLocationUsed(pVKVA->location)) {
+			uint32_t vaBinding = pVKVA->binding;
+			uint32_t vaOffset = pVKVA->offset;
+
+			// Vulkan allows offsets to exceed the buffer stride, but Metal doesn't.
+			// If this is the case, fetch an a translated artificial buffer binding, using the same MTLBuffer,
+			// but that is translated so that the reduced VA offset fits into the binding stride.
+			const VkVertexInputBindingDescription* pVKVB = pVI->pVertexBindingDescriptions;
+			for (uint32_t j = 0; j < vbCnt; j++, pVKVB++) {
+				if (pVKVB->binding == pVKVA->binding) {
+					uint32_t attrSize = getPixelFormats()->getBytesPerBlock(pVKVA->format);
+					if (pVKVB->stride == 0) {
+						// The step is set to constant, but we need to change stride to be non-zero for metal.
+						// Look for the maximum offset + size to set as the stride.
+						uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
+						MTLVertexBufferLayoutDescriptor* vbDesc = plDesc.vertexDescriptor.layouts[vbIdx];
+						uint32_t strideLowBound = vaOffset + attrSize;
+						if (vbDesc.stride < strideLowBound) vbDesc.stride = strideLowBound;
+					} else if (vaOffset >= pVKVB->stride) {
+						// Move vertex attribute offset into the stride. This vertex attribute may be
+						// combined with other vertex attributes into the same translated buffer binding.
+						// But if the reduced offset combined with the vertex attribute size still won't
+						// fit into the buffer binding stride, force the vertex attribute offset to zero,
+						// effectively dedicating this vertex attribute to its own buffer binding.
+						uint32_t origOffset = vaOffset;
+						vaOffset %= pVKVB->stride;
+						if (vaOffset + attrSize > pVKVB->stride) {
+							vaOffset = 0;
+						}
+						vaBinding = getTranslatedVertexBinding(vaBinding, origOffset - vaOffset, maxBinding);
+					}
+					break;
+				}
+			}
+
+			MTLVertexAttributeDescriptor* vaDesc = plDesc.vertexDescriptor.attributes[pVKVA->location];
+			vaDesc.format = getPixelFormats()->getMTLVertexFormat(pVKVA->format);
+			vaDesc.bufferIndex = getMetalBufferIndexForVertexAttributeBinding(vaBinding);
+			vaDesc.offset = vaOffset;
+		}
+	}
+
+	// Run through the vertex bindings. Add a new Metal vertex layout for each translated binding,
+	// identical to the original layout. The translated binding will index into the same MTLBuffer,
+	// but at an offset that is one or more strides away from the original.
+	for (uint32_t i = 0; i < vbCnt; i++) {
+		const VkVertexInputBindingDescription* pVKVB = &pVI->pVertexBindingDescriptions[i];
+		uint32_t vbVACnt = shaderContext.countVertexAttributesAt(pVKVB->binding);
+		if (vbVACnt > 0) {
+			uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
+			MTLVertexBufferLayoutDescriptor* vbDesc = plDesc.vertexDescriptor.layouts[vbIdx];
+
+			uint32_t xldtVACnt = 0;
+			for (auto& xltdBind : _translatedVertexBindings) {
+				if (xltdBind.binding == pVKVB->binding) {
+					uint32_t vbXltdIdx = getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding);
+					MTLVertexBufferLayoutDescriptor* vbXltdDesc = plDesc.vertexDescriptor.layouts[vbXltdIdx];
+					vbXltdDesc.stride = vbDesc.stride;
+					vbXltdDesc.stepFunction = vbDesc.stepFunction;
+					vbXltdDesc.stepRate = vbDesc.stepRate;
+					xldtVACnt++;
+				}
+			}
+
+			// If all of the vertex attributes at this vertex buffer binding have been translated, remove it.
+			if (xldtVACnt == vbVACnt) { vbDesc.stride = 0; }
+		}
+	}
+
 	return true;
 }
 
+// Returns a translated binding for the existing binding and translation offset, creating it if needed.
+uint32_t MVKGraphicsPipeline::getTranslatedVertexBinding(uint32_t binding, uint32_t translationOffset, uint32_t maxBinding) {
+	// See if a translated binding already exists (for example if more than one VA needs the same translation).
+	for (auto& xltdBind : _translatedVertexBindings) {
+		if (xltdBind.binding == binding && xltdBind.translationOffset == translationOffset) {
+			return xltdBind.translationBinding;
+		}
+	}
+
+	// Get next available binding point and add a translation binding description for it
+	uint16_t xltdBindPt = (uint16_t)(maxBinding + _translatedVertexBindings.size() + 1);
+	_translatedVertexBindings.push_back( {.binding = (uint16_t)binding, .translationBinding = xltdBindPt, .translationOffset = translationOffset} );
+
+	return xltdBindPt;
+}
+
 void MVKGraphicsPipeline::addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc,
 													const SPIRVTessReflectionData& reflectData,
 													const VkPipelineTessellationStateCreateInfo* pTS) {
 
 	VkPipelineTessellationDomainOriginStateCreateInfo* pTessDomainOriginState = nullptr;
 	if (reflectData.patchKind == spv::ExecutionModeTriangles) {
-		auto* next = (MVKVkAPIStructHeader*)pTS->pNext;
-		while (next) {
+		for (const auto* next = (VkBaseInStructure*)pTS->pNext; next; next = next->pNext) {
 			switch (next->sType) {
 			case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO:
 				pTessDomainOriginState = (VkPipelineTessellationDomainOriginStateCreateInfo*)next;
-				next = (MVKVkAPIStructHeader*)pTessDomainOriginState->pNext;
 				break;
 			default:
-				next = (MVKVkAPIStructHeader*)next->pNext;
 				break;
 			}
 		}
@@ -1131,15 +1195,12 @@
 
     VkPipelineTessellationDomainOriginStateCreateInfo* pTessDomainOriginState = nullptr;
     if (pCreateInfo->pTessellationState) {
-        auto* next = (MVKVkAPIStructHeader*)pCreateInfo->pTessellationState->pNext;
-        while (next) {
+		for (const auto* next = (VkBaseInStructure*)pCreateInfo->pTessellationState->pNext; next; next = next->pNext) {
             switch (next->sType) {
             case VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO:
                 pTessDomainOriginState = (VkPipelineTessellationDomainOriginStateCreateInfo*)next;
-                next = (MVKVkAPIStructHeader*)pTessDomainOriginState->pNext;
                 break;
             default:
-                next = (MVKVkAPIStructHeader*)next->pNext;
                 break;
             }
         }
@@ -1196,8 +1257,7 @@
         // Set binding and offset from Vulkan vertex attribute
         MSLVertexAttribute va;
         va.vertexAttribute.location = pVKVA->location;
-        va.vertexAttribute.msl_buffer = _device->getMetalBufferIndexForVertexAttributeBinding(pVKVA->binding);
-        va.vertexAttribute.msl_offset = pVKVA->offset;
+        va.binding = pVKVA->binding;
 
         // Metal can't do signedness conversions on vertex buffers (rdar://45922847). If the shader
         // and the vertex attribute have mismatched signedness, we have to fix the shader
@@ -1233,24 +1293,13 @@
 
         }
 
-        // Set stride and input rate of vertex attribute from corresponding Vulkan vertex bindings
-        uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount;
-        for (uint32_t vbIdx = 0; vbIdx < vbCnt; vbIdx++) {
-            const VkVertexInputBindingDescription* pVKVB = &pCreateInfo->pVertexInputState->pVertexBindingDescriptions[vbIdx];
-            if (pVKVB->binding == pVKVA->binding) {
-                va.vertexAttribute.msl_stride = pVKVB->stride;
-                va.vertexAttribute.per_instance = (pVKVB->inputRate == VK_VERTEX_INPUT_RATE_INSTANCE);
-                break;
-            }
-        }
-
         shaderContext.vertexAttributes.push_back(va);
     }
 }
 
 // Initializes the vertex attributes in a shader converter context from the previous stage output.
 void MVKGraphicsPipeline::addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext,
-                                                                     std::vector<SPIRVShaderOutput>& shaderOutputs) {
+                                                                     SPIRVShaderOutputs& shaderOutputs) {
     // Set the shader context vertex attribute information
     shaderContext.vertexAttributes.clear();
     uint32_t vaCnt = (uint32_t)shaderOutputs.size();
@@ -1297,10 +1346,6 @@
 #pragma mark -
 #pragma mark MVKComputePipeline
 
-void MVKComputePipeline::getStages(MVKVector<uint32_t>& stages) {
-    stages.push_back(0);
-}
-
 void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t) {
 	if ( !_hasValidMTLPipelineStates ) { return; }
 
@@ -1666,10 +1711,6 @@
 	template<class Archive>
 	void serialize(Archive & archive, MSLVertexAttr& va) {
 		archive(va.location,
-				va.msl_buffer,
-				va.msl_offset,
-				va.msl_stride,
-				va.per_instance,
 				va.format,
 				va.builtin);
 	}
@@ -1745,6 +1786,7 @@
 	template<class Archive>
 	void serialize(Archive & archive, MSLVertexAttribute& va) {
 		archive(va.vertexAttribute,
+				va.binding,
 				va.isUsedByShader);
 	}
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
index 9e2c4a1..e7b657d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
@@ -21,6 +21,7 @@
 #include "mvk_datatypes.h"
 #include "MVKEnvironment.h"
 #include "MVKBaseObject.h"
+#include <SPIRV-Cross/spirv_msl.hpp>
 #include <unordered_map>
 
 #import <Metal/Metal.h>
@@ -31,7 +32,8 @@
 // Validate these values periodically as new formats are added over time.
 static const uint32_t _vkFormatCount = 256;
 static const uint32_t _vkFormatCoreCount = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1;
-static const uint32_t _mtlPixelFormatCount = MTLPixelFormatX32_Stencil8 + 2;     // The actual last enum value is not available on iOS
+static const uint32_t _mtlPixelFormatCount = 128;
+static const uint32_t _mtlPixelFormatCoreCount = MTLPixelFormatX32_Stencil8 + 2;     // The actual last enum value is not available on iOS
 static const uint32_t _mtlVertexFormatCount = MTLVertexFormatHalf + 1;
 
 
@@ -69,6 +71,8 @@
 	kMVKMTLFmtCapsDRMR     = (kMVKMTLFmtCapsDRM | kMVKMTLFmtCapsResolve),
 	kMVKMTLFmtCapsDRFMR    = (kMVKMTLFmtCapsDRMR | kMVKMTLFmtCapsFilter),
 
+	kMVKMTLFmtCapsChromaSubsampling = kMVKMTLFmtCapsRF,
+	kMVKMTLFmtCapsMultiPlanar = kMVKMTLFmtCapsChromaSubsampling,
 } MVKMTLFmtCaps;
 
 
@@ -82,22 +86,22 @@
 	MTLPixelFormat mtlPixelFormatSubstitute;
 	MTLVertexFormat mtlVertexFormat;
 	MTLVertexFormat mtlVertexFormatSubstitute;
+    uint8_t chromaSubsamplingPlaneCount;
+    uint8_t chromaSubsamplingComponentBits;
 	VkExtent2D blockTexelSize;
 	uint32_t bytesPerBlock;
 	MVKFormatType formatType;
 	VkFormatProperties properties;
 	const char* name;
 	bool hasReportedSubstitution;
+    
+    inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); };
 
-	inline double bytesPerTexel() const { return (double)bytesPerBlock / (double)(blockTexelSize.width * blockTexelSize.height); };
-
-	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid); };
+	inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid || chromaSubsamplingPlaneCount > 0); };
 	inline bool isSupportedOrSubstitutable() const { return isSupported() || (mtlPixelFormatSubstitute != MTLPixelFormatInvalid); };
-	inline MTLPixelFormat getMTLPixelFormatOrSubstitute() const { return mtlPixelFormat ? mtlPixelFormat : mtlPixelFormatSubstitute; }
 
 	inline bool vertexIsSupported() const { return (mtlVertexFormat != MTLVertexFormatInvalid); };
 	inline bool vertexIsSupportedOrSubstitutable() const { return vertexIsSupported() || (mtlVertexFormatSubstitute != MTLVertexFormatInvalid); };
-	inline MTLVertexFormat getMTLVertexFormatOrSubstitute() const { return mtlVertexFormat ? mtlVertexFormat : mtlVertexFormatSubstitute; }
 } MVKVkFormatDesc;
 
 /** Describes the properties of a MTLPixelFormat or MTLVertexFormat. */
@@ -175,16 +179,28 @@
 
 	/**
 	 * Returns the size of the compression block, measured in texels for a Vulkan format.
-	 * The returned value will be {1, 1} for non-compressed formats.
+	 * The returned value will be {1, 1} for non-compressed formats without chroma-subsampling.
 	 */
 	VkExtent2D getBlockTexelSize(VkFormat vkFormat);
 
 	/**
 	 * Returns the size of the compression block, measured in texels for a Metal format.
-	 * The returned value will be {1, 1} for non-compressed formats.
+	 * The returned value will be {1, 1} for non-compressed formats without chroma-subsampling.
 	 */
 	VkExtent2D getBlockTexelSize(MTLPixelFormat mtlFormat);
 
+	/** Returns the number of planes of the specified chroma-subsampling (YCbCr) VkFormat */
+	uint8_t getChromaSubsamplingPlaneCount(VkFormat vkFormat);
+
+	/** Returns the number of bits per channel of the specified chroma-subsampling (YCbCr) VkFormat */
+	uint8_t getChromaSubsamplingComponentBits(VkFormat vkFormat);
+
+	/** Returns the MSLFormatResolution of the specified chroma-subsampling (YCbCr) VkFormat */
+	SPIRV_CROSS_NAMESPACE::MSLFormatResolution getChromaSubsamplingResolution(VkFormat vkFormat);
+
+    /** Returns the number of planes, blockTexelSize,  bytesPerBlock and mtlPixFmt of each plane of the specified chroma-subsampling (YCbCr) VkFormat into the given arrays */
+    uint8_t getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]);
+
 	/**
 	 * Returns the size, in bytes, of a texel of the specified Vulkan format.
 	 * The returned value may be fractional for certain compressed formats.
@@ -233,9 +249,9 @@
 	size_t getBytesPerLayer(MTLPixelFormat mtlFormat, size_t bytesPerRow, uint32_t texelRowsPerLayer);
 
 	/** Returns the default properties for the specified Vulkan format. */
-	VkFormatProperties getVkFormatProperties(VkFormat vkFormat);
+	VkFormatProperties& getVkFormatProperties(VkFormat vkFormat);
 
-	/** Returns the Metal format capabilities supported by the specified Vulkan format. */
+	/** Returns the Metal format capabilities supported by the specified Vulkan format, without substitution. */
 	MVKMTLFmtCaps getCapabilities(VkFormat vkFormat);
 
 	/** Returns the Metal format capabilities supported by the specified Metal format. */
@@ -287,9 +303,7 @@
 protected:
 	MVKVkFormatDesc& getVkFormatDesc(VkFormat vkFormat);
 	MVKVkFormatDesc& getVkFormatDesc(MTLPixelFormat mtlFormat);
-	MVKMTLFormatDesc& getMTLPixelFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLPixelFormatDesc(MTLPixelFormat mtlFormat);
-	MVKMTLFormatDesc& getMTLVertexFormatDesc(VkFormat vkFormat);
 	MVKMTLFormatDesc& getMTLVertexFormatDesc(MTLVertexFormat mtlFormat);
 	void initVkFormatCapabilities();
 	void initMTLPixelFormatCapabilities();
@@ -323,7 +337,10 @@
 	uint16_t _vkFormatDescIndicesByVkFormatsCore[_vkFormatCoreCount];
 	std::unordered_map<uint32_t, uint32_t> _vkFormatDescIndicesByVkFormatsExt;
 
-	// Metal formats have small values and are mapped by simple lookup array.
-	uint16_t _mtlFormatDescIndicesByMTLPixelFormats[_mtlPixelFormatCount];
+	// Most Metal formats have small values and are mapped by simple lookup array.
+	// Outliers are mapped by a map.
+	uint16_t _mtlFormatDescIndicesByMTLPixelFormatsCore[_mtlPixelFormatCoreCount];
+	std::unordered_map<NSUInteger, uint32_t> _mtlFormatDescIndicesByMTLPixelFormatsExt;
+
 	uint16_t _mtlFormatDescIndicesByMTLVertexFormats[_mtlVertexFormatCount];
 };
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
index c307579..912a873 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -198,7 +198,7 @@
 		if ( !mtlPixFmt || !vkDesc.hasReportedSubstitution ) {
 			string errMsg;
 			errMsg += "VkFormat ";
-			errMsg += (vkDesc.name) ? vkDesc.name : to_string(vkDesc.vkFormat);
+			errMsg += vkDesc.name;
 			errMsg += " is not supported on this device.";
 
 			if (mtlPixFmt) {
@@ -206,7 +206,7 @@
 
 				auto& vkDescSubs = getVkFormatDesc(mtlPixFmt);
 				errMsg += " Using VkFormat ";
-				errMsg += (vkDescSubs.name) ? vkDescSubs.name : to_string(vkDescSubs.vkFormat);
+				errMsg += vkDescSubs.name;
 				errMsg += " instead.";
 			}
 			MVKBaseObject::reportError(_physicalDevice, VK_ERROR_FORMAT_NOT_SUPPORTED, "%s", errMsg.c_str());
@@ -236,6 +236,61 @@
     return getVkFormatDesc(mtlFormat).blockTexelSize;
 }
 
+uint8_t MVKPixelFormats::getChromaSubsamplingPlaneCount(VkFormat vkFormat) {
+    return getVkFormatDesc(vkFormat).chromaSubsamplingPlaneCount;
+}
+
+uint8_t MVKPixelFormats::getChromaSubsamplingComponentBits(VkFormat vkFormat) {
+    return getVkFormatDesc(vkFormat).chromaSubsamplingComponentBits;
+}
+
+SPIRV_CROSS_NAMESPACE::MSLFormatResolution MVKPixelFormats::getChromaSubsamplingResolution(VkFormat vkFormat) {
+    VkExtent2D blockTexelSize = getVkFormatDesc(vkFormat).blockTexelSize;
+    return (blockTexelSize.width != 2) ? SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_444
+        : (blockTexelSize.height != 2) ? SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_422
+                                       : SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_420;
+}
+
+uint8_t MVKPixelFormats::getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]) {
+    uint8_t planes = getChromaSubsamplingPlaneCount(vkFormat);
+    uint8_t bits = getChromaSubsamplingComponentBits(vkFormat);
+    SPIRV_CROSS_NAMESPACE::MSLFormatResolution resolution = getChromaSubsamplingResolution(vkFormat);
+    bytesPerBlock[0] = mvkCeilingDivide((uint32_t)bits/8U, 1U);
+    switch(resolution) {
+        default:
+            return 0;
+        case SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_444:
+            blockTexelSize[0] = blockTexelSize[1] = blockTexelSize[2] = VkExtent2D{1, 1};
+            break;
+        case SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_422:
+            blockTexelSize[0] = blockTexelSize[1] = blockTexelSize[2] = VkExtent2D{2, 1};
+            break;
+        case SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_420:
+            blockTexelSize[0] = blockTexelSize[1] = blockTexelSize[2] = VkExtent2D{2, 2};
+            break;
+    }
+    switch(planes) {
+        default:
+            return 0;
+        case 1:
+            bytesPerBlock[0] *= 4;
+            mtlPixFmt[0] = (bits == 8) ? MTLPixelFormatRGBA8Unorm : MTLPixelFormatRGBA16Unorm;
+            break;
+        case 2:
+            blockTexelSize[0] = VkExtent2D{1, 1};
+            bytesPerBlock[1] = bytesPerBlock[0]*2;
+            mtlPixFmt[0] = (bits == 8) ? MTLPixelFormatR8Unorm : MTLPixelFormatR16Unorm;
+            mtlPixFmt[1] = (bits == 8) ? MTLPixelFormatRG8Unorm : MTLPixelFormatRG16Unorm;
+            break;
+        case 3:
+            blockTexelSize[0] = VkExtent2D{1, 1};
+            bytesPerBlock[1] = bytesPerBlock[2] = bytesPerBlock[0];
+            mtlPixFmt[0] = mtlPixFmt[1] = mtlPixFmt[2] = (bits == 8) ? MTLPixelFormatR8Unorm : MTLPixelFormatR16Unorm;
+            break;
+    }
+    return planes;
+}
+
 float MVKPixelFormats::getBytesPerTexel(VkFormat vkFormat) {
     return getVkFormatDesc(vkFormat).bytesPerTexel();
 }
@@ -262,12 +317,12 @@
     return mvkCeilingDivide(texelRowsPerLayer, getVkFormatDesc(mtlFormat).blockTexelSize.height) * bytesPerRow;
 }
 
-VkFormatProperties MVKPixelFormats::getVkFormatProperties(VkFormat vkFormat) {
-	return	getVkFormatDesc(vkFormat).properties;
+VkFormatProperties& MVKPixelFormats::getVkFormatProperties(VkFormat vkFormat) {
+	return getVkFormatDesc(vkFormat).properties;
 }
 
 MVKMTLFmtCaps MVKPixelFormats::getCapabilities(VkFormat vkFormat) {
-	return getMTLPixelFormatDesc(vkFormat).mtlFmtCaps;
+	return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).mtlPixelFormat).mtlFmtCaps;
 }
 
 MVKMTLFmtCaps MVKPixelFormats::getCapabilities(MTLPixelFormat mtlFormat) {
@@ -311,7 +366,7 @@
 	if ( !mtlVtxFmt && vkFormat ) {
 		string errMsg;
 		errMsg += "VkFormat ";
-		errMsg += (vkDesc.name) ? vkDesc.name : to_string(vkDesc.vkFormat);
+		errMsg += vkDesc.name;
 		errMsg += " is not supported for vertex buffers on this device.";
 
 		if (vkDesc.vertexIsSupportedOrSubstitutable()) {
@@ -319,7 +374,7 @@
 
 			auto& vkDescSubs = getVkFormatDesc(getMTLVertexFormatDesc(mtlVtxFmt).vkFormat);
 			errMsg += " Using VkFormat ";
-			errMsg += (vkDescSubs.name) ? vkDescSubs.name : to_string(vkDescSubs.vkFormat);
+			errMsg += vkDescSubs.name;
 			errMsg += " instead.";
 		}
 		MVKBaseObject::reportError(_physicalDevice, VK_ERROR_FORMAT_NOT_SUPPORTED, "%s", errMsg.c_str());
@@ -449,7 +504,9 @@
 
 // Return a reference to the Vulkan format descriptor corresponding to the VkFormat.
 MVKVkFormatDesc& MVKPixelFormats::getVkFormatDesc(VkFormat vkFormat) {
-	uint16_t fmtIdx = (vkFormat < _vkFormatCoreCount) ? _vkFormatDescIndicesByVkFormatsCore[vkFormat] : _vkFormatDescIndicesByVkFormatsExt[vkFormat];
+	uint16_t fmtIdx = ((vkFormat < _vkFormatCoreCount)
+					   ? _vkFormatDescIndicesByVkFormatsCore[vkFormat]
+					   : _vkFormatDescIndicesByVkFormatsExt[vkFormat]);
 	return _vkFormatDescriptions[fmtIdx];
 }
 
@@ -458,22 +515,14 @@
 	return getVkFormatDesc(getMTLPixelFormatDesc(mtlFormat).vkFormat);
 }
 
-// Return a reference to the Metal format descriptor corresponding to the VkFormat.
-MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(VkFormat vkFormat) {
-	return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).getMTLPixelFormatOrSubstitute());
-}
-
 // Return a reference to the Metal format descriptor corresponding to the MTLPixelFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLPixelFormatDesc(MTLPixelFormat mtlFormat) {
-	uint16_t fmtIdx = (mtlFormat < _mtlPixelFormatCount) ? _mtlFormatDescIndicesByMTLPixelFormats[mtlFormat] : 0;
+	uint16_t fmtIdx = ((mtlFormat < _mtlPixelFormatCoreCount)
+					   ? _mtlFormatDescIndicesByMTLPixelFormatsCore[mtlFormat]
+					   : _mtlFormatDescIndicesByMTLPixelFormatsExt[mtlFormat]);
 	return _mtlPixelFormatDescriptions[fmtIdx];
 }
 
-// Return a reference to the Metal format descriptor corresponding to the VkFormat.
-MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(VkFormat vkFormat) {
-	return getMTLVertexFormatDesc(getVkFormatDesc(vkFormat).getMTLVertexFormatOrSubstitute());
-}
-
 // Return a reference to the Metal format descriptor corresponding to the MTLVertexFormat.
 MVKMTLFormatDesc& MVKPixelFormats::getMTLVertexFormatDesc(MTLVertexFormat mtlFormat) {
 	uint16_t fmtIdx = (mtlFormat < _mtlVertexFormatCount) ? _mtlFormatDescIndicesByMTLVertexFormats[mtlFormat] : 0;
@@ -498,10 +547,16 @@
 //	test();
 }
 
-#define addVkFormatDesc(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE)  \
+#define addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE)  \
 	MVKAssert(fmtIdx < _vkFormatCount, "Attempting to describe %d VkFormats, but only have space for %d. Increase the value of _vkFormatCount", fmtIdx + 1, _vkFormatCount);  \
 	_vkFormatDescriptions[fmtIdx++] = { VK_FORMAT_ ##VK_FMT, MTLPixelFormat ##MTL_FMT, MTLPixelFormat ##MTL_FMT_ALT, MTLVertexFormat ##MTL_VTX_FMT, MTLVertexFormat ##MTL_VTX_FMT_ALT,  \
-										{ BLK_W, BLK_H }, BLK_BYTE_CNT, kMVKFormat ##MVK_FMT_TYPE, { 0, 0, 0 }, "VK_FORMAT_" #VK_FMT, false }
+										CSPC, CSCB, { BLK_W, BLK_H }, BLK_BYTE_CNT, kMVKFormat ##MVK_FMT_TYPE, { 0, 0, 0 }, "VK_FORMAT_" #VK_FMT, false }
+
+#define addVkFormatDesc(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE)  \
+    addVkFormatDescFull(VK_FMT, MTL_FMT, MTL_FMT_ALT, MTL_VTX_FMT, MTL_VTX_FMT_ALT, 0, 0, BLK_W, BLK_H, BLK_BYTE_CNT, MVK_FMT_TYPE)
+
+#define addVkFormatDescChromaSubsampling(VK_FMT, MTL_FMT, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT)  \
+addVkFormatDescFull(VK_FMT, MTL_FMT, Invalid, Invalid, Invalid, CSPC, CSCB, BLK_W, BLK_H, BLK_BYTE_CNT, ColorFloat)
 
 void MVKPixelFormats::initVkFormatCapabilities() {
 
@@ -510,6 +565,7 @@
 	uint32_t fmtIdx = 0;
 
 	// When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count
+
 	// UNDEFINED must come first.
 	addVkFormatDesc( UNDEFINED, Invalid, Invalid, Invalid, Invalid, 1, 1, 0, None );
 
@@ -747,9 +803,41 @@
 	addVkFormatDesc( PVRTC2_2BPP_SRGB_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 8, 4, 8, Compressed );
 	addVkFormatDesc( PVRTC2_4BPP_SRGB_BLOCK_IMG, Invalid, Invalid, Invalid, Invalid, 4, 4, 8, Compressed );
 
-	// Future extension VK_KHX_color_conversion and Vulkan 1.1.
-	addVkFormatDesc( UNDEFINED, GBGR422, Invalid, Invalid, Invalid, 2, 1, 4, ColorFloat );
-	addVkFormatDesc( UNDEFINED, BGRG422, Invalid, Invalid, Invalid, 2, 1, 4, ColorFloat );
+	// Extension VK_KHR_sampler_ycbcr_conversion
+    addVkFormatDescChromaSubsampling( G8B8G8R8_422_UNORM, GBGR422, 1, 8, 2, 1, 4 );
+    addVkFormatDescChromaSubsampling( B8G8R8G8_422_UNORM, BGRG422, 1, 8, 2, 1, 4 );
+    addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_420_UNORM, Invalid, 3, 8, 2, 2, 6 );
+    addVkFormatDescChromaSubsampling( G8_B8R8_2PLANE_420_UNORM, Invalid, 2, 8, 2, 2, 6 );
+    addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_422_UNORM, Invalid, 3, 8, 2, 1, 4 );
+    addVkFormatDescChromaSubsampling( G8_B8R8_2PLANE_422_UNORM, Invalid, 2, 8, 2, 1, 4 );
+    addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_444_UNORM, Invalid, 3, 8, 1, 1, 3 );
+    addVkFormatDescChromaSubsampling( R10X6_UNORM_PACK16, Invalid, 0, 10, 1, 1, 2 );
+    addVkFormatDescChromaSubsampling( R10X6G10X6_UNORM_2PACK16, Invalid, 0, 10, 1, 1, 4 );
+    addVkFormatDescChromaSubsampling( R10X6G10X6B10X6A10X6_UNORM_4PACK16, Invalid, 0, 10, 1, 1, 8 );
+    addVkFormatDescChromaSubsampling( G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, Invalid, 3, 10, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16, Invalid, 2, 10, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, Invalid, 3, 10, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, Invalid, 2, 10, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, Invalid, 3, 10, 1, 1, 6 );
+    addVkFormatDescChromaSubsampling( R12X4_UNORM_PACK16, Invalid, 0, 12, 1, 1, 2 );
+    addVkFormatDescChromaSubsampling( R12X4G12X4_UNORM_2PACK16, Invalid, 0, 12, 1, 1, 4 );
+    addVkFormatDescChromaSubsampling( R12X4G12X4B12X4A12X4_UNORM_4PACK16, Invalid, 0, 12, 1, 1, 8 );
+    addVkFormatDescChromaSubsampling( G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, Invalid, 3, 12, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16, Invalid, 2, 12, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16, Invalid, 3, 12, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16, Invalid, 2, 12, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16, Invalid, 3, 12, 1, 1, 6 );
+    addVkFormatDescChromaSubsampling( G16B16G16R16_422_UNORM, Invalid, 1, 16, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( B16G16R16G16_422_UNORM, Invalid, 1, 16, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G16_B16_R16_3PLANE_420_UNORM, Invalid, 3, 16, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G16_B16R16_2PLANE_420_UNORM, Invalid, 2, 16, 2, 2, 12 );
+    addVkFormatDescChromaSubsampling( G16_B16_R16_3PLANE_422_UNORM, Invalid, 3, 16, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G16_B16R16_2PLANE_422_UNORM, Invalid, 2, 16, 2, 1, 8 );
+    addVkFormatDescChromaSubsampling( G16_B16_R16_3PLANE_444_UNORM, Invalid, 3, 16, 1, 1, 6 );
 
 	// When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count
 }
@@ -939,6 +1027,7 @@
 	uint32_t fmtIdx = 0;
 
 	// When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count
+
 	// MTLVertexFormatInvalid must come first.
 	addMTLVertexFormatDesc( Invalid, None, None );
 
@@ -1014,13 +1103,21 @@
 void MVKPixelFormats::buildMTLFormatMaps() {
 
 	// Set all MTLPixelFormats and MTLVertexFormats to undefined/invalid
-	mvkClear(_mtlFormatDescIndicesByMTLPixelFormats, _mtlPixelFormatCount);
+	mvkClear(_mtlFormatDescIndicesByMTLPixelFormatsCore, _mtlPixelFormatCoreCount);
 	mvkClear(_mtlFormatDescIndicesByMTLVertexFormats, _mtlVertexFormatCount);
 
-	// Build lookup table for MTLPixelFormat specs
+	// Build lookup table for MTLPixelFormat specs.
+	// For most Metal format values, which are small and consecutive, use a simple lookup array.
+	// For outlier format values, which can be large, use a map.
 	for (uint32_t fmtIdx = 0; fmtIdx < _mtlPixelFormatCount; fmtIdx++) {
 		MTLPixelFormat fmt = _mtlPixelFormatDescriptions[fmtIdx].mtlPixelFormat;
-		if (fmt) { _mtlFormatDescIndicesByMTLPixelFormats[fmt] = fmtIdx; }
+		if (fmt) {
+			if (fmt < _mtlPixelFormatCoreCount) {
+				_mtlFormatDescIndicesByMTLPixelFormatsCore[fmt] = fmtIdx;
+			} else {
+				_mtlFormatDescIndicesByMTLPixelFormatsExt[fmt] = fmtIdx;
+			}
+		}
 	}
 
 	// Build lookup table for MTLVertexFormat specs
@@ -1135,44 +1232,44 @@
 	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RGBA32Sint, RWC );
 	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v2, RGBA32Float, RWC );
 
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_4x4_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_4x4_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x4_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x4_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x5_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_5x5_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x5_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x5_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x6_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_6x6_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x5_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x5_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x6_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x6_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x8_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_8x8_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x5_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x5_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x6_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x6_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x8_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x8_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x10_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_10x10_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x10_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x10_sRGB, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x12_LDR, RF );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily2_v1, ASTC_12x12_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_4x4_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_4x4_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_5x4_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_5x4_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_5x5_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_5x5_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_6x5_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_6x5_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_6x6_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_6x6_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x5_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x5_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x6_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x6_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x8_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_8x8_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x5_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x5_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x6_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x6_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x8_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x8_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x10_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_10x10_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_12x10_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_12x10_sRGB, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_12x12_LDR, RF );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily2_v1, ASTC_12x12_sRGB, RF );
 
 	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, Depth32Float, DRMR );
 	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v1, Depth32Float_Stencil8, DRMR );
 
-	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGRA10_XR, All );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGRA10_XR_sRGB, All );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGR10_XR, All );
-	addMTLPixelFormatCapabilities(iOS_GPUFamily3_v2, BGR10_XR_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v2, BGRA10_XR, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v2, BGRA10_XR_sRGB, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v2, BGR10_XR, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily3_v2, BGR10_XR_sRGB, All );
 
-	addMTLPixelFormatCapabilities(iOS_GPUFamily1_v4, BGR10A2Unorm, All );
+	addMTLPixelFormatCapabilities( iOS_GPUFamily1_v4, BGR10A2Unorm, All );
 
 	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, UCharNormalized, Vertex );
 	addMTLVertexFormatCapabilities( iOS_GPUFamily1_v4, CharNormalized, Vertex );
@@ -1252,6 +1349,17 @@
 										   VK_FORMAT_FEATURE_BLIT_DST_BIT),
 	kMVKVkFormatFeatureFlagsTexDSAtt    = (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT),
 	kMVKVkFormatFeatureFlagsTexBlend    = (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT),
+    kMVKVkFormatFeatureFlagsTexTransfer          = (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
+                                                    VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
+                                                    VK_FORMAT_FEATURE_BLIT_SRC_BIT |
+                                                    VK_FORMAT_FEATURE_BLIT_DST_BIT),
+    kMVKVkFormatFeatureFlagsTexChromaSubsampling = (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR |
+                                                    VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR |
+                                                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR |
+                                                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR |
+                                                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR |
+                                                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR),
+    kMVKVkFormatFeatureFlagsTexMultiPlanar       = (VK_FORMAT_FEATURE_DISJOINT_BIT_KHR),
 	kMVKVkFormatFeatureFlagsBufRead     = (VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT),
 	kMVKVkFormatFeatureFlagsBufWrite    = (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT),
 	kMVKVkFormatFeatureFlagsBufAtomic   = (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT),
@@ -1266,12 +1374,25 @@
 		mvkEnableFlags(VK_FEATS, kMVKVkFormatFeatureFlags ##TYPE ##CAP);  \
 	}
 
-	VkFormat vkFmt = vkDesc.vkFormat;
 	VkFormatProperties& vkProps = vkDesc.properties;
-	MVKMTLFmtCaps mtlPixFmtCaps = getMTLPixelFormatDesc(vkFmt).mtlFmtCaps;
+	MVKMTLFmtCaps mtlPixFmtCaps = getMTLPixelFormatDesc(vkDesc.mtlPixelFormat).mtlFmtCaps;
+    vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
+    vkProps.linearTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
 
-	// Set optimal tiling features first
-	vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
+    // Chroma subsampling and multi planar features
+    if (getChromaSubsamplingComponentBits(vkDesc.vkFormat) > 0) {
+        vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
+    }
+    uint8_t chromaSubsamplingPlaneCount = getChromaSubsamplingPlaneCount(vkDesc.vkFormat);
+    if (chromaSubsamplingPlaneCount > 0) {
+        mtlPixFmtCaps = kMVKMTLFmtCapsRF;
+        enableFormatFeatures(ChromaSubsampling, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
+    }
+    if (chromaSubsamplingPlaneCount > 1) {
+        enableFormatFeatures(MultiPlanar, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
+    }
+
+	// Optimal tiling features
 	enableFormatFeatures(Read, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
 	enableFormatFeatures(Filter, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
 	enableFormatFeatures(Write, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
@@ -1280,9 +1401,7 @@
 	enableFormatFeatures(Blend, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
 
 	// Linear tiling is not available to depth/stencil or compressed formats.
-	vkProps.linearTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
 	if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed) ) {
-
 		// Start with optimal tiling features, and modify.
 		vkProps.linearTilingFeatures = vkProps.optimalTilingFeatures;
 
@@ -1303,7 +1422,7 @@
 		enableFormatFeatures(Read, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
 		enableFormatFeatures(Write, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
 		enableFormatFeatures(Atomic, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
-		enableFormatFeatures(Vertex, Buf, getMTLVertexFormatDesc(vkFmt).mtlFmtCaps, vkProps.bufferFeatures);
+		enableFormatFeatures(Vertex, Buf, getMTLVertexFormatDesc(vkDesc.mtlVertexFormat).mtlFmtCaps, vkProps.bufferFeatures);
 	}
 }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
index 5bc06cf..467c4ea 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <mutex>
 #include <condition_variable>
 
@@ -57,7 +57,7 @@
     virtual void endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder);
 
     /** Finishes the specified queries and marks them as available. */
-    virtual void finishQueries(MVKVector<uint32_t>& queries);
+    virtual void finishQueries(const MVKArrayRef<uint32_t>& queries);
 
 	/** Resets the results and availability status of the specified queries. */
 	virtual void resetResults(uint32_t firstQuery, uint32_t queryCount, MVKCommandEncoder* cmdEncoder);
@@ -127,8 +127,8 @@
 		Available           /**< Query is available to the host. */
 	};
 
-	MVKVectorInline<Status, kMVKDefaultQueryCount> _availability;
-	MVKVectorInline<DeferredCopy, 4> _deferredCopies;
+	MVKSmallVector<Status, kMVKDefaultQueryCount> _availability;
+	MVKSmallVector<DeferredCopy, 4> _deferredCopies;
 	uint32_t _queryElementCount;
 	std::mutex _availabilityLock;
 	std::condition_variable _availabilityBlocker;
@@ -143,7 +143,7 @@
 class MVKTimestampQueryPool : public MVKQueryPool {
 
 public:
-    void finishQueries(MVKVector<uint32_t>& queries) override;
+    void finishQueries(const MVKArrayRef<uint32_t>& queries) override;
 
 
 #pragma mark Construction
@@ -151,12 +151,12 @@
 	MVKTimestampQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	void getResult(uint32_t query, void* pQryData, bool shouldOutput64Bit) override;
 	id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) override;
 	void encodeSetResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) override;
 
-	MVKVectorInline<uint64_t, kMVKDefaultQueryCount> _timestamps;
+	MVKSmallVector<uint64_t, kMVKDefaultQueryCount> _timestamps;
 };
 
 
@@ -187,7 +187,7 @@
     ~MVKOcclusionQueryPool() override;
 
 protected:
-	void propogateDebugName() override;
+	void propagateDebugName() override;
     void getResult(uint32_t query, void* pQryData, bool shouldOutput64Bit) override;
 	id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) override;
 	void encodeSetResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) override;
@@ -207,7 +207,7 @@
     MVKPipelineStatisticsQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 };
 
 
@@ -221,6 +221,6 @@
 	MVKUnsupportedQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo);
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
index 41ba5bc..e0d89d4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
@@ -47,7 +47,7 @@
 }
 
 // Mark queries as available
-void MVKQueryPool::finishQueries(MVKVector<uint32_t>& queries) {
+void MVKQueryPool::finishQueries(const MVKArrayRef<uint32_t>& queries) {
     lock_guard<mutex> lock(_availabilityLock);
     for (uint32_t qry : queries) { _availability[qry] = Available; }
     _availabilityBlocker.notify_all();      // Predicate of each wait() call will check whether all required queries are available
@@ -184,7 +184,7 @@
 #pragma mark MVKTimestampQueryPool
 
 // Update timestamp values, then mark queries as available
-void MVKTimestampQueryPool::finishQueries(MVKVector<uint32_t>& queries) {
+void MVKTimestampQueryPool::finishQueries(const MVKArrayRef<uint32_t>& queries) {
     uint64_t ts = mvkGetTimestamp();
     for (uint32_t qry : queries) { _timestamps[qry] = ts; }
 
@@ -223,7 +223,7 @@
 #pragma mark -
 #pragma mark MVKOcclusionQueryPool
 
-void MVKOcclusionQueryPool::propogateDebugName() { setLabelIfNotNil(_visibilityResultMTLBuffer, _debugName); }
+void MVKOcclusionQueryPool::propagateDebugName() { setLabelIfNotNil(_visibilityResultMTLBuffer, _debugName); }
 
 // If a dedicated visibility buffer has been established, use it, otherwise fetch the
 // current global visibility buffer, but don't cache it because it could be replaced later.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index c705a9d..61ff838 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -22,7 +22,7 @@
 #include "MVKCommandBuffer.h"
 #include "MVKImage.h"
 #include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <mutex>
 
 #import <Metal/Metal.h>
@@ -64,7 +64,7 @@
 	MVKPhysicalDevice* _physicalDevice;
     uint32_t _queueFamilyIndex;
 	VkQueueFamilyProperties _properties;
-	MVKVectorInline<id<MTLCommandQueue>, kMVKQueueCountPerQueueFamily> _mtlQueues;
+	MVKSmallVector<id<MTLCommandQueue>, kMVKQueueCountPerQueueFamily> _mtlQueues;
 	std::mutex _qLock;
 };
 
@@ -133,7 +133,7 @@
 	friend class MVKQueuePresentSurfaceSubmission;
 
 	MVKBaseObject* getBaseObject() override { return this; };
-	void propogateDebugName() override;
+	void propagateDebugName() override;
 	void initName();
 	void initExecQueue();
 	void initMTLCommandQueue();
@@ -179,7 +179,7 @@
 	friend class MVKQueue;
 
 	MVKQueue* _queue;
-	MVKVectorInline<MVKSemaphore*, 8> _waitSemaphores;
+	MVKSmallVector<MVKSemaphore*> _waitSemaphores;
 	bool _trackPerformance;
 };
 
@@ -193,10 +193,7 @@
 public:
 	void execute() override;
 
-	/** Constructs an instance for the queue. */
-	MVKQueueCommandBufferSubmission(MVKQueue* queue,
-									const VkSubmitInfo* pSubmit,
-									VkFence fence);
+	MVKQueueCommandBufferSubmission(MVKQueue* queue, const VkSubmitInfo* pSubmit, VkFence fence);
 
 protected:
 	friend MVKCommandBuffer;
@@ -205,14 +202,44 @@
 	void setActiveMTLCommandBuffer(id<MTLCommandBuffer> mtlCmdBuff);
 	void commitActiveMTLCommandBuffer(bool signalCompletion = false);
 	void finish();
+	virtual void submitCommandBuffers() {}
 
-	MVKVectorInline<MVKCommandBuffer*, 32> _cmdBuffers;
-	MVKVectorInline<MVKSemaphore*, 8> _signalSemaphores;
+	MVKSmallVector<MVKSemaphore*> _signalSemaphores;
 	MVKFence* _fence;
 	id<MTLCommandBuffer> _activeMTLCommandBuffer;
 };
 
 
+/**
+ * Submits the commands in a set of command buffers to the queue.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKQueueFullCommandBufferSubmission : public MVKQueueCommandBufferSubmission {
+
+public:
+	MVKQueueFullCommandBufferSubmission(MVKQueue* queue, const VkSubmitInfo* pSubmit, VkFence fence) :
+		MVKQueueCommandBufferSubmission(queue, pSubmit, fence) {
+
+			// pSubmit can be null if just tracking the fence alone
+			if (pSubmit) {
+				uint32_t cbCnt = pSubmit->commandBufferCount;
+				_cmdBuffers.reserve(cbCnt);
+				for (uint32_t i = 0; i < cbCnt; i++) {
+					MVKCommandBuffer* cb = MVKCommandBuffer::getMVKCommandBuffer(pSubmit->pCommandBuffers[i]);
+					_cmdBuffers.push_back(cb);
+					setConfigurationResult(cb->getConfigurationResult());
+				}
+			}
+		}
+
+protected:
+	void submitCommandBuffers() override { for (auto& cb : _cmdBuffers) { cb->submit(this); } }
+
+	MVKSmallVector<MVKCommandBuffer*, N> _cmdBuffers;
+};
+
+
 #pragma mark -
 #pragma mark MVKQueuePresentSurfaceSubmission
 
@@ -228,6 +255,13 @@
 protected:
 	id<MTLCommandBuffer> getMTLCommandBuffer();
 
-	MVKVectorInline<MVKPresentableSwapchainImage*, 4> _presentableImages;
+	typedef struct  {
+		MVKPresentableSwapchainImage* presentableImage;
+		bool hasPresentTime;          // Keep track of whether present included VK_GOOGLE_display_timing
+		uint32_t presentID;           // VK_GOOGLE_display_timing presentID
+		uint64_t desiredPresentTime;  // VK_GOOGLE_display_timing desired presentation time in nanoseconds
+	} PresentInfo;
+
+	MVKSmallVector<PresentInfo, 4> _presentInfo;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
index b6f0183..8eba6d8 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
@@ -62,7 +62,7 @@
 #pragma mark -
 #pragma mark MVKQueue
 
-void MVKQueue::propogateDebugName() { setLabelIfNotNil(_mtlQueue, _debugName); }
+void MVKQueue::propagateDebugName() { setLabelIfNotNil(_mtlQueue, _debugName); }
 
 
 #pragma mark Queue submissions
@@ -97,7 +97,27 @@
     VkResult rslt = VK_SUCCESS;
     for (uint32_t sIdx = 0; sIdx < submitCount; sIdx++) {
         VkFence fenceOrNil = (sIdx == (submitCount - 1)) ? fence : VK_NULL_HANDLE; // last one gets the fence
-        VkResult subRslt = submit(new MVKQueueCommandBufferSubmission(this, &pSubmits[sIdx], fenceOrNil));
+
+		const VkSubmitInfo* pVkSub = &pSubmits[sIdx];
+		MVKQueueCommandBufferSubmission* mvkSub;
+		uint32_t cbCnt = pVkSub->commandBufferCount;
+		if (cbCnt <= 1) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<1>(this, pVkSub, fenceOrNil);
+		} else if (cbCnt <= 16) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<16>(this, pVkSub, fenceOrNil);
+		} else if (cbCnt <= 32) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<32>(this, pVkSub, fenceOrNil);
+		} else if (cbCnt <= 64) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<64>(this, pVkSub, fenceOrNil);
+		} else if (cbCnt <= 128) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<128>(this, pVkSub, fenceOrNil);
+		} else if (cbCnt <= 256) {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<256>(this, pVkSub, fenceOrNil);
+		} else {
+			mvkSub = new MVKQueueFullCommandBufferSubmission<512>(this, pVkSub, fenceOrNil);
+		}
+
+        VkResult subRslt = submit(mvkSub);
         if (rslt == VK_SUCCESS) { rslt = subRslt; }
     }
     return rslt;
@@ -226,7 +246,7 @@
 	for (auto* ws : _waitSemaphores) { ws->encodeWait(getActiveMTLCommandBuffer()); }
 
 	// Submit each command buffer.
-	for (auto& cb : _cmdBuffers) { cb->submit(this); }
+	submitCommandBuffers();
 
 	// If using encoded semaphore signaling, do so now.
 	for (auto* ss : _signalSemaphores) { ss->encodeSignal(getActiveMTLCommandBuffer()); }
@@ -307,14 +327,6 @@
 
     // pSubmit can be null if just tracking the fence alone
     if (pSubmit) {
-        uint32_t cbCnt = pSubmit->commandBufferCount;
-        _cmdBuffers.reserve(cbCnt);
-        for (uint32_t i = 0; i < cbCnt; i++) {
-            MVKCommandBuffer* cb = MVKCommandBuffer::getMVKCommandBuffer(pSubmit->pCommandBuffers[i]);
-            _cmdBuffers.push_back(cb);
-            setConfigurationResult(cb->getConfigurationResult());
-        }
-
         uint32_t ssCnt = pSubmit->signalSemaphoreCount;
         _signalSemaphores.reserve(ssCnt);
         for (uint32_t i = 0; i < ssCnt; i++) {
@@ -339,7 +351,10 @@
 	// The semaphores know what to do.
 	id<MTLCommandBuffer> mtlCmdBuff = getMTLCommandBuffer();
 	for (auto& ws : _waitSemaphores) { ws->encodeWait(mtlCmdBuff); }
-	for (auto& img : _presentableImages) { img->presentCAMetalDrawable(mtlCmdBuff); }
+	for (int i = 0; i < _presentInfo.size(); i++ ) {
+		MVKPresentableSwapchainImage *img = _presentInfo[i].presentableImage;
+		img->presentCAMetalDrawable(mtlCmdBuff, _presentInfo[i].hasPresentTime, _presentInfo[i].presentID, _presentInfo[i].desiredPresentTime);
+	}
 	for (auto& ws : _waitSemaphores) { ws->encodeWait(nil); }
 	[mtlCmdBuff commit];
 
@@ -362,13 +377,40 @@
 																   const VkPresentInfoKHR* pPresentInfo)
 	: MVKQueueSubmission(queue, pPresentInfo->waitSemaphoreCount, pPresentInfo->pWaitSemaphores) {
 
+	const VkPresentTimesInfoGOOGLE *pPresentTimesInfoGOOGLE = nullptr;
+	for ( const auto *next = ( VkBaseInStructure* ) pPresentInfo->pNext; next; next = next->pNext )
+	{
+		switch ( next->sType )
+		{
+			case VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE:
+				pPresentTimesInfoGOOGLE = ( const VkPresentTimesInfoGOOGLE * ) next;
+				break;
+			default:
+				break;
+		}
+	}
+
 	// Populate the array of swapchain images, testing each one for status
 	uint32_t scCnt = pPresentInfo->swapchainCount;
+	const VkPresentTimeGOOGLE *pPresentTimesGOOGLE = nullptr;
+	if ( pPresentTimesInfoGOOGLE && pPresentTimesInfoGOOGLE->pTimes ) {
+		pPresentTimesGOOGLE = pPresentTimesInfoGOOGLE->pTimes;
+		MVKAssert( pPresentTimesInfoGOOGLE->swapchainCount == pPresentInfo->swapchainCount, "VkPresentTimesInfoGOOGLE swapchainCount must match VkPresentInfo swapchainCount" );
+	}
 	VkResult* pSCRslts = pPresentInfo->pResults;
-	_presentableImages.reserve(scCnt);
+	_presentInfo.reserve(scCnt);
 	for (uint32_t scIdx = 0; scIdx < scCnt; scIdx++) {
 		MVKSwapchain* mvkSC = (MVKSwapchain*)pPresentInfo->pSwapchains[scIdx];
-		_presentableImages.push_back(mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]));
+		PresentInfo presentInfo = {};
+		presentInfo.presentableImage = mvkSC->getPresentableImage(pPresentInfo->pImageIndices[scIdx]);
+		if ( pPresentTimesGOOGLE ) {
+			presentInfo.hasPresentTime = true;
+			presentInfo.presentID = pPresentTimesGOOGLE[scIdx].presentID;
+			presentInfo.desiredPresentTime = pPresentTimesGOOGLE[scIdx].desiredPresentTime;
+		} else {
+			presentInfo.hasPresentTime = false;
+		}
+		_presentInfo.push_back(presentInfo);
 		VkResult scRslt = mvkSC->getSurfaceStatus();
 		if (pSCRslts) { pSCRslts[scIdx] = scRslt; }
 		setConfigurationResult(scRslt);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index 9c73c45..83abbbb 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 #import <Metal/Metal.h>
 
@@ -30,6 +30,8 @@
 // Parameters to define the sizing of inline collections
 const static uint32_t kMVKDefaultAttachmentCount = 8;
 
+/** Collection of attachment clears . */
+typedef MVKSmallVector<VkClearAttachment, kMVKDefaultAttachmentCount> MVKClearAttachments;
 
 #pragma mark -
 #pragma mark MVKRenderSubpass
@@ -64,7 +66,7 @@
 	 */
 	void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
 										 MVKFramebuffer* framebuffer,
-										 MVKVector<VkClearValue>& clearValues,
+										 const MVKArrayRef<VkClearValue>& clearValues,
 										 bool isRenderingEntireAttachment,
                                          bool loadOverride = false,
                                          bool storeOverride = false);
@@ -73,8 +75,8 @@
 	 * Populates the specified vector with the attachments that need to be cleared
 	 * when the render area is smaller than the full framebuffer size.
 	 */
-	void populateClearAttachments(MVKVector<VkClearAttachment>& clearAtts,
-								  MVKVector<VkClearValue>& clearValues);
+	void populateClearAttachments(MVKClearAttachments& clearAtts,
+								  const MVKArrayRef<VkClearValue>& clearValues);
 
 	/** Constructs an instance for the specified parent renderpass. */
 	MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo);
@@ -88,10 +90,10 @@
 
 	MVKRenderPass* _renderPass;
 	uint32_t _subpassIndex;
-	MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments;
-	MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments;
-	MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments;
-	MVKVectorInline<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
+	MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments;
+	MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments;
+	MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments;
+	MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
 	VkAttachmentReference _depthStencilAttachment;
 	id<MTLTexture> _mtlDummyTex = nil;
 };
@@ -169,11 +171,11 @@
 	friend class MVKRenderSubpass;
 	friend class MVKRenderPassAttachment;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
-	MVKVectorInline<MVKRenderPassAttachment, kMVKDefaultAttachmentCount> _attachments;
-	MVKVectorInline<MVKRenderSubpass, 1> _subpasses;
-	MVKVectorDefault<VkSubpassDependency> _subpassDependencies;
+	MVKSmallVector<MVKRenderPassAttachment> _attachments;
+	MVKSmallVector<MVKRenderSubpass> _subpasses;
+	MVKSmallVector<VkSubpassDependency> _subpassDependencies;
 
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 7fe41fe..8ce7738 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -69,7 +69,7 @@
 
 void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
 													   MVKFramebuffer* framebuffer,
-													   MVKVector<VkClearValue>& clearValues,
+													   const MVKArrayRef<VkClearValue>& clearValues,
 													   bool isRenderingEntireAttachment,
 													   bool loadOverride,
 													   bool storeOverride) {
@@ -110,7 +110,7 @@
 	if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
 		MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx];
 		MVKImageView* dsImage = framebuffer->getAttachment(dsRPAttIdx);
-		MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat();
+		MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0);
 
 		if (pixFmts->isDepthFormat(mtlDSFormat)) {
 			MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment;
@@ -167,8 +167,8 @@
 	}
 }
 
-void MVKRenderSubpass::populateClearAttachments(MVKVector<VkClearAttachment>& clearAtts,
-												MVKVector<VkClearValue>& clearValues) {
+void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
+												const MVKArrayRef<VkClearValue>& clearValues) {
 	VkClearAttachment cAtt;
 
 	uint32_t attIdx;
@@ -342,7 +342,8 @@
 			_lastUseSubpassIdx = max(spIdx, _lastUseSubpassIdx);
 
 			// Validate that the attachment pixel format supports the capabilities required by the subpass.
-			if ( !mvkAreAllFlagsEnabled(pixFmts->getCapabilities(_info.format), reqCaps) ) {
+			// Use MTLPixelFormat to look up capabilities to permit Metal format substitution.
+			if ( !mvkAreAllFlagsEnabled(pixFmts->getCapabilities(pixFmts->getMTLPixelFormat(_info.format)), reqCaps) ) {
 				_renderPass->setConfigurationResult(reportError(VK_ERROR_FORMAT_NOT_SUPPORTED, "vkCreateRenderPass(): Attachment format %s on this device does not support the VkFormat attachment capabilities required by the subpass at index %d.", _renderPass->getPixelFormats()->getName(_info.format), spIdx));
 			}
 		}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKResource.h b/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
index 3f5c235..ee691de 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKResource.h
@@ -20,6 +20,7 @@
 
 #include "MVKDevice.h"
 #include "MVKDeviceMemory.h"
+#include "MVKMTLResourceBindings.h"
 
 class MVKCommandEncoder;
 
@@ -38,17 +39,8 @@
     /** Returns the byte offset in the bound device memory. */
     inline VkDeviceSize getDeviceMemoryOffset() { return _deviceMemoryOffset; }
 
-	/** Returns the memory requirements of this resource by populating the specified structure. */
-	virtual VkResult getMemoryRequirements(VkMemoryRequirements* pMemoryRequirements) = 0;
-
-	/** Returns the memory requirements of this resource by populating the specified structure. */
-	virtual VkResult getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements) = 0;
-
 	/** Binds this resource to the specified offset within the specified memory allocation. */
-	virtual VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
-
-	/** Binds this resource according to the specified bind information. */
-	virtual VkResult bindDeviceMemory2(const void* pBindInfo);
+	VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset);
 
 	/** Returns the device memory underlying this resource. */
 	inline MVKDeviceMemory* getDeviceMemory() { return _deviceMemory; }
@@ -70,9 +62,9 @@
 	/** Applies the specified global memory barrier. */
 	virtual void applyMemoryBarrier(VkPipelineStageFlags srcStageMask,
 									VkPipelineStageFlags dstStageMask,
-									VkMemoryBarrier* pMemoryBarrier,
-                                    MVKCommandEncoder* cmdEncoder,
-                                    MVKCommandUse cmdUse) = 0;
+									MVKPipelineBarrier& barrier,
+									MVKCommandEncoder* cmdEncoder,
+									MVKCommandUse cmdUse) = 0;
 
 	
 #pragma mark Construction
@@ -88,4 +80,6 @@
 	VkDeviceSize _deviceMemoryOffset = 0;
     VkDeviceSize _byteCount = 0;
     VkDeviceSize _byteAlignment = 0;
+	VkExternalMemoryHandleTypeFlags _externalMemoryHandleTypes = 0;
+	bool _requiresDedicatedMemoryAllocation = false;
 };
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm b/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm
index ab50512..bf106f1 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKResource.mm
@@ -21,18 +21,6 @@
 #include "MVKEnvironment.h"
 
 
-struct MVKBindDeviceMemoryInfo {
-	VkStructureType sType;
-	void* pNext;
-	union {
-		VkBuffer buffer;
-		VkImage image;
-	};
-	VkDeviceMemory memory;
-	VkDeviceSize memoryOffset;
-};
-
-
 #pragma mark MVKResource
 
 VkResult MVKResource::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset) {
@@ -46,11 +34,6 @@
 	return VK_SUCCESS;
 }
 
-VkResult MVKResource::bindDeviceMemory2(const void* pBindInfo) {
-	auto* mvkBindInfo = (const MVKBindDeviceMemoryInfo*)pBindInfo;
-	return bindDeviceMemory((MVKDeviceMemory*)mvkBindInfo->memory, mvkBindInfo->memoryOffset);
-}
-
 // Returns whether the specified global memory barrier requires a sync between this
 // texture and host memory for the purpose of the host reading texture memory.
 bool MVKResource::needsHostReadSync(VkPipelineStageFlags srcStageMask,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
index c4fdc0a..3af05fc 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
@@ -20,7 +20,7 @@
 
 #include "MVKDevice.h"
 #include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
 #include <MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h>
 #include <mutex>
@@ -151,7 +151,7 @@
 	void merge(MVKShaderLibraryCache* other);
 
 	MVKVulkanAPIDeviceObject* _owner;
-	MVKVectorInline<std::pair<SPIRVToMSLConversionConfiguration, MVKShaderLibrary*>, 1> _shaderLibraries;
+	MVKSmallVector<std::pair<SPIRVToMSLConversionConfiguration, MVKShaderLibrary*>> _shaderLibraries;
 };
 
 
@@ -224,7 +224,7 @@
 protected:
 	friend MVKShaderCacheIterator;
 
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	MVKGLSLConversionShaderStage getMVKGLSLConversionShaderStage(SPIRVToMSLConversionConfiguration* pContext);
 
 	MVKShaderLibraryCache _shaderLibraryCache;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h
index 2d4ab94..a0104ab 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h
@@ -76,7 +76,7 @@
 	~MVKSurface() override;
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	void initLayerObserver();
 
 	MVKInstance* _mvkInstance;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
index ba55a6d..a1fc360 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
@@ -20,7 +20,7 @@
 
 #include "MVKDevice.h"
 #include "MVKImage.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 #import "CAMetalLayer+MoltenVK.h"
 #import <Metal/Metal.h>
@@ -89,8 +89,13 @@
 
 	/** Adds HDR metadata to this swapchain. */
 	void setHDRMetadataEXT(const VkHdrMetadataEXT& metadata);
-
-
+	
+	/** VK_GOOGLE_display_timing - returns the duration of the refresh cycle */
+	VkResult getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration);
+	
+	/** VK_GOOGLE_display_timing - returns past presentation times */
+	VkResult getPastPresentationTiming(uint32_t *pCount, VkPastPresentationTimingGOOGLE *pPresentationTimings);
+	
 #pragma mark Construction
 	
 	MVKSwapchain(MVKDevice* device, const VkSwapchainCreateInfoKHR* pCreateInfo);
@@ -100,7 +105,7 @@
 protected:
 	friend class MVKPresentableSwapchainImage;
 
-	void propogateDebugName() override;
+	void propagateDebugName() override;
 	void initCAMetalLayer(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt);
 	void initSurfaceImages(const VkSwapchainCreateInfoKHR* pCreateInfo, uint32_t imgCnt);
 	void releaseUndisplayedSurfaces();
@@ -108,15 +113,22 @@
     void willPresentSurface(id<MTLTexture> mtlTexture, id<MTLCommandBuffer> mtlCmdBuff);
     void renderWatermark(id<MTLTexture> mtlTexture, id<MTLCommandBuffer> mtlCmdBuff);
     void markFrameInterval();
+	void recordPresentTime(uint32_t presentID, uint64_t desiredPresentTime, uint64_t actualPresentTime);
 
 	CAMetalLayer* _mtlLayer;
     MVKWatermark* _licenseWatermark;
-	MVKVectorInline<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
+	MVKSmallVector<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
 	std::atomic<uint64_t> _currentAcquisitionID;
     CGSize _mtlLayerOrigDrawSize;
     uint64_t _lastFrameTime;
     uint32_t _currentPerfLogFrameCount;
     std::atomic<bool> _surfaceLost;
     MVKBlockObserver* _layerObserver;
+	static const int kMaxPresentationHistory = 60;
+	VkPastPresentationTimingGOOGLE _presentTimingHistory[kMaxPresentationHistory];
+	uint32_t _presentHistoryCount;
+	uint32_t _presentHistoryIndex;
+	uint32_t _presentHistoryHeadIndex;
+	std::mutex _presentHistoryLock;
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
index c73d16d..45e2335 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm
@@ -30,6 +30,10 @@
 #import "CAMetalLayer+MoltenVK.h"
 #import "MVKBlockObserver.h"
 
+#if MVK_IOS
+#	include <UIKit/UIScreen.h>
+#endif
+
 #include <libkern/OSByteOrder.h>
 
 using namespace std;
@@ -38,7 +42,7 @@
 #pragma mark -
 #pragma mark MVKSwapchain
 
-void MVKSwapchain::propogateDebugName() {
+void MVKSwapchain::propagateDebugName() {
 	if (_debugName) {
 		size_t imgCnt = _presentableImages.size();
 		for (size_t imgIdx = 0; imgIdx < imgCnt; imgIdx++) {
@@ -235,8 +239,12 @@
 	_layerObserver(nil),
 	_currentPerfLogFrameCount(0),
 	_lastFrameTime(0),
-	_licenseWatermark(nil) {
+	_licenseWatermark(nil),
+	_presentHistoryCount(0),
+	_presentHistoryIndex(0),
+	_presentHistoryHeadIndex(0) {
 
+	memset(_presentTimingHistory, 0, sizeof(_presentTimingHistory));
 	// If applicable, release any surfaces (not currently being displayed) from the old swapchain.
 	MVKSwapchain* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain;
 	if (oldSwapchain) { oldSwapchain->releaseUndisplayedSurfaces(); }
@@ -374,6 +382,58 @@
     MVKLogInfo("Created %d swapchain images with initial size (%d, %d).", imgCnt, imgExtent.width, imgExtent.height);
 }
 
+VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) {
+	NSInteger framesPerSecond = 60;
+
+#if MVK_IOS
+	UIScreen* screen = [UIScreen mainScreen];
+	if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) {
+		framesPerSecond = screen.maximumFramesPerSecond;
+	}
+#endif
+#if MVK_MACOS
+	// TODO: hook this up for macOS, probably need to use CGDisplayModeGetRefeshRate
+#endif
+
+	pRefreshCycleDuration->refreshDuration = (uint64_t)1e9 / framesPerSecond;
+	return VK_SUCCESS;
+}
+
+VkResult MVKSwapchain::getPastPresentationTiming(uint32_t *pCount, VkPastPresentationTimingGOOGLE *pPresentationTimings) {
+	std::lock_guard<std::mutex> lock(_presentHistoryLock);
+	if (pCount && pPresentationTimings == nullptr) {
+		*pCount = _presentHistoryCount;
+	} else if (pPresentationTimings) {
+		uint32_t index = _presentHistoryHeadIndex;
+		uint32_t countRemaining = std::min(_presentHistoryCount, *pCount);
+		uint32_t outIndex = 0;
+		while (countRemaining > 0) {
+			pPresentationTimings[outIndex] = _presentTimingHistory[index];
+			countRemaining--;
+			index = (index + 1) % kMaxPresentationHistory;
+			outIndex++;
+		}
+	}
+	return VK_SUCCESS;
+}
+
+void MVKSwapchain::recordPresentTime(uint32_t presentID, uint64_t desiredPresentTime, uint64_t actualPresentTime) {
+	std::lock_guard<std::mutex> lock(_presentHistoryLock);
+	if (_presentHistoryCount < kMaxPresentationHistory) {
+		_presentHistoryCount++;
+		_presentHistoryHeadIndex = 0;
+	} else {
+		_presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory;
+	}
+	_presentTimingHistory[_presentHistoryIndex].presentID = presentID;
+	_presentTimingHistory[_presentHistoryIndex].desiredPresentTime = desiredPresentTime;
+	_presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime;
+	// These details are not available in Metal
+	_presentTimingHistory[_presentHistoryIndex].earliestPresentTime = actualPresentTime;
+	_presentTimingHistory[_presentHistoryIndex].presentMargin = 0;
+	_presentHistoryIndex = (_presentHistoryIndex + 1) % kMaxPresentationHistory;
+}
+
 MVKSwapchain::~MVKSwapchain() {
 	for (auto& img : _presentableImages) { _device->destroyPresentableSwapchainImage(img, NULL); }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
index 67c3e15..917255c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.h
@@ -159,7 +159,7 @@
     MVKSemaphore(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {}
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 };
 
@@ -270,7 +270,7 @@
 		MVKVulkanAPIDeviceObject(device), _isSignaled(mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_FENCE_CREATE_SIGNALED_BIT)) {}
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 	void notifySitters();
 
 	std::mutex _lock;
@@ -349,7 +349,7 @@
 	MVKEvent(MVKDevice* device, const VkEventCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {}
 
 protected:
-	void propogateDebugName() override {}
+	void propagateDebugName() override {}
 
 };
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
index 9a91477..35f8397 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
@@ -101,7 +101,7 @@
 	~MVKVulkanAPIObject() override;
 
 protected:
-	virtual void propogateDebugName() = 0;
+	virtual void propagateDebugName() = 0;
 
 	std::atomic<uint32_t> _refCount;
 	NSString* _debugName = nil;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
index 7f99ec6..ec5fef0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
@@ -40,7 +40,7 @@
 	if (pObjectName) {
 		[_debugName release];
 		_debugName = [[NSString alloc] initWithUTF8String: pObjectName];	// retained
-		propogateDebugName();
+		propagateDebugName();
 	}
 	return VK_SUCCESS;
 }
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 196860b..0c74478 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -39,58 +39,62 @@
 #define MVK_EXTENSION_LAST(var, EXT, type) MVK_EXTENSION(var, EXT, type)
 #endif
 
-MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_surface, KHR_SURFACE, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, MVK_EXTENSION_INSTANCE)
-MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, MVK_EXTENSION_DEVICE)
-MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, MVK_EXTENSION_DEVICE)
+MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE)
+MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE)
+MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE)
+MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE)
+MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE)
+MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE)
+MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE)
+MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE)
+MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE)
+MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE)
+MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE)
+MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE)
+MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE)
+MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE)
+MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE)
+MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE)
+MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE)
+MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE)
+MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE)
+MVK_EXTENSION(KHR_sampler_ycbcr_conversion, KHR_SAMPLER_YCBCR_CONVERSION, DEVICE)
+MVK_EXTENSION(KHR_shader_draw_parameters, KHR_SHADER_DRAW_PARAMETERS, DEVICE)
+MVK_EXTENSION(KHR_shader_float16_int8, KHR_SHADER_FLOAT16_INT8, DEVICE)
+MVK_EXTENSION(KHR_storage_buffer_storage_class, KHR_STORAGE_BUFFER_STORAGE_CLASS, DEVICE)
+MVK_EXTENSION(KHR_surface, KHR_SURFACE, INSTANCE)
+MVK_EXTENSION(KHR_swapchain, KHR_SWAPCHAIN, DEVICE)
+MVK_EXTENSION(KHR_swapchain_mutable_format, KHR_SWAPCHAIN_MUTABLE_FORMAT, DEVICE)
+MVK_EXTENSION(KHR_uniform_buffer_standard_layout, KHR_UNIFORM_BUFFER_STANDARD_LAYOUT, DEVICE)
+MVK_EXTENSION(KHR_variable_pointers, KHR_VARIABLE_POINTERS, DEVICE)
+MVK_EXTENSION(EXT_debug_marker, EXT_DEBUG_MARKER, DEVICE)
+MVK_EXTENSION(EXT_debug_report, EXT_DEBUG_REPORT, INSTANCE)
+MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, INSTANCE)
+MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE)
+MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE)
+MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE)
+MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE)
+MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE)
+MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE)
+MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE)
+MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE)
+MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE)
+MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER, DEVICE)
+MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE)
+MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE)
+MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE)
+MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET, DEVICE)
+MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE)
+MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE)
+MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE)
+MVK_EXTENSION(AMD_gpu_shader_half_float, AMD_GPU_SHADER_HALF_FLOAT, DEVICE)
+MVK_EXTENSION(AMD_negative_viewport_height, AMD_NEGATIVE_VIEWPORT_HEIGHT, DEVICE)
+MVK_EXTENSION(AMD_shader_image_load_store_lod, AMD_SHADER_IMAGE_LOAD_STORE_LOD, DEVICE)
+MVK_EXTENSION(AMD_shader_trinary_minmax, AMD_SHADER_TRINARY_MINMAX, DEVICE)
+MVK_EXTENSION(IMG_format_pvrtc, IMG_FORMAT_PVRTC, DEVICE)
+MVK_EXTENSION(INTEL_shader_integer_functions2, INTEL_SHADER_INTEGER_FUNCTIONS_2, DEVICE)
+MVK_EXTENSION(GOOGLE_display_timing, GOOGLE_DISPLAY_TIMING, DEVICE)
+MVK_EXTENSION_LAST(NV_glsl_shader, NV_GLSL_SHADER, DEVICE)
 
 #undef MVK_EXTENSION
 #undef MVK_EXTENSION_LAST
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
index 4d15962..80c221a 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
@@ -47,54 +47,30 @@
 // Returns whether the specified properties are valid for this platform
 static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
 #if MVK_MACOS
-	if (pProperties == &kVkExtProps_EXT_HDR_METADATA) {
-		return mvkOSVersionIsAtLeast(10.15);
-	}
-	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) {
-		return mvkOSVersionIsAtLeast(10.13);
-	}
-	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
-		return mvkOSVersionIsAtLeast(10.13);
-	}
-	if (pProperties == &kVkExtProps_EXT_POST_DEPTH_COVERAGE) { return false; }
-	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
-		return mvkOSVersionIsAtLeast(10.14);
-	}
-	if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) {
-		return mvkOSVersionIsAtLeast(10.13);
-	}
 	if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; }
-	if (pProperties == &kVkExtProps_AMD_SHADER_IMAGE_LOAD_STORE_LOD) { return false; }
-	if (pProperties == &kVkExtProps_AMD_SHADER_TRINARY_MINMAX) {
-		return mvkOSVersionIsAtLeast(10.14);
-	}
 	if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; }
+	if (pProperties == &kVkExtProps_EXT_POST_DEPTH_COVERAGE) { return false; }
+	if (pProperties == &kVkExtProps_AMD_SHADER_IMAGE_LOAD_STORE_LOD) { return false; }
+
+	if (pProperties == &kVkExtProps_EXT_HDR_METADATA) { return mvkOSVersionIsAtLeast(10.15); }
+	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) { return mvkOSVersionIsAtLeast(10.13); }
+	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) { return mvkOSVersionIsAtLeast(10.13); }
+	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) { return mvkOSVersionIsAtLeast(10.14); }
+	if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) { return mvkOSVersionIsAtLeast(10.13); }
+	if (pProperties == &kVkExtProps_AMD_SHADER_TRINARY_MINMAX) { return mvkOSVersionIsAtLeast(10.14); }
 #endif
 #if MVK_IOS
+	if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
 	if (pProperties == &kVkExtProps_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE) { return false; }
 	if (pProperties == &kVkExtProps_EXT_HDR_METADATA) { return false; }
-	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) {
-		return mvkOSVersionIsAtLeast(11.0);
-	}
-	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
-		return mvkOSVersionIsAtLeast(11.0);
-	}
-	if (pProperties == &kVkExtProps_EXT_POST_DEPTH_COVERAGE) {
-		return mvkOSVersionIsAtLeast(11.0);
-	}
-	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
-		return mvkOSVersionIsAtLeast(12.0);
-	}
-	if (pProperties == &kVkExtProps_EXT_SWAPCHAIN_COLOR_SPACE) {
-		return mvkOSVersionIsAtLeast(9.0);
-	}
-	if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) {
-		return mvkOSVersionIsAtLeast(11.0);
-	}
-	if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
-	if (pProperties == &kVkExtProps_AMD_SHADER_TRINARY_MINMAX) {
-		return mvkOSVersionIsAtLeast(12.0);
-	}
+
+	if (pProperties == &kVkExtProps_EXT_FRAGMENT_SHADER_INTERLOCK) { return mvkOSVersionIsAtLeast(11.0); }
+	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) { return mvkOSVersionIsAtLeast(11.0); }
+	if (pProperties == &kVkExtProps_EXT_POST_DEPTH_COVERAGE) { return mvkOSVersionIsAtLeast(11.0); }
+	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) { return mvkOSVersionIsAtLeast(12.0); }
+	if (pProperties == &kVkExtProps_EXT_SWAPCHAIN_COLOR_SPACE) { return mvkOSVersionIsAtLeast(9.0); }
+	if (pProperties == &kVkExtProps_EXT_TEXEL_BUFFER_ALIGNMENT) { return mvkOSVersionIsAtLeast(11.0); }
+	if (pProperties == &kVkExtProps_AMD_SHADER_TRINARY_MINMAX) { return mvkOSVersionIsAtLeast(12.0); }
 #endif
 
 	return true;
@@ -127,17 +103,19 @@
 #include "MVKExtensions.def"
 }
 
+#define MVK_ENSURE_EXTENSION_TYPE(var, EXT, type) vk_ ##var.enabled = vk_ ##var.enabled && MVK_EXTENSION_ ##type;
+
 void MVKExtensionList::disableAllButEnabledInstanceExtensions() {
-#define MVK_EXTENSION_INSTANCE	true
-#define MVK_EXTENSION_DEVICE	false
-#define MVK_EXTENSION(var, EXT, type) vk_ ##var.enabled = type && vk_ ##var.enabled;
+#define MVK_EXTENSION_INSTANCE         true
+#define MVK_EXTENSION_DEVICE           false
+#define MVK_EXTENSION(var, EXT, type)  MVK_ENSURE_EXTENSION_TYPE(var, EXT, type)
 #include "MVKExtensions.def"
 }
 
 void MVKExtensionList::disableAllButEnabledDeviceExtensions() {
-#define MVK_EXTENSION_INSTANCE	false
-#define MVK_EXTENSION_DEVICE	true
-#define MVK_EXTENSION(var, EXT, type) vk_ ##var.enabled = type && vk_ ##var.enabled;
+#define MVK_EXTENSION_INSTANCE         false
+#define MVK_EXTENSION_DEVICE           true
+#define MVK_EXTENSION(var, EXT, type)  MVK_ENSURE_EXTENSION_TYPE(var, EXT, type)
 #include "MVKExtensions.def"
 }
 
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.h b/MoltenVK/MoltenVK/Layers/MVKLayers.h
index 76a00ff..993105a 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.h
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.h
@@ -20,7 +20,7 @@
 
 #include "MVKBaseObject.h"
 #include "MVKExtensions.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
 
 
 #pragma mark MVKLayer
@@ -114,7 +114,7 @@
 	static MVKLayerManager* globalManager();
 
 protected:
-	MVKVectorInline<MVKLayer, 1> _layers;
+	MVKSmallVector<MVKLayer, 1> _layers;
 
 };
 
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
index fa1753e..aefaef3 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
@@ -78,7 +78,7 @@
 		return VK_SUCCESS;
 	}
 
-	// Othewise, determine how many layers we'll return, and return that count
+	// Otherwise, determine how many layers we'll return, and return that count
 	uint32_t layerCnt = (uint32_t)_layers.size();
 	VkResult result = (*pCount >= layerCnt) ? VK_SUCCESS : VK_INCOMPLETE;
 	*pCount = min(layerCnt, *pCount);
diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
index c43332a..1789e78 100644
--- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
+++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm
@@ -119,10 +119,9 @@
 
 	// If message is too big for original buffer, allocate a buffer big enough to hold it and
 	// write the message out again. We only want to do this double writing if we have to.
-	// Create the redoBuff outside scope of if block to allow it to be referencable by pMessage later below.
 	int redoBuffSize = (msgLen >= kOrigBuffSize) ? msgLen + 1 : 0;
-	char redoBuff[redoBuffSize];
-	if (redoBuffSize > 0) {
+	char *redoBuff = NULL;
+	if (redoBuffSize > 0 && (redoBuff = (char *)malloc(redoBuffSize))) {
 		pMessage = redoBuff;
 		vsnprintf(redoBuff, redoBuffSize, format, redoArgs);
 	}
@@ -135,6 +134,8 @@
 
 	// Broadcast the message to any Vulkan debug report callbacks
 	if (hasDebugCallbacks) { mvkInst->debugReportMessage(mvkAPIObj, aslLvl, pMessage); }
+
+	free(redoBuff);
 }
 
 VkResult MVKBaseObject::reportError(VkResult vkErr, const char* format, ...) {
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index c256bf0..a8ea008 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -29,18 +29,6 @@
 
 #pragma mark Math
 
-/**
- * The following constants are used to indicate values that have no defined limit.
- * They are ridiculously large numbers, but low enough to be safely used as both
- * uint and int values without risking overflowing between positive and negative values.
- */
-static int32_t kMVKUndefinedLargeNegativeInt32 = std::numeric_limits<int32_t>::min() / 2;
-static int32_t kMVKUndefinedLargePositiveInt32 = std::numeric_limits<int32_t>::max() / 2;
-static uint32_t kMVKUndefinedLargeUInt32 = kMVKUndefinedLargePositiveInt32;
-static int64_t kMVKUndefinedLargeNegativeInt64 = std::numeric_limits<int64_t>::min() / 2;
-static int64_t kMVKUndefinedLargePositiveInt64 = std::numeric_limits<int64_t>::max() / 2;
-static uint64_t kMVKUndefinedLargeUInt64 = kMVKUndefinedLargePositiveInt64;
-
 // Common scaling multipliers
 #define KIBI		(1024)
 #define MEBI		(KIBI * KIBI)
@@ -55,12 +43,6 @@
 /** A representation of the value of 1.0 as a 16-bit half-float. */
 #define kHalfFloat1	0x3C00
 
-/** Common header for many standard Vulkan API structures. */
-typedef struct {
-	VkStructureType sType;
-	const void* pNext;
-} MVKVkAPIStructHeader;
-
 
 #pragma mark -
 #pragma mark Vertex content structures
@@ -76,7 +58,7 @@
 #pragma mark Vulkan support
 
 /** Tracks the Vulkan command currently being used. */
-typedef enum {
+typedef enum : uint8_t {
     kMVKCommandUseNone,                     /**< No use defined. */
     kMVKCommandUseQueueSubmit,              /**< vkQueueSubmit. */
     kMVKCommandUseQueuePresent,             /**< vkQueuePresentKHR. */
@@ -142,21 +124,23 @@
 #pragma mark -
 #pragma mark Alignment functions
 
-/** Returns whether the specified value is a power-of-two. */
-static inline bool mvkIsPowerOfTwo(uintptr_t value) {
+/** Returns whether the specified positive value is a power-of-two. */
+template<typename T>
+static inline bool mvkIsPowerOfTwo(T value) {
 	// Test POT:  (x != 0) && ((x & (x - 1)) == 0)
 	return value && ((value & (value - 1)) == 0);
 }
 
 /**
- * Ensures the specified value is a power-of-two. Returns the specified value if it is a
- * power-of-two value. If it is not, returns the next power-of-two value that is larger
- * than the specified value is returned.
+ * Ensures the specified positive value is a power-of-two. Returns the specified value
+ * if it is a power-of-two value. If it is not, returns the next power-of-two value
+ * that is larger than the specified value is returned.
  */
-static inline uintptr_t mvkEnsurePowerOfTwo(uintptr_t value) {
+template<typename T>
+static inline T mvkEnsurePowerOfTwo(T value) {
 	if (mvkIsPowerOfTwo(value)) { return value; }
 
-	uintptr_t pot = 1;
+	T pot = 1;
 	while(pot <= value) { pot <<= 1; };
 	return pot;
 }
@@ -167,12 +151,13 @@
  *
  * This implementation returns zero for both zero and one as inputs.
  */
-static inline uint32_t mvkPowerOfTwoExponent(uintptr_t value) {
-    uintptr_t p2Value = mvkEnsurePowerOfTwo(value);
+template<typename T>
+static inline T mvkPowerOfTwoExponent(T value) {
+    T p2Value = mvkEnsurePowerOfTwo(value);
 
     // Count the trailing zeros
     p2Value = (p2Value ^ (p2Value - 1)) >> 1;  // Set trailing 0s to 1s and zero rest
-    uint32_t potExp = 0;
+    T potExp = 0;
     while (p2Value) {
         p2Value >>= 1;
         potExp++;
@@ -236,6 +221,18 @@
  */
 void mvkFlipVertically(void* rowMajorData, uint32_t rowCount, size_t bytesPerRow);
 
+/**
+ * The following constants are used to indicate values that have no defined limit.
+ * They are ridiculously large numbers, but low enough to be safely used as both
+ * uint and int values without risking overflowing between positive and negative values.
+ */
+static  int32_t kMVKUndefinedLargePositiveInt32 =  mvkEnsurePowerOfTwo(std::numeric_limits<int32_t>::max() / 2);
+static  int32_t kMVKUndefinedLargeNegativeInt32 = -kMVKUndefinedLargePositiveInt32;
+static uint32_t kMVKUndefinedLargeUInt32        =  kMVKUndefinedLargePositiveInt32;
+static  int64_t kMVKUndefinedLargePositiveInt64 =  mvkEnsurePowerOfTwo(std::numeric_limits<int64_t>::max() / 2);
+static  int64_t kMVKUndefinedLargeNegativeInt64 = -kMVKUndefinedLargePositiveInt64;
+static uint64_t kMVKUndefinedLargeUInt64        =  kMVKUndefinedLargePositiveInt64;
+
 
 #pragma mark Vulkan structure support functions
 
@@ -327,6 +324,9 @@
 			mvkVKComponentSwizzlesMatch(cm1.a, cm2.a, VK_COMPONENT_SWIZZLE_A));
 }
 
+/** Print the size of the type. */
+#define mvkPrintSizeOf(type)    printf("Size of " #type " is %lu.\n", sizeof(type))
+
 
 #pragma mark -
 #pragma mark Template functions
@@ -373,6 +373,23 @@
 
 #pragma mark Containers
 
+/**
+ * Structure to reference an array of typed elements in contiguous memory.
+ * Allocation and management of the memory is handled externally.
+ */
+template<typename Type>
+struct MVKArrayRef {
+	Type* data;
+	const size_t size;
+
+	const Type* begin() const { return data; }
+	const Type* end() const { return &data[size]; }
+	const Type& operator[]( const size_t i ) const { return data[i]; }
+	Type& operator[]( const size_t i ) { return data[i]; }
+	MVKArrayRef() : MVKArrayRef(nullptr, 0) {}
+	MVKArrayRef(Type* d, size_t s) : data(d), size(s) {}
+};
+
 /** Ensures the size of the specified container is at least the specified size. */
 template<typename C, typename S>
 void mvkEnsureSize(C& container, S size) {
diff --git a/MoltenVK/MoltenVK/Utility/MVKSmallVector.h b/MoltenVK/MoltenVK/Utility/MVKSmallVector.h
new file mode 100755
index 0000000..1d1612b
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKSmallVector.h
@@ -0,0 +1,889 @@
+/*

+ * MVKSmallVector.h

+ *

+ * Copyright (c) 2012-2020 Dr. Torsten Hans (hans@ipacs.de)

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ * 

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#pragma once

+

+// In case MVKSmallVector should use just std::vector instead

+#if 0

+

+template<typename T, size_t N = 0>

+using MVKSmallVector = std::vector<T>;

+

+#else

+

+// MVKSmallVector.h is a sequence container that (optionally) implements a small buffer optimization.

+// It behaves similarly to std::vector, except until a certain number of elements are reserved,

+// it does not use the heap. Like std::vector, MVKSmallVector is guaranteed to use contiguous memory,

+// so if the preallocated number of elements are exceeded, all elements are then in heap.

+// MVKSmallVector supports just the necessary members to be compatible with MoltenVK.

+// If C++17 will be the default in the future, code can be simplified quite a bit.

+//

+// Example:

+//

+//  MVKSmallVector<int, 2> sv;

+//  sv.push_back( 1 );  // no allocation, uses pre-allocated memory

+//  sv.push_back( 2 );	// no allocation, uses pre-allocated memory

+//  sv.push_back( 3 );	// adding another element now reserves memory from heap and copies from pre-allocated memory

+//

+// If you don't need any inline storage use:

+//  MVKSmallVector<int> v;   // this is essentially the same as using std::vector

+//

+// The per-instance memory overhead of MVKSmallVector (16 bytes) is smaller than MVKVector (40 bytes)

+// and std::vector (24 bytes), but MVKSmallVector lacks the polymorphism of MVKVector (or std::vector),

+// that allows them to be passed around to functions without reference to the pre-allocation size.

+// MVKSmallVector supports the contents() function to derive an MVKArrayRef from its contents,

+// which can be passed around without reference to the pre-allocaton size.

+

+#include "MVKSmallVectorAllocator.h"

+#include "MVKFoundation.h"

+#include <type_traits>

+#include <initializer_list>

+#include <utility>

+

+

+template<typename Type, typename Allocator = mvk_smallvector_allocator<Type, 0>>

+class MVKSmallVectorImpl

+{

+  Allocator  alc;

+  

+public:

+  class iterator : public std::iterator<std::random_access_iterator_tag, Type>

+  {

+    const MVKSmallVectorImpl *vector;

+    size_t               index;

+

+  public:

+    typedef typename std::iterator_traits<iterator>::difference_type diff_type;

+

+    iterator() : vector{ nullptr }, index{ 0 } { }

+    iterator( const size_t _index, const MVKSmallVectorImpl &_vector ) : vector{ &_vector }, index{ _index } { }

+

+    iterator &operator=( const iterator &it )

+    {

+      vector = it.vector;

+      index  = it.index;

+      return *this;

+    }

+

+    Type *operator->() { return &vector->alc.ptr[index]; }

+    Type &operator*()  { return  vector->alc.ptr[index]; }

+    operator Type*()   { return &vector->alc.ptr[index]; }

+

+    bool operator==( const iterator &it ) const { return vector == it.vector && index == it.index; }

+    bool operator!=( const iterator &it ) const { return vector != it.vector || index != it.index; }

+

+    iterator& operator++()      {                 ++index; return *this; }

+    iterator  operator++( int ) { auto t = *this; ++index; return t; }

+    iterator& operator--()      {                 --index; return *this; }

+    iterator  operator--( int ) { auto t = *this; --index; return t; }

+

+    iterator operator+ (const diff_type n)   { return iterator( index + n, *vector ); }

+    iterator& operator+= (const diff_type n) { index += n; return *this; }

+    iterator operator- (const diff_type n)   { return iterator( index - n, *vector ); }

+    iterator& operator-= (const diff_type n) { index -= n; return *this; }

+

+    diff_type operator- (const iterator& it) { return index - it.index; }

+

+    bool operator< (const iterator& it)  { return index < it.index; }

+    bool operator<= (const iterator& it) { return index <= it.index; }

+    bool operator> (const iterator& it)  { return index > it.index; }

+    bool operator>= (const iterator& it) { return index >= it.index; }

+

+    const Type &operator[]( const diff_type i ) const { return vector->alc.ptr[index + i]; }

+    Type &operator[]( const diff_type i )             { return vector->alc.ptr[index + i]; }

+

+    bool   is_valid()     const { return index < vector->alc.size(); }

+    size_t get_position() const { return index; }

+  };

+

+private:

+  // this is the growth strategy -> adjust to your needs

+  size_t vector_GetNextCapacity() const

+  {

+    constexpr auto ELEMENTS_FOR_64_BYTES = 64 / sizeof( Type );

+    constexpr auto MINIMUM_CAPACITY = ELEMENTS_FOR_64_BYTES > 4 ? ELEMENTS_FOR_64_BYTES : 4;

+    const auto current_capacity = capacity();

+    return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;

+  }

+

+  void vector_Allocate( const size_t s )

+  {

+    const auto new_reserved_size = s > size() ? s : size();

+

+    alc.allocate( new_reserved_size );

+  }

+

+  void vector_ReAllocate( const size_t s )

+  {

+    alc.re_allocate( s );

+  }

+

+public:

+  MVKSmallVectorImpl()

+  {

+  }

+

+  MVKSmallVectorImpl( const size_t n, const Type t )

+  {

+    if( n > 0 )

+    {

+      alc.allocate( n );

+

+      for( size_t i = 0; i < n; ++i )

+      {

+        alc.construct( &alc.ptr[i], t );

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKSmallVectorImpl( const MVKSmallVectorImpl &a )

+  {

+    const size_t n = a.size();

+

+    if( n > 0 )

+    {

+      alc.allocate( n );

+

+      for( size_t i = 0; i < n; ++i )

+      {

+        alc.construct( &alc.ptr[i], a.alc.ptr[i] );

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  template<typename U>

+  MVKSmallVectorImpl( const U &a )

+  {

+    const size_t n = a.size();

+

+    if( n > 0 )

+    {

+      alc.allocate( n );

+

+      for( size_t i = 0; i < n; ++i )

+      {

+        alc.construct( &alc.ptr[i], a[i] );

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKSmallVectorImpl( MVKSmallVectorImpl &&a ) : alc{ std::move( a.alc ) }

+  {

+  }

+

+  MVKSmallVectorImpl( std::initializer_list<Type> vector )

+  {

+    if( vector.size() > capacity() )

+    {

+      vector_Allocate( vector.size() );

+    }

+

+    // std::initializer_list does not yet support std::move, we use it anyway but it has no effect

+    for( auto &&element : vector )

+    {

+      alc.construct( &alc.ptr[alc.num_elements_used], std::move( element ) );

+      ++alc.num_elements_used;

+    }

+  }

+

+  ~MVKSmallVectorImpl()

+  {

+  }

+

+  template<typename U>

+  MVKSmallVectorImpl& operator=( const U &a )

+  {

+    static_assert( std::is_base_of<MVKSmallVectorImpl<Type>, U>::value, "argument is not of type MVKSmallVectorImpl" );

+

+    if( this != reinterpret_cast<const MVKSmallVectorImpl<Type>*>( &a ) )

+    {

+      const auto n = a.size();

+

+      if( alc.num_elements_used == n )

+      {

+        for( size_t i = 0; i < n; ++i )

+        {

+          alc.ptr[i] = a.alc.ptr[i];

+        }

+      }

+      else

+      {

+        if( n > capacity() )

+        {

+          vector_ReAllocate( n );

+        }

+        else

+        {

+          alc.template destruct_all<Type>();

+        }

+

+        for( size_t i = 0; i < n; ++i )

+        {

+          alc.construct( &alc.ptr[i], a[i] );

+        }

+

+        alc.num_elements_used = n;

+      }

+    }

+

+    return *this;

+  }

+

+  MVKSmallVectorImpl& operator=( MVKSmallVectorImpl &&a )

+  {

+    alc.swap( a.alc );

+    return *this;

+  }

+

+  bool operator==( const MVKSmallVectorImpl &a ) const

+  {

+    if( alc.num_elements_used != a.alc.num_elements_used )

+      return false;

+    for( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if( alc[i] != a.alc[i] )

+        return false;

+    }

+    return true;

+  }

+

+  bool operator!=( const MVKSmallVectorImpl &a ) const

+  {

+    if( alc.num_elements_used != a.alc.num_elements_used )

+      return true;

+    for( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if( alc.ptr[i] != a.alc[i] )

+        return true;

+    }

+    return false;

+  }

+

+  void swap( MVKSmallVectorImpl &a )

+  {

+    alc.swap( a.alc );

+  }

+

+  iterator begin() const { return iterator( 0, *this ); }

+  iterator end()   const { return iterator( alc.num_elements_used, *this ); }

+

+  const MVKArrayRef<Type> contents() const { return MVKArrayRef<Type>(data(), size()); }

+        MVKArrayRef<Type> contents()       { return MVKArrayRef<Type>(data(), size()); }

+

+  const Type &operator[]( const size_t i ) const { return alc[i]; }

+        Type &operator[]( const size_t i )        { return alc[i]; }

+  const Type &at( const size_t i )         const { return alc[i]; }

+        Type &at( const size_t i )                { return alc[i]; }

+  const Type &front()                      const  { return alc[0]; }

+        Type &front()                             { return alc[0]; }

+  const Type &back()                       const  { return alc[alc.num_elements_used - 1]; }

+        Type &back()                              { return alc[alc.num_elements_used - 1]; }

+  const Type *data()                       const  { return alc.ptr; }

+        Type *data()                              { return alc.ptr; }

+

+  size_t      size()                       const { return alc.num_elements_used; }

+  bool        empty()                      const { return alc.num_elements_used == 0; }

+  size_t      capacity()                   const { return alc.get_capacity(); }

+

+  void pop_back()

+  {

+    if( alc.num_elements_used > 0 )

+    {

+      --alc.num_elements_used;

+      alc.destruct( &alc.ptr[alc.num_elements_used] );

+    }

+  }

+

+  void clear()

+  {

+    alc.template destruct_all<Type>();

+  }

+

+  void reset()

+  {

+    alc.deallocate();

+  }

+

+  void reserve( const size_t new_size )

+  {

+    if( new_size > capacity() )

+    {

+      vector_ReAllocate( new_size );

+    }

+  }

+

+  void assign( const size_t new_size, const Type &t )

+  {

+    if( new_size <= capacity() )

+    {

+      clear();

+    }

+    else

+    {

+      vector_Allocate( new_size );

+    }

+

+    for( size_t i = 0; i < new_size; ++i )

+    {

+      alc.construct( &alc.ptr[i], t );

+    }

+

+    alc.num_elements_used = new_size;

+  }

+

+  template <class InputIterator>

+  void assign( InputIterator first, InputIterator last )

+  {

+    clear();

+

+    while( first != last )

+    {

+      emplace_back( *first );

+      ++first;

+    }

+  }

+

+  void resize( const size_t new_size, const Type t = { } )

+  {

+    if( new_size == alc.num_elements_used )

+    {

+      return;

+    }

+

+    if( new_size == 0 )

+    {

+      clear();

+      return;

+    }

+

+    if( new_size > alc.num_elements_used )

+    {

+      if( new_size > capacity() )

+      {

+        vector_ReAllocate( new_size );

+      }

+

+      while( alc.num_elements_used < new_size )

+      {

+        alc.construct( &alc.ptr[alc.num_elements_used], t );

+        ++alc.num_elements_used;

+      }

+    }

+    else

+    {

+      //if constexpr( !std::is_trivially_destructible<Type>::value )

+      {

+        while( alc.num_elements_used > new_size )

+        {

+          --alc.num_elements_used;

+          alc.destruct( &alc.ptr[alc.num_elements_used] );

+        }

+      }

+      //else

+      //{

+      //  alc.num_elements_used = new_size;

+      //}

+    }

+  }

+

+  // trims the capacity of the slist to the number of alc.ptr

+  void shrink_to_fit()

+  {

+    alc.shrink_to_fit();

+  }

+

+  void erase( const iterator it )

+  {

+    if( it.is_valid() )

+    {

+      --alc.num_elements_used;

+

+      for( size_t i = it.get_position(); i < alc.num_elements_used; ++i )

+      {

+        alc.ptr[i] = std::move( alc.ptr[i + 1] );

+      }

+

+      // this is required for types with a destructor

+      alc.destruct( &alc.ptr[alc.num_elements_used] );

+    }

+  }

+

+  void erase( const iterator first, const iterator last )

+  {

+    if( first.is_valid() )

+    {

+      size_t last_pos = last.is_valid() ? last.get_position() : size();

+      size_t n = last_pos - first.get_position();

+      alc.num_elements_used -= n;

+

+      for( size_t i = first.get_position(), e = last_pos; i < alc.num_elements_used && e < alc.num_elements_used + n; ++i, ++e )

+      {

+        alc.ptr[i] = std::move( alc.ptr[e] );

+      }

+

+      // this is required for types with a destructor

+      for( size_t i = alc.num_elements_used; i < alc.num_elements_used + n; ++i )

+      {

+        alc.destruct( &alc.ptr[i] );

+      }

+    }

+  }

+

+  // adds t before it and automatically resizes vector if necessary

+  void insert( const iterator it, Type t )

+  {

+    if( !it.is_valid() || alc.num_elements_used == 0 )

+    {

+      push_back( std::move( t ) );

+    }

+    else

+    {

+      if( alc.num_elements_used == capacity() )

+        vector_ReAllocate( vector_GetNextCapacity() );

+

+      // move construct last element

+      alc.construct( &alc.ptr[alc.num_elements_used], std::move( alc.ptr[alc.num_elements_used - 1] ) );

+

+      // move the remaining elements

+      const size_t it_position = it.get_position();

+      for( size_t i = alc.num_elements_used - 1; i > it_position; --i )

+      {

+        alc.ptr[i] = std::move( alc.ptr[i - 1] );

+      }

+

+      alc.ptr[it_position] = std::move( t );

+      ++alc.num_elements_used;

+    }

+  }

+

+  void push_back( const Type &t )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], t );

+    ++alc.num_elements_used;

+  }

+

+  void push_back( Type &&t )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Type>( t ) );

+    ++alc.num_elements_used;

+  }

+

+  template<class... Args>

+  Type &emplace_back( Args&&... args )

+  {

+    if( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Args>( args )... );

+    ++alc.num_elements_used;

+

+    return alc.ptr[alc.num_elements_used - 1];

+  }

+};

+

+// specialization for pointer types

+template<typename Type, typename Allocator>

+class MVKSmallVectorImpl<Type*, Allocator>

+{

+

+  Allocator  alc;

+

+public:

+  class iterator : public std::iterator<std::random_access_iterator_tag, Type*>

+  {

+    MVKSmallVectorImpl *vector;

+    size_t         index;

+

+  public:

+    typedef typename std::iterator_traits<iterator>::difference_type diff_type;

+

+    iterator() : vector{ nullptr }, index{ 0 } { }

+    iterator( const size_t _index, MVKSmallVectorImpl &_vector ) : vector{ &_vector }, index{ _index } { }

+

+    iterator &operator=( const iterator &it )

+    {

+      vector = it.vector;

+      index = it.index;

+      return *this;

+    }

+

+    Type *&operator*() { return vector->alc[index]; }

+

+    bool operator==( const iterator &it ) const { return vector == it.vector && index == it.index; }

+    bool operator!=( const iterator &it ) const { return vector != it.vector || index != it.index; }

+

+    iterator& operator++()      { ++index; return *this; }

+    iterator  operator++( int ) { auto t = *this; ++index; return t; }

+    iterator& operator--()      {                 --index; return *this; }

+    iterator  operator--( int ) { auto t = *this; --index; return t; }

+

+    iterator operator+ (const diff_type n)   { return iterator( index + n, *vector ); }

+    iterator& operator+= (const diff_type n) { index += n; return *this; }

+    iterator operator- (const diff_type n)   { return iterator( index - n, *vector ); }

+    iterator& operator-= (const diff_type n) { index -= n; return *this; }

+

+    diff_type operator- (const iterator& it) { return index - it.index; }

+

+    bool operator< (const iterator& it)  { return index < it.index; }

+    bool operator<= (const iterator& it) { return index <= it.index; }

+    bool operator> (const iterator& it)  { return index > it.index; }

+    bool operator>= (const iterator& it) { return index >= it.index; }

+

+    const Type &operator[]( const diff_type i ) const { return vector->alc.ptr[index + i]; }

+    Type &operator[]( const diff_type i )             { return vector->alc.ptr[index + i]; }

+

+    bool   is_valid()     const { return index < vector->alc.size(); }

+    size_t get_position() const { return index; }

+  };

+

+private:

+  // this is the growth strategy -> adjust to your needs

+  size_t vector_GetNextCapacity() const

+  {

+    constexpr auto ELEMENTS_FOR_64_BYTES = 64 / sizeof( Type* );

+    constexpr auto MINIMUM_CAPACITY = ELEMENTS_FOR_64_BYTES > 4 ? ELEMENTS_FOR_64_BYTES : 4;

+    const auto current_capacity = capacity();

+    return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;

+  }

+

+  void vector_Allocate( const size_t s )

+  {

+    const auto new_reserved_size = s > size() ? s : size();

+

+    alc.allocate( new_reserved_size );

+  }

+

+  void vector_ReAllocate( const size_t s )

+  {

+    alc.re_allocate( s );

+  }

+

+public:

+  MVKSmallVectorImpl()

+  {

+  }

+

+  MVKSmallVectorImpl( const size_t n, const Type *t )

+  {

+    if ( n > 0 )

+    {

+      alc.allocate( n );

+

+      for ( size_t i = 0; i < n; ++i )

+      {

+        alc.ptr[i] = t;

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKSmallVectorImpl( const MVKSmallVectorImpl &a )

+  {

+    const size_t n = a.size();

+

+    if ( n > 0 )

+    {

+      alc.allocate( n );

+

+      for ( size_t i = 0; i < n; ++i )

+      {

+        alc.ptr[i] = a.alc.ptr[i];

+      }

+

+      alc.num_elements_used = n;

+    }

+  }

+

+  MVKSmallVectorImpl( MVKSmallVectorImpl &&a ) : alc{ std::move( a.alc ) }

+  {

+  }

+

+  MVKSmallVectorImpl( std::initializer_list<Type*> vector )

+  {

+    if ( vector.size() > capacity() )

+    {

+      vector_Allocate( vector.size() );

+    }

+

+    // std::initializer_list does not yet support std::move, we use it anyway but it has no effect

+    for ( auto element : vector )

+    {

+      alc.ptr[alc.num_elements_used] = element;

+      ++alc.num_elements_used;

+    }

+  }

+

+  ~MVKSmallVectorImpl()

+  {

+  }

+

+  template<typename U>

+  MVKSmallVectorImpl& operator=( const U &a )

+  {

+    static_assert( std::is_base_of<MVKSmallVectorImpl<U>, U>::value, "argument is not of type MVKSmallVectorImpl" );

+

+    if ( this != reinterpret_cast< const MVKSmallVectorImpl<Type>* >( &a ) )

+    {

+      const auto n = a.size();

+

+      if ( alc.num_elements_used == n )

+      {

+        for ( size_t i = 0; i < n; ++i )

+        {

+          alc.ptr[i] = a.alc.ptr[i];

+        }

+      }

+      else

+      {

+        if ( n > capacity() )

+        {

+          vector_ReAllocate( n );

+        }

+

+        for ( size_t i = 0; i < n; ++i )

+        {

+          alc.ptr[i] = a[i];

+        }

+

+        alc.num_elements_used = n;

+      }

+    }

+

+    return *this;

+  }

+

+  MVKSmallVectorImpl& operator=( MVKSmallVectorImpl &&a )

+  {

+    alc.swap( a.alc );

+    return *this;

+  }

+

+  bool operator==( const MVKSmallVectorImpl &a ) const

+  {

+    if ( alc.num_elements_used != a.alc.num_elements_used )

+      return false;

+    for ( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if ( alc[i] != a.alc[i] )

+        return false;

+    }

+    return true;

+  }

+

+  bool operator!=( const MVKSmallVectorImpl &a ) const

+  {

+    if ( alc.num_elements_used != a.alc.num_elements_used )

+      return true;

+    for ( size_t i = 0; i < alc.num_elements_used; ++i )

+    {

+      if ( alc.ptr[i] != a.alc[i] )

+        return true;

+    }

+    return false;

+  }

+

+  void swap( MVKSmallVectorImpl &a )

+  {

+    alc.swap( a.alc );

+  }

+

+  iterator begin()        { return iterator( 0, *this ); }

+  iterator end()          { return iterator( alc.num_elements_used, *this ); }

+

+  const MVKArrayRef<Type*> contents() const { return MVKArrayRef<Type*>(data(), size()); }

+        MVKArrayRef<Type*> contents()       { return MVKArrayRef<Type*>(data(), size()); }

+

+  const Type * const  at( const size_t i )         const { return alc[i]; }

+        Type *       &at( const size_t i )               { return alc[i]; }

+  const Type * const  operator[]( const size_t i ) const { return alc[i]; }

+        Type *       &operator[]( const size_t i )       { return alc[i]; }

+  const Type * const  front()                      const { return alc[0]; }

+        Type *       &front()                            { return alc[0]; }

+  const Type * const  back()                       const { return alc[alc.num_elements_used - 1]; }

+        Type *       &back()                             { return alc[alc.num_elements_used - 1]; }

+  const Type * const *data()                       const { return alc.ptr; }

+        Type *       *data()                             { return alc.ptr; }

+

+  size_t   size()                                  const { return alc.num_elements_used; }

+  bool     empty()                                 const { return alc.num_elements_used == 0; }

+  size_t   capacity()                              const { return alc.get_capacity(); }

+

+  void pop_back()

+  {

+    if ( alc.num_elements_used > 0 )

+    {

+      --alc.num_elements_used;

+    }

+  }

+

+  void clear()

+  {

+    alc.num_elements_used = 0;

+  }

+

+  void reset()

+  {

+    alc.deallocate();

+  }

+

+  void reserve( const size_t new_size )

+  {

+    if ( new_size > capacity() )

+    {

+      vector_ReAllocate( new_size );

+    }

+  }

+

+  void assign( const size_t new_size, const Type *t )

+  {

+    if ( new_size <= capacity() )

+    {

+      clear();

+    }

+    else

+    {

+      vector_Allocate( new_size );

+    }

+

+    for ( size_t i = 0; i < new_size; ++i )

+    {

+      alc.ptr[i] = const_cast< Type* >( t );

+    }

+

+    alc.num_elements_used = new_size;

+  }

+

+  void resize( const size_t new_size, const Type *t = nullptr )

+  {

+    if ( new_size == alc.num_elements_used )

+    {

+      return;

+    }

+

+    if ( new_size == 0 )

+    {

+      clear();

+      return;

+    }

+

+    if ( new_size > alc.num_elements_used )

+    {

+      if ( new_size > capacity() )

+      {

+        vector_ReAllocate( new_size );

+      }

+

+      while ( alc.num_elements_used < new_size )

+      {

+        alc.ptr[alc.num_elements_used] = const_cast< Type* >( t );

+        ++alc.num_elements_used;

+      }

+    }

+    else

+    {

+      alc.num_elements_used = new_size;

+    }

+  }

+

+  // trims the capacity of the MVKSmallVectorImpl to the number of used elements

+  void shrink_to_fit()

+  {

+    alc.shrink_to_fit();

+  }

+

+  void erase( const iterator it )

+  {

+    if ( it.is_valid() )

+    {

+      --alc.num_elements_used;

+

+      for ( size_t i = it.get_position(); i < alc.num_elements_used; ++i )

+      {

+        alc.ptr[i] = alc.ptr[i + 1];

+      }

+    }

+  }

+

+  void erase( const iterator first, const iterator last )

+  {

+    if( first.is_valid() )

+    {

+      size_t last_pos = last.is_valid() ? last.get_position() : size();

+      size_t n = last_pos - first.get_position();

+      alc.num_elements_used -= n;

+

+      for( size_t i = first.get_position(), e = last_pos; i < alc.num_elements_used && e < alc.num_elements_used + n; ++i, ++e )

+      {

+        alc.ptr[i] = alc.ptr[e];

+      }

+    }

+  }

+

+  // adds t before position it and automatically resizes vector if necessary

+  void insert( const iterator it, const Type *t )

+  {

+    if ( !it.is_valid() || alc.num_elements_used == 0 )

+    {

+      push_back( t );

+    }

+    else

+    {

+      if ( alc.num_elements_used == capacity() )

+        vector_ReAllocate( vector_GetNextCapacity() );

+

+      // move the remaining elements

+      const size_t it_position = it.get_position();

+      for ( size_t i = alc.num_elements_used; i > it_position; --i )

+      {

+        alc.ptr[i] = alc.ptr[i - 1];

+      }

+

+      alc.ptr[it_position] = const_cast< Type* >( t );

+      ++alc.num_elements_used;

+    }

+  }

+

+  void push_back( const Type *t )

+  {

+    if ( alc.num_elements_used == capacity() )

+      vector_ReAllocate( vector_GetNextCapacity() );

+

+    alc.ptr[alc.num_elements_used] = const_cast< Type* >( t );

+    ++alc.num_elements_used;

+  }

+};

+

+template<typename Type, size_t N = 0>

+using MVKSmallVector = MVKSmallVectorImpl<Type, mvk_smallvector_allocator<Type, N>>;

+

+#endif

+

+

diff --git a/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h
new file mode 100755
index 0000000..5bab836
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h
@@ -0,0 +1,380 @@
+/*

+ * MVKSmallVectorAllocator.h

+ *

+ * Copyright (c) 2012-2020 Dr. Torsten Hans (hans@ipacs.de)

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ * 

+ *     http://www.apache.org/licenses/LICENSE-2.0

+ * 

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#pragma once

+

+#include <new>

+#include <type_traits>

+

+

+namespace mvk_smallvector_memory_allocator

+{

+  inline char *alloc( const size_t num_bytes )

+  {

+    return new char[num_bytes];

+  }

+

+  inline void free( void *ptr )

+  {

+    delete[] (char*)ptr;

+  }

+};

+

+

+//////////////////////////////////////////////////////////////////////////////////////////

+//

+// mvk_smallvector_allocator -> malloc based MVKSmallVector allocator with preallocated storage

+//

+//////////////////////////////////////////////////////////////////////////////////////////

+template <typename T, int M>

+class mvk_smallvector_allocator final

+{

+public:

+	typedef T value_type;

+	T      *ptr;

+	size_t  num_elements_used;

+

+private:

+

+	// Once dynamic allocation is in use, the preallocated content memory space will

+	// be re-purposed to hold the capacity count. If the content type is small, ensure

+	// preallocated memory is large enough to hold the capacity count, and increase

+	// the number of preallocated elements accordintly, to make use of this memory.

+	// In addition, increase the number of pre-allocated elements to fill any space created

+	// by the alignment of this structure, to maximize the use of the preallocated memory.

+	static constexpr size_t CAP_CNT_SIZE = sizeof( size_t );

+	static constexpr size_t ALIGN_CNT = CAP_CNT_SIZE / sizeof( T );

+	static constexpr size_t ALIGN_MASK = (ALIGN_CNT > 0) ? (ALIGN_CNT - 1) : 0;

+

+	static constexpr size_t MIN_CNT = M > ALIGN_CNT ? M : ALIGN_CNT;

+	static constexpr size_t N = (MIN_CNT + ALIGN_MASK) & ~ALIGN_MASK;

+

+	static constexpr size_t MIN_STACK_SIZE = ( N * sizeof( T ) );

+	static constexpr size_t STACK_SIZE = MIN_STACK_SIZE > CAP_CNT_SIZE ? MIN_STACK_SIZE : CAP_CNT_SIZE;

+	alignas( alignof( T ) ) unsigned char elements_stack[ STACK_SIZE ];

+

+  void set_num_elements_reserved( const size_t num_elements_reserved )

+  {

+    *reinterpret_cast<size_t*>( &elements_stack[0] ) = num_elements_reserved;

+  }

+

+public:

+  const T &operator[]( const size_t i ) const { return ptr[i]; }

+  T       &operator[]( const size_t i )       { return ptr[i]; }

+

+  size_t size() const { return num_elements_used; }

+

+  //

+  // faster element construction and destruction using type traits

+  //

+  template<class S, class... Args> typename std::enable_if< !std::is_trivially_constructible<S, Args...>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    new ( _ptr ) S( std::forward<Args>( _args )... );

+  }

+

+  template<class S, class... Args> typename std::enable_if< std::is_trivially_constructible<S, Args...>::value >::type

+    construct( S *_ptr, Args&&... _args )

+  {

+    *_ptr = S( std::forward<Args>( _args )... );

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+    _ptr->~S();

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct( S *_ptr )

+  {

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      ptr[i].~S();

+    }

+

+    num_elements_used = 0;

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    destruct_all()

+  {

+    num_elements_used = 0;

+  }

+

+  template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type

+    swap_stack( mvk_smallvector_allocator &a )

+  {

+    T stack_copy[N];

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &stack_copy[i], std::move( S::ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    for( size_t i = 0; i < a.num_elements_used; ++i )

+    {

+      construct( &ptr[i], std::move( a.ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &a.ptr[i], std::move( stack_copy[i] ) );

+      destruct( &stack_copy[i] );

+    }

+  }

+

+  template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type

+    swap_stack( mvk_smallvector_allocator &a )

+  {

+    for( int i = 0; i < STACK_SIZE; ++i )

+    {

+      const auto v = elements_stack[i];

+      elements_stack[i] = a.elements_stack[i];

+      a.elements_stack[i] = v;

+    }

+  }

+

+public:

+  mvk_smallvector_allocator() : ptr(reinterpret_cast<T*>( &elements_stack[0] )), num_elements_used(0)

+  {

+  }

+

+  mvk_smallvector_allocator( mvk_smallvector_allocator &&a )

+  {

+    // is a heap based -> steal ptr from a

+    if( !a.get_data_on_stack() )

+    {

+      ptr = a.ptr;

+      set_num_elements_reserved( a.get_capacity() );

+

+      a.ptr = a.get_default_ptr();

+    }

+    else

+    {

+      ptr = get_default_ptr();

+      for( size_t i = 0; i < a.num_elements_used; ++i )

+      {

+        construct( &ptr[i], std::move( a.ptr[i] ) );

+        destruct( &a.ptr[i] );

+      }

+    }

+

+	num_elements_used = a.num_elements_used;

+    a.num_elements_used = 0;

+  }

+

+  ~mvk_smallvector_allocator()

+  {

+    deallocate();

+  }

+

+  size_t get_capacity() const

+  {

+    return get_data_on_stack() ? N : *reinterpret_cast<const size_t*>( &elements_stack[0] );

+  }

+

+  constexpr T *get_default_ptr() const

+  {

+    return reinterpret_cast< T* >( const_cast< unsigned char * >( &elements_stack[0] ) );

+  }

+

+  bool get_data_on_stack() const

+  {

+    return ptr == get_default_ptr();

+  }

+

+  void swap( mvk_smallvector_allocator &a )

+  {

+    // both allocators on heap -> easy case

+    if( !get_data_on_stack() && !a.get_data_on_stack() )

+    {

+      auto copy_ptr = ptr;

+      auto copy_num_elements_reserved = get_capacity();

+      ptr = a.ptr;

+      set_num_elements_reserved( a.get_capacity() );

+      a.ptr = copy_ptr;

+      a.set_num_elements_reserved( copy_num_elements_reserved );

+    }

+    // both allocators on stack -> just switch the stack contents

+    else if( get_data_on_stack() && a.get_data_on_stack() )

+    {

+      swap_stack<T>( a );

+    }

+    else if( get_data_on_stack() && !a.get_data_on_stack() )

+    {

+      auto copy_ptr = a.ptr;

+      auto copy_num_elements_reserved = a.get_capacity();

+

+      a.ptr = a.get_default_ptr();

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &a.ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      ptr = copy_ptr;

+      set_num_elements_reserved( copy_num_elements_reserved );

+    }

+    else if( !get_data_on_stack() && a.get_data_on_stack() )

+    {

+      auto copy_ptr = ptr;

+      auto copy_num_elements_reserved = get_capacity();

+

+      ptr = get_default_ptr();

+      for( size_t i = 0; i < a.num_elements_used; ++i )

+      {

+        construct( &ptr[i], std::move( a.ptr[i] ) );

+        destruct( &a.ptr[i] );

+      }

+

+      a.ptr = copy_ptr;

+      a.set_num_elements_reserved( copy_num_elements_reserved );

+    }

+

+    auto copy_num_elements_used = num_elements_used;

+    num_elements_used = a.num_elements_used;

+    a.num_elements_used = copy_num_elements_used;

+  }

+

+  //

+  // allocates rounded up to the defined alignment the number of bytes / if the system cannot allocate the specified amount of memory then a null block is returned

+  //

+  void allocate( const size_t num_elements_to_reserve )

+  {

+    deallocate();

+

+    // check if enough memory on stack space is left

+    if( num_elements_to_reserve <= N )

+    {

+      return;

+    }

+

+    ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+    num_elements_used = 0;

+    set_num_elements_reserved( num_elements_to_reserve );

+  }

+

+  //template<class S> typename std::enable_if< !std::is_trivially_copyable<S>::value >::type

+  void _re_allocate( const size_t num_elements_to_reserve )

+  {

+    auto *new_ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );

+

+    for( size_t i = 0; i < num_elements_used; ++i )

+    {

+      construct( &new_ptr[i], std::move( ptr[i] ) );

+      destruct( &ptr[i] );

+    }

+

+    if( ptr != get_default_ptr() )

+    {

+      mvk_smallvector_memory_allocator::free( ptr );

+    }

+

+    ptr = new_ptr;

+    set_num_elements_reserved( num_elements_to_reserve );

+  }

+

+  //template<class S> typename std::enable_if< std::is_trivially_copyable<S>::value >::type

+  //  _re_allocate( const size_t num_elements_to_reserve )

+  //{

+  //  const bool data_is_on_stack = get_data_on_stack();

+  //

+  //  auto *new_ptr = reinterpret_cast< S* >( mvk_smallvector_memory_allocator::tm_memrealloc( data_is_on_stack ? nullptr : ptr, num_elements_to_reserve * sizeof( S ) ) );

+  //  if( data_is_on_stack )

+  //  {

+  //    for( int i = 0; i < N; ++i )

+  //    {

+  //      new_ptr[i] = ptr[i];

+  //    }

+  //  }

+  //

+  //  ptr = new_ptr;

+  //  set_num_elements_reserved( num_elements_to_reserve );

+  //}

+

+  void re_allocate( const size_t num_elements_to_reserve )

+  {

+    //TM_ASSERT( num_elements_to_reserve > get_capacity() );

+

+    if( num_elements_to_reserve > N )

+    {

+      _re_allocate( num_elements_to_reserve );

+    }

+  }

+

+  void shrink_to_fit()

+  {

+    // nothing to do if data is on stack already

+    if( get_data_on_stack() )

+      return;

+

+    // move elements to stack space

+    if( num_elements_used <= N )

+    {

+      //const auto num_elements_reserved = get_capacity();

+

+      auto *stack_ptr = get_default_ptr();

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &stack_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      mvk_smallvector_memory_allocator::free( ptr );

+

+      ptr = stack_ptr;

+    }

+    else

+    {

+      auto *new_ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_used * sizeof( T ) ) );

+

+      for( size_t i = 0; i < num_elements_used; ++i )

+      {

+        construct( &new_ptr[i], std::move( ptr[i] ) );

+        destruct( &ptr[i] );

+      }

+

+      mvk_smallvector_memory_allocator::free( ptr );

+

+      ptr = new_ptr;

+      set_num_elements_reserved( num_elements_used );

+    }

+  }

+

+  void deallocate()

+  {

+    destruct_all<T>();

+

+    if( !get_data_on_stack() )

+    {

+      mvk_smallvector_memory_allocator::free( ptr );

+    }

+

+    ptr = get_default_ptr();

+    num_elements_used = 0;

+  }

+};

+

diff --git a/MoltenVK/MoltenVK/Utility/MVKVector.h b/MoltenVK/MoltenVK/Utility/MVKVector.h
index c11137a..60a4871 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVector.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVector.h
@@ -62,6 +62,7 @@
 // use MVKVector.

 //

 #include "MVKVectorAllocator.h"

+#include "MVKFoundation.h"

 #include <type_traits>

 #include <initializer_list>

 #include <utility>

@@ -106,6 +107,9 @@
   iterator begin() const { return iterator( 0,               *this ); }

   iterator end()   const { return iterator( alc_ptr->size(), *this ); }

 

+  const MVKArrayRef<Type> contents() const { return MVKArrayRef<Type>(data(), size()); }

+        MVKArrayRef<Type> contents()       { return MVKArrayRef<Type>(data(), size()); }

+

   virtual const Type &operator[]( const size_t i ) const                  = 0;

   virtual       Type &operator[]( const size_t i )                        = 0;

   virtual const Type &at( const size_t i ) const                          = 0;

@@ -171,6 +175,9 @@
   iterator begin() const { return iterator( 0,               *this ); }

   iterator end()   const { return iterator( alc_ptr->size(), *this ); }

 

+  const MVKArrayRef<Type*> contents() const { return MVKArrayRef<Type*>(data(), size()); }

+        MVKArrayRef<Type*> contents()       { return MVKArrayRef<Type*>(data(), size()); }

+

   virtual const Type * const  operator[]( const size_t i ) const             = 0;

   virtual       Type *       &operator[]( const size_t i )                   = 0;

   virtual const Type * const  at( const size_t i ) const                     = 0;

diff --git a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
index edad56c..38623c0 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
@@ -242,7 +242,7 @@
   //size_t  num_elements_reserved; // uhh, num_elements_reserved is mapped onto the stack elements, let the fun begin

   alignas( alignof( T ) ) unsigned char   elements_stack[N * sizeof( T )];

 

-  static_assert( N * sizeof( T ) >= sizeof( size_t ), "Bummer, nasty optimization doesn't work" );

+  static_assert( N * sizeof( T ) >= sizeof( size_t ), "Initial static allocation must be at least 8 bytes. Increase the count of pre-allocated elements." );

 

   void set_num_elements_reserved( const size_t num_elements_reserved )

   {

diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index e3407ec..8acd4ae 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -452,9 +452,10 @@
 MTLTriangleFillMode mvkMTLTriangleFillModeFromVkPolygonModeInObj(VkPolygonMode vkFillMode, MVKBaseObject* mvkObj) {
 	switch (vkFillMode) {
 		case VK_POLYGON_MODE_FILL:
-		case VK_POLYGON_MODE_POINT:
 			return MTLTriangleFillModeFill;
 
+		case VK_POLYGON_MODE_POINT:
+			MVKBaseObject::reportError(mvkObj, VK_ERROR_FORMAT_NOT_SUPPORTED, "VkPolygonMode value VK_POLYGON_MODE_POINT is not supported for render pipelines.");
 		case VK_POLYGON_MODE_LINE:
 			return MTLTriangleFillModeLines;
 
diff --git a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm b/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
index bccb8c1..3976621 100644
--- a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
@@ -115,7 +115,7 @@
     id<MTLTexture>                              mtlTexture) {
 
     MVKImage* mvkImg = (MVKImage*)image;
-    return mvkImg->setMTLTexture(mtlTexture);
+    return mvkImg->setMTLTexture(0, mtlTexture);
 }
 
 MVK_PUBLIC_SYMBOL void vkGetMTLTextureMVK(
@@ -123,7 +123,7 @@
     id<MTLTexture>*                             pMTLTexture) {
 
     MVKImage* mvkImg = (MVKImage*)image;
-    *pMTLTexture = mvkImg->getMTLTexture();
+    *pMTLTexture = mvkImg->getMTLTexture(0);
 }
 
 MVK_PUBLIC_SYMBOL void vkGetMTLBufferMVK(
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index 5b28ae3..b84a88c 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -117,14 +117,45 @@
 // Create and configure a command of particular type.
 // If the command is configured correctly, add it to the buffer,
 // otherwise indicate the configuration error to the command buffer.
-#define MVKAddCmd(cmdType, vkCmdBuff, ...)  										\
-	MVKCommandBuffer* cmdBuff = MVKCommandBuffer::getMVKCommandBuffer(vkCmdBuff);	\
+#define MVKAddCmd(cmdType, vkCmdBuff, ...)  													\
+	MVKCommandBuffer* cmdBuff = MVKCommandBuffer::getMVKCommandBuffer(vkCmdBuff);				\
 	MVKCmd ##cmdType* cmd = cmdBuff->getCommandPool()->_cmd ##cmdType ##Pool.acquireObject();	\
-	VkResult cmdRslt = cmd->setContent(cmdBuff, ##__VA_ARGS__);						\
-	if(cmdRslt == VK_SUCCESS) {														\
-		cmdBuff->addCommand(cmd);													\
-	} else {																		\
-		cmdBuff->setConfigurationResult(cmdRslt);									\
+	VkResult cmdRslt = cmd->setContent(cmdBuff, ##__VA_ARGS__);									\
+	if (cmdRslt == VK_SUCCESS) {																\
+		cmdBuff->addCommand(cmd);																\
+	} else {																					\
+		cmdBuff->setConfigurationResult(cmdRslt);												\
+	}
+
+// Add one of two commands, based on comparing a command parameter against a threshold value
+#define MVKAddCmdFromThreshold(baseCmdType, value, threshold, vkCmdBuff, ...)					\
+	if (value <= threshold) {																	\
+		MVKAddCmd(baseCmdType ##threshold, vkCmdBuff, ##__VA_ARGS__);							\
+	} else {																					\
+		MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__);								\
+	}
+
+// Add one of three commands, based on comparing a command parameter against two threshold values
+#define MVKAddCmdFrom2Thresholds(baseCmdType, value, threshold1, threshold2, vkCmdBuff, ...)	\
+	if (value <= threshold1) {																	\
+		MVKAddCmd(baseCmdType ##threshold1, vkCmdBuff, ##__VA_ARGS__);							\
+	} else if (value <= threshold2) {															\
+		MVKAddCmd(baseCmdType ##threshold2, vkCmdBuff, ##__VA_ARGS__);							\
+	} else {																					\
+		MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__);								\
+	}
+
+
+// Add one of four commands, based on comparing a command parameter against two threshold values
+#define MVKAddCmdFrom3Thresholds(baseCmdType, value, threshold1, threshold2, threshold3, vkCmdBuff, ...)	\
+	if (value <= threshold1) {																				\
+		MVKAddCmd(baseCmdType ##threshold1, vkCmdBuff, ##__VA_ARGS__);										\
+	} else if (value <= threshold2) {																		\
+		MVKAddCmd(baseCmdType ##threshold2, vkCmdBuff, ##__VA_ARGS__);										\
+	} else if (value <= threshold3) {																		\
+		MVKAddCmd(baseCmdType ##threshold3, vkCmdBuff, ##__VA_ARGS__);										\
+	} else {																								\
+		MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__);											\
 	}
 
 
@@ -149,8 +180,7 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !instance ) { return; }
-	MVKInstance::getMVKInstance(instance)->destroy();
+	if (instance) { MVKInstance::getMVKInstance(instance)->destroy(); }
 	MVKTraceVulkanCallEnd();
 }
 
@@ -230,7 +260,7 @@
 
 	MVKTraceVulkanCallStart();
 	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-	mvkPD->getPhysicalDeviceMemoryProperties(pMemoryProperties);
+	mvkPD->getMemoryProperties(pMemoryProperties);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -287,8 +317,7 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !device ) { return; }
-	MVKDevice::getMVKDevice(device)->destroy();
+	if (device) { MVKDevice::getMVKDevice(device)->destroy(); }
 	MVKTraceVulkanCallEnd();
 }
 
@@ -345,10 +374,8 @@
     VkQueue*                                    pQueue) {
 
 	MVKTraceVulkanCallStart();
-	if (pQueue) {
-		MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
-		*pQueue = mvkDev->getQueue(queueFamilyIndex, queueIndex)->getVkQueue();
-	}
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	*pQueue = mvkDev->getQueue(queueFamilyIndex, queueIndex)->getVkQueue();
 	MVKTraceVulkanCallEnd();
 }
 
@@ -406,7 +433,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !mem ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->freeMemory((MVKDeviceMemory*)mem, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -472,8 +498,6 @@
     VkDeviceSize*                               pCommittedMemoryInBytes) {
 
 	MVKTraceVulkanCallStart();
-    if ( !pCommittedMemoryInBytes ) { return; }
-
     MVKDeviceMemory* mvkMem = (MVKDeviceMemory*)memory;
     *pCommittedMemoryInBytes = mvkMem->getDeviceMemoryCommitment();
 	MVKTraceVulkanCallEnd();
@@ -502,7 +526,7 @@
 	MVKTraceVulkanCallStart();
 	MVKImage* mvkImg = (MVKImage*)image;
 	MVKDeviceMemory* mvkMem = (MVKDeviceMemory*)mem;
-	VkResult rslt = mvkImg->bindDeviceMemory(mvkMem, memOffset);
+	VkResult rslt = mvkImg->bindDeviceMemory(mvkMem, memOffset, 0);
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }
@@ -525,7 +549,7 @@
 	
 	MVKTraceVulkanCallStart();
 	MVKImage* mvkImg = (MVKImage*)image;
-	mvkImg->getMemoryRequirements(pMemoryRequirements);
+	mvkImg->getMemoryRequirements(pMemoryRequirements, 0);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -599,7 +623,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !fence ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyFence((MVKFence*)fence, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -662,7 +685,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !semaphore ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroySemaphore((MVKSemaphore*)semaphore, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -689,7 +711,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !event ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyEvent((MVKEvent*)event, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -749,7 +770,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !queryPool ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyQueryPool((MVKQueryPool*)queryPool, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -793,7 +813,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !buffer ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyBuffer((MVKBuffer*)buffer, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -820,7 +839,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !bufferView ) { return; }
     MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
     mvkDev->destroyBufferView((MVKBufferView*)bufferView, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -847,7 +865,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !image ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyImage((MVKImage*)image, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -886,7 +903,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !imageView ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyImageView((MVKImageView*)imageView, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -913,7 +929,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !shaderModule ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyShaderModule((MVKShaderModule*)shaderModule, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -940,7 +955,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !pipelineCache ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyPipelineCache((MVKPipelineCache*)pipelineCache, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1008,7 +1022,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !pipeline ) { return; }
     MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
     mvkDev->destroyPipeline((MVKPipeline*)pipeline, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1035,7 +1048,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !pipelineLayout ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyPipelineLayout((MVKPipelineLayout*)pipelineLayout, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1062,7 +1074,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !sampler ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroySampler((MVKSampler*)sampler, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1089,7 +1100,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !descriptorSetLayout ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyDescriptorSetLayout((MVKDescriptorSetLayout*)descriptorSetLayout, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1116,7 +1126,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !descriptorPool ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyDescriptorPool((MVKDescriptorPool*)descriptorPool, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1194,7 +1203,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !framebuffer ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyFramebuffer((MVKFramebuffer*)framebuffer, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1221,7 +1229,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !renderPass ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyRenderPass((MVKRenderPass*)renderPass, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1233,8 +1240,6 @@
     VkExtent2D*                                 pGranularity) {
 
 	MVKTraceVulkanCallStart();
-    if ( !pGranularity ) { return; }
-
     MVKRenderPass* mvkRendPass = (MVKRenderPass*)renderPass;
     *pGranularity = mvkRendPass->getRenderAreaGranularity();
 	MVKTraceVulkanCallEnd();
@@ -1261,7 +1266,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !commandPool ) { return; }
 	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
 	mvkDev->destroyCommandPool((MVKCommandPool*)commandPool, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -1341,7 +1345,18 @@
     VkPipeline                                  pipeline) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BindPipeline, commandBuffer, pipelineBindPoint, pipeline);
+	switch (pipelineBindPoint) {
+		case VK_PIPELINE_BIND_POINT_GRAPHICS: {
+			MVKAddCmd(BindGraphicsPipeline, commandBuffer, pipeline);
+			break;
+		}
+		case VK_PIPELINE_BIND_POINT_COMPUTE: {
+			MVKAddCmd(BindComputePipeline, commandBuffer, pipeline);
+			break;
+		}
+		default:
+			break;
+	}
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1352,11 +1367,7 @@
 	const VkViewport*                           pViewports) {
 
 	MVKTraceVulkanCallStart();
-	if (viewportCount <= 1) {
-		MVKAddCmd(SetViewport1, commandBuffer, firstViewport, viewportCount, pViewports);
-	} else {
-		MVKAddCmd(SetViewportMulti, commandBuffer, firstViewport, viewportCount, pViewports);
-	}
+	MVKAddCmdFromThreshold(SetViewport, viewportCount, 1, commandBuffer, firstViewport, viewportCount, pViewports);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1367,11 +1378,7 @@
 	const VkRect2D*                             pScissors) {
 
 	MVKTraceVulkanCallStart();
-	if (scissorCount <= 1) {
-		MVKAddCmd(SetScissor1, commandBuffer, firstScissor, scissorCount, pScissors);
-	} else {
-		MVKAddCmd(SetScissorMulti, commandBuffer, firstScissor, scissorCount, pScissors);
-	}
+	MVKAddCmdFromThreshold(SetScissor, scissorCount, 1, commandBuffer, firstScissor, scissorCount, pScissors);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1455,8 +1462,13 @@
     const uint32_t*                             pDynamicOffsets) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BindDescriptorSets, commandBuffer, pipelineBindPoint, layout,
-			  firstSet, setCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
+	if (dynamicOffsetCount) {
+		MVKAddCmdFromThreshold(BindDescriptorSetsDynamic, setCount, 4, commandBuffer, pipelineBindPoint, layout,
+				  firstSet, setCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
+	} else {
+		MVKAddCmdFrom2Thresholds(BindDescriptorSetsStatic, setCount, 1, 4, commandBuffer, pipelineBindPoint, layout,
+				  firstSet, setCount, pDescriptorSets);
+	}
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1479,7 +1491,7 @@
     const VkDeviceSize*                         pOffsets) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BindVertexBuffers, commandBuffer, startBinding, bindingCount, pBuffers, pOffsets);
+	MVKAddCmdFrom2Thresholds(BindVertexBuffers, bindingCount, 1, 2, commandBuffer, startBinding, bindingCount, pBuffers, pOffsets);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1561,7 +1573,7 @@
     const VkBufferCopy*                         pRegions) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(CopyBuffer, commandBuffer, srcBuffer, destBuffer, regionCount, pRegions);
+	MVKAddCmdFromThreshold(CopyBuffer, regionCount, 1, commandBuffer, srcBuffer, destBuffer, regionCount, pRegions);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1575,7 +1587,8 @@
     const VkImageCopy*                          pRegions) {
 
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(CopyImage, commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
+	MVKAddCmdFromThreshold(CopyImage, regionCount, 1, commandBuffer,
+						   srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1590,7 +1603,8 @@
     VkFilter                                    filter) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BlitImage, commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
+	MVKAddCmdFromThreshold(BlitImage, regionCount, 1, commandBuffer,
+						   srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions, filter);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1603,7 +1617,8 @@
     const VkBufferImageCopy*                    pRegions) {
 	
 	MVKTraceVulkanCallStart();
-    MVKAddCmd(BufferImageCopy, commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions, true);
+    MVKAddCmdFrom3Thresholds(BufferImageCopy, regionCount, 1, 4, 8, commandBuffer,
+							 srcBuffer, dstImage, dstImageLayout, regionCount, pRegions, true);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1616,7 +1631,8 @@
     const VkBufferImageCopy*                    pRegions) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BufferImageCopy, commandBuffer, dstBuffer, srcImage, srcImageLayout, regionCount, pRegions, false);
+	MVKAddCmdFrom3Thresholds(BufferImageCopy, regionCount, 1, 4, 8, commandBuffer,
+							 dstBuffer, srcImage, srcImageLayout, regionCount, pRegions, false);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1655,7 +1671,8 @@
 	MVKTraceVulkanCallStart();
 	VkClearValue clrVal;
 	clrVal.color = *pColor;
-	MVKAddCmd(ClearImage, commandBuffer, image, imageLayout, clrVal, rangeCount, pRanges, false);
+	MVKAddCmdFromThreshold(ClearColorImage, rangeCount, 1, commandBuffer,
+						   image, imageLayout, clrVal, rangeCount, pRanges);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1670,7 +1687,8 @@
 	MVKTraceVulkanCallStart();
 	VkClearValue clrVal;
 	clrVal.depthStencil = *pDepthStencil;
-    MVKAddCmd(ClearImage, commandBuffer, image, imageLayout, clrVal, rangeCount, pRanges, true);
+    MVKAddCmdFromThreshold(ClearDepthStencilImage, rangeCount, 1, commandBuffer,
+						   image, imageLayout, clrVal, rangeCount, pRanges);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1682,7 +1700,13 @@
 	const VkClearRect*                          pRects) {
 
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(ClearAttachments, commandBuffer, attachmentCount, pAttachments, rectCount, pRects);
+	if (attachmentCount > 1) {
+		MVKAddCmdFromThreshold(ClearMultiAttachments, rectCount, 1, commandBuffer,
+							   attachmentCount, pAttachments, rectCount, pRects);
+	} else {
+		MVKAddCmdFromThreshold(ClearSingleAttachment, rectCount, 1, commandBuffer,
+							   attachmentCount, pAttachments, rectCount, pRects);
+	}
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1696,8 +1720,8 @@
     const VkImageResolve*                       pRegions) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(ResolveImage, commandBuffer, srcImage, srcImageLayout,
-			  dstImage, dstImageLayout, regionCount, pRegions);
+	MVKAddCmdFromThreshold(ResolveImage, regionCount, 1, commandBuffer,
+						   srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, pRegions);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1705,9 +1729,9 @@
     VkCommandBuffer                             commandBuffer,
     VkEvent                                     event,
     VkPipelineStageFlags                        stageMask) {
-	
+
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(SetResetEvent, commandBuffer, event, stageMask, true);
+	MVKAddCmd(SetEvent, commandBuffer, event, stageMask);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1715,9 +1739,9 @@
     VkCommandBuffer                             commandBuffer,
     VkEvent                                     event,
     VkPipelineStageFlags                        stageMask) {
-	
+
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(SetResetEvent, commandBuffer, event, stageMask, false);
+	MVKAddCmd(ResetEvent, commandBuffer, event, stageMask);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1735,11 +1759,11 @@
 	const VkImageMemoryBarrier*                 pImageMemoryBarriers) {
 
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(WaitEvents, commandBuffer, eventCount, pEvents,
-			  srcStageMask, dstStageMask,
-			  memoryBarrierCount, pMemoryBarriers,
-			  bufferMemoryBarrierCount, pBufferMemoryBarriers,
-			  imageMemoryBarrierCount, pImageMemoryBarriers);
+	MVKAddCmdFromThreshold(WaitEvents, eventCount, 1, commandBuffer,
+						   eventCount, pEvents, srcStageMask, dstStageMask,
+						   memoryBarrierCount, pMemoryBarriers,
+						   bufferMemoryBarrierCount, pBufferMemoryBarriers,
+						   imageMemoryBarrierCount, pImageMemoryBarriers);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1756,10 +1780,12 @@
 	const VkImageMemoryBarrier*                 pImageMemoryBarriers) {
 
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(PipelineBarrier, commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
-			  memoryBarrierCount, pMemoryBarriers,
-			  bufferMemoryBarrierCount, pBufferMemoryBarriers,
-			  imageMemoryBarrierCount, pImageMemoryBarriers);
+	uint32_t barrierCount = memoryBarrierCount + bufferMemoryBarrierCount + imageMemoryBarrierCount;
+	MVKAddCmdFrom2Thresholds(PipelineBarrier, barrierCount, 1, 4, commandBuffer,
+							   srcStageMask, dstStageMask, dependencyFlags,
+							   memoryBarrierCount, pMemoryBarriers,
+							   bufferMemoryBarrierCount, pBufferMemoryBarriers,
+							   imageMemoryBarrierCount, pImageMemoryBarriers);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1831,7 +1857,7 @@
     const void*                                 pValues) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(PushConstants, commandBuffer, layout, stageFlags, offset, size, pValues);
+	MVKAddCmdFrom2Thresholds(PushConstants, size, 64, 128, commandBuffer, layout, stageFlags, offset, size, pValues);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1841,7 +1867,7 @@
     VkSubpassContents							contents) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(BeginRenderPass, commandBuffer,pRenderPassBegin, contents);
+	MVKAddCmdFrom2Thresholds(BeginRenderPass, pRenderPassBegin->clearValueCount, 1, 2, commandBuffer,pRenderPassBegin, contents);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1868,7 +1894,7 @@
     const VkCommandBuffer*						pCommandBuffers) {
 	
 	MVKTraceVulkanCallStart();
-	MVKAddCmd(ExecuteCommands, commandBuffer, cmdBuffersCount, pCommandBuffers);
+	MVKAddCmdFromThreshold(ExecuteCommands, cmdBuffersCount, 1, commandBuffer, cmdBuffersCount, pCommandBuffers);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -1934,7 +1960,6 @@
     const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-    if (!descriptorUpdateTemplate) { return; }
     MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
     mvkDev->destroyDescriptorUpdateTemplate((MVKDescriptorUpdateTemplate*)descriptorUpdateTemplate, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -2113,7 +2138,7 @@
 
 	MVKTraceVulkanCallStart();
     MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-    mvkPD->getPhysicalDeviceMemoryProperties(pMemoryProperties);
+    mvkPD->getMemoryProperties(pMemoryProperties);
 	MVKTraceVulkanCallEnd();
 }
 
@@ -2194,6 +2219,37 @@
 
 
 #pragma mark -
+#pragma mark VK_KHR_sampler_ycbcr_conversion extension
+
+MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversionKHR(
+    VkDevice                                    device,
+    const VkSamplerYcbcrConversionCreateInfo*   pCreateInfo,
+    const VkAllocationCallbacks*                pAllocator,
+    VkSamplerYcbcrConversion*                   pYcbcrConversion) {
+
+    MVKTraceVulkanCallStart();
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
+	*pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
+	VkResult rslt = mvkSampConv->getConfigurationResult();
+	MVKTraceVulkanCallEnd();
+	return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkDestroySamplerYcbcrConversionKHR(
+    VkDevice                                    device,
+    VkSamplerYcbcrConversion                    ycbcrConversion,
+    const VkAllocationCallbacks*                pAllocator) {
+
+    MVKTraceVulkanCallStart();
+	if ( !ycbcrConversion ) { return; }
+	MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+	mvkDev->destroySamplerYcbcrConversion((MVKSamplerYcbcrConversion*)ycbcrConversion, pAllocator);
+	MVKTraceVulkanCallEnd();
+}
+
+
+#pragma mark -
 #pragma mark VK_KHR_swapchain extension
 
 MVK_PUBLIC_SYMBOL VkResult vkCreateSwapchainKHR(
@@ -2217,7 +2273,6 @@
     const VkAllocationCallbacks*             pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !swapchain ) { return; }
     MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
     mvkDev->destroySwapchain((MVKSwapchain*)swapchain, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -2326,7 +2381,6 @@
     const VkAllocationCallbacks*                 pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !surface ) { return; }
     MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
     mvkInst->destroySurface((MVKSurface*)surface, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -2443,7 +2497,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !callback ) { return; }
 	MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
 	mvkInst->destroyDebugReportCallback((MVKDebugReportCallback*)callback, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -2611,7 +2664,6 @@
 	const VkAllocationCallbacks*                pAllocator) {
 
 	MVKTraceVulkanCallStart();
-	if ( !messenger ) { return; }
 	MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
 	mvkInst->destroyDebugUtilsMessenger((MVKDebugUtilsMessenger*)messenger, pAllocator);
 	MVKTraceVulkanCallEnd();
@@ -2665,6 +2717,21 @@
 
 
 #pragma mark -
+#pragma mark VK_KHR_external_memory_capabilities extension
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalBufferPropertiesKHR(
+	VkPhysicalDevice                            physicalDevice,
+	const VkPhysicalDeviceExternalBufferInfo*   pExternalBufferInfo,
+	VkExternalBufferProperties*                 pExternalBufferProperties) {
+
+	MVKTraceVulkanCallStart();
+	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+	mvkPD->getExternalBufferProperties(pExternalBufferInfo, pExternalBufferProperties);
+	MVKTraceVulkanCallEnd();
+}
+
+
+#pragma mark -
 #pragma mark VK_EXT_metal_surface extension
 
 MVK_PUBLIC_SYMBOL VkResult vkCreateMetalSurfaceEXT(
@@ -2683,6 +2750,32 @@
 }
 
 #pragma mark -
+#pragma mark VK_GOOGLE_display_timing extension
+
+MVK_PUBLIC_SYMBOL VkResult vkGetRefreshCycleDurationGOOGLE(
+	VkDevice                                    device,
+	VkSwapchainKHR                              swapchain,
+	VkRefreshCycleDurationGOOGLE*               pDisplayTimingProperties) {
+	MVKTraceVulkanCallStart();
+	MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain;
+	VkResult rslt = mvkSwapchain->getRefreshCycleDuration(pDisplayTimingProperties);
+	MVKTraceVulkanCallEnd();
+	return rslt;
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkGetPastPresentationTimingGOOGLE(
+	VkDevice                                    device,
+	VkSwapchainKHR                              swapchain,
+	uint32_t*                                   pPresentationTimingCount,
+	VkPastPresentationTimingGOOGLE*             pPresentationTimings) {
+	MVKTraceVulkanCallStart();
+	MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain;
+	VkResult rslt = mvkSwapchain->getPastPresentationTiming(pPresentationTimingCount, pPresentationTimings);
+	MVKTraceVulkanCallEnd();
+	return rslt;
+}
+
+#pragma mark -
 #pragma mark iOS & macOS surface extensions
 
 MVK_PUBLIC_SYMBOL VkResult vkCreate_PLATFORM_SurfaceMVK(
diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj
index a6599f1..c9cf30d 100644
--- a/MoltenVKPackaging.xcodeproj/project.pbxproj
+++ b/MoltenVKPackaging.xcodeproj/project.pbxproj
@@ -267,7 +267,7 @@
 		A90B2B1D1A9B6170008EE819 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 				TargetAttributes = {
 					A9FEADBC1F3517480010240E = {
 						DevelopmentTeam = VU3TCKU48B;
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
index f1086b5..88e120b 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
index c68daf5..fb519fc 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
index 5d5ea44..c8303b7 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
index 011bb1f..296fbcd 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
index 0e1d409..02b62e2 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "NO"
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp
deleted file mode 100644
index 213b3ad..0000000
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * SPIRVReflection.cpp
- *
- * Copyright (c) 2019-2020 Chip Davis for Codeweavers
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SPIRVReflection.h"
-#include <SPIRV-Cross/spirv_parser.hpp>
-#include <SPIRV-Cross/spirv_reflect.hpp>
-
-namespace mvk {
-
-static const char missingPatchInputErr[] = "Neither tessellation shader specifies a patch input mode (Triangles, Quads, or Isolines).";
-static const char missingWindingErr[] = "Neither tessellation shader specifies a winding order mode (VertexOrderCw or VertexOrderCcw).";
-static const char missingPartitionErr[] = "Neither tessellation shader specifies a partition mode (SpacingEqual, SpacingFractionalOdd, or SpacingFractionalEven).";
-static const char missingOutputVerticesErr[] = "Neither tessellation shader specifies the number of output control points.";
-
-/** Given a tessellation control shader and a tessellation evaluation shader, both in SPIR-V format, returns tessellation reflection data. */
-bool getTessReflectionData(const std::vector<uint32_t>& tesc, const std::string& tescEntryName, const std::vector<uint32_t>& tese, const std::string& teseEntryName, SPIRVTessReflectionData& reflectData, std::string& errorLog) {
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
-	try {
-#endif
-		SPIRV_CROSS_NAMESPACE::CompilerReflection tescReflect(tesc);
-		SPIRV_CROSS_NAMESPACE::CompilerReflection teseReflect(tese);
-
-		if (!tescEntryName.empty()) {
-			tescReflect.set_entry_point(tescEntryName, spv::ExecutionModelTessellationControl);
-		}
-		if (!teseEntryName.empty()) {
-			teseReflect.set_entry_point(teseEntryName, spv::ExecutionModelTessellationEvaluation);
-		}
-
-		tescReflect.compile();
-		teseReflect.compile();
-
-		const SPIRV_CROSS_NAMESPACE::Bitset& tescModes = tescReflect.get_execution_mode_bitset();
-		const SPIRV_CROSS_NAMESPACE::Bitset& teseModes = teseReflect.get_execution_mode_bitset();
-
-		// Extract the parameters from the shaders.
-		if (tescModes.get(spv::ExecutionModeTriangles)) {
-			reflectData.patchKind = spv::ExecutionModeTriangles;
-		} else if (tescModes.get(spv::ExecutionModeQuads)) {
-			reflectData.patchKind = spv::ExecutionModeQuads;
-		} else if (tescModes.get(spv::ExecutionModeIsolines)) {
-			reflectData.patchKind = spv::ExecutionModeIsolines;
-		} else if (teseModes.get(spv::ExecutionModeTriangles)) {
-			reflectData.patchKind = spv::ExecutionModeTriangles;
-		} else if (teseModes.get(spv::ExecutionModeQuads)) {
-			reflectData.patchKind = spv::ExecutionModeQuads;
-		} else if (teseModes.get(spv::ExecutionModeIsolines)) {
-			reflectData.patchKind = spv::ExecutionModeIsolines;
-		} else {
-			errorLog = missingPatchInputErr;
-			return false;
-		}
-
-		if (tescModes.get(spv::ExecutionModeVertexOrderCw)) {
-			reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
-		} else if (tescModes.get(spv::ExecutionModeVertexOrderCcw)) {
-			reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
-		} else if (teseModes.get(spv::ExecutionModeVertexOrderCw)) {
-			reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
-		} else if (teseModes.get(spv::ExecutionModeVertexOrderCcw)) {
-			reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
-		} else {
-			errorLog = missingWindingErr;
-			return false;
-		}
-
-		reflectData.pointMode = tescModes.get(spv::ExecutionModePointMode) || teseModes.get(spv::ExecutionModePointMode);
-
-		if (tescModes.get(spv::ExecutionModeSpacingEqual)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
-		} else if (tescModes.get(spv::ExecutionModeSpacingFractionalEven)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
-		} else if (tescModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
-		} else if (teseModes.get(spv::ExecutionModeSpacingEqual)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
-		} else if (teseModes.get(spv::ExecutionModeSpacingFractionalEven)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
-		} else if (teseModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
-			reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
-		} else {
-			errorLog = missingPartitionErr;
-			return false;
-		}
-
-		if (tescModes.get(spv::ExecutionModeOutputVertices)) {
-			reflectData.numControlPoints = tescReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
-		} else if (teseModes.get(spv::ExecutionModeOutputVertices)) {
-			reflectData.numControlPoints = teseReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
-		} else {
-			errorLog = missingOutputVerticesErr;
-			return false;
-		}
-
-		return true;
-
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
-	} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
-		errorLog = ex.what();
-		return false;
-	}
-#endif
-}
-
-/** Given a shader in SPIR-V format, returns output reflection data. */
-bool getShaderOutputs(const std::vector<uint32_t>& spirv, spv::ExecutionModel model, const std::string& entryName, std::vector<SPIRVShaderOutput>& outputs, std::string& errorLog) {
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
-	try {
-#endif
-		SPIRV_CROSS_NAMESPACE::Parser parser(spirv);
-		parser.parse();
-		SPIRV_CROSS_NAMESPACE::CompilerReflection reflect(parser.get_parsed_ir());
-		if (!entryName.empty()) {
-			reflect.set_entry_point(entryName, model);
-		}
-		reflect.compile();
-		reflect.update_active_builtins();
-
-		outputs.clear();
-
-		auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
-		parser.get_parsed_ir().for_each_typed_id<SPIRV_CROSS_NAMESPACE::SPIRVariable>([&reflect, &outputs, model, addSat](uint32_t varID, const SPIRV_CROSS_NAMESPACE::SPIRVariable& var) {
-			if (var.storage != spv::StorageClassOutput) { return; }
-
-			bool isUsed = true;
-			const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
-			bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
-			auto biType = spv::BuiltInMax;
-			if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
-				biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);
-				isUsed = reflect.has_active_builtin(biType, var.storage);
-			}
-			uint32_t loc = -1;
-			if (reflect.has_decoration(varID, spv::DecorationLocation)) {
-				loc = reflect.get_decoration(varID, spv::DecorationLocation);
-			}
-			if (model == spv::ExecutionModelTessellationControl && !patch)
-				type = &reflect.get_type(type->parent_type);
-
-			if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
-				for (uint32_t i = 0; i < type->member_types.size(); i++) {
-					// Each member may have a location decoration. If not, each member
-					// gets an incrementing location.
-					uint32_t memberLoc = addSat(loc, i);
-					if (reflect.has_member_decoration(type->self, i, spv::DecorationLocation)) {
-						memberLoc = reflect.get_member_decoration(type->self, i, spv::DecorationLocation);
-					}
-					patch = reflect.has_member_decoration(type->self, i, spv::DecorationPatch);
-					if (reflect.has_member_decoration(type->self, i, spv::DecorationBuiltIn)) {
-						biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, i, spv::DecorationBuiltIn);
-						isUsed = reflect.has_active_builtin(biType, var.storage);
-					}
-					const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[i]);
-					if (memberType.columns > 1) {
-						for (uint32_t i = 0; i < memberType.columns; i++) {
-							outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
-						}
-					} else if (!memberType.array.empty()) {
-						for (uint32_t i = 0; i < memberType.array[0]; i++) {
-							outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
-						}
-					} else {
-						outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, biType, patch, isUsed});
-					}
-				}
-			} else if (type->columns > 1) {
-				for (uint32_t i = 0; i < type->columns; i++) {
-					outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
-				}
-			} else if (!type->array.empty()) {
-				for (uint32_t i = 0; i < type->array[0]; i++) {
-					outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
-				}
-			} else {
-				outputs.push_back({type->basetype, type->vecsize, loc, biType, patch, isUsed});
-			}
-		});
-		// Sort outputs by ascending location.
-		std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
-			return a.location < b.location;
-		});
-		// Assign locations to outputs that don't have one.
-		uint32_t loc = -1;
-		for (SPIRVShaderOutput& out : outputs) {
-			if (out.location == uint32_t(-1)) { out.location = loc + 1; }
-			loc = out.location;
-		}
-		return true;
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
-	} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
-		errorLog = ex.what();
-		return false;
-	}
-#endif
-}
-
-}
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
index 30d4dbf..b17fe79 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
@@ -21,6 +21,8 @@
 
 #include <SPIRV-Cross/spirv.hpp>
 #include <SPIRV-Cross/spirv_common.hpp>
+#include <SPIRV-Cross/spirv_parser.hpp>
+#include <SPIRV-Cross/spirv_reflect.hpp>
 #include <string>
 #include <vector>
 
@@ -75,10 +77,191 @@
 #pragma mark Functions
 
 	/** Given a tessellation control shader and a tessellation evaluation shader, both in SPIR-V format, returns tessellation reflection data. */
-	bool getTessReflectionData(const std::vector<uint32_t>& tesc, const std::string& tescEntryName, const std::vector<uint32_t>& tese, const std::string& teseEntryName, SPIRVTessReflectionData& reflectData, std::string& errorLog);
+	template<typename Vs>
+	static inline bool getTessReflectionData(const Vs& tesc, const std::string& tescEntryName,
+											 const Vs& tese, const std::string& teseEntryName,
+											 SPIRVTessReflectionData& reflectData, std::string& errorLog) {
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+		try {
+#endif
+			SPIRV_CROSS_NAMESPACE::CompilerReflection tescReflect(tesc);
+			SPIRV_CROSS_NAMESPACE::CompilerReflection teseReflect(tese);
+
+			if (!tescEntryName.empty()) {
+				tescReflect.set_entry_point(tescEntryName, spv::ExecutionModelTessellationControl);
+			}
+			if (!teseEntryName.empty()) {
+				teseReflect.set_entry_point(teseEntryName, spv::ExecutionModelTessellationEvaluation);
+			}
+
+			tescReflect.compile();
+			teseReflect.compile();
+
+			const SPIRV_CROSS_NAMESPACE::Bitset& tescModes = tescReflect.get_execution_mode_bitset();
+			const SPIRV_CROSS_NAMESPACE::Bitset& teseModes = teseReflect.get_execution_mode_bitset();
+
+			// Extract the parameters from the shaders.
+			if (tescModes.get(spv::ExecutionModeTriangles)) {
+				reflectData.patchKind = spv::ExecutionModeTriangles;
+			} else if (tescModes.get(spv::ExecutionModeQuads)) {
+				reflectData.patchKind = spv::ExecutionModeQuads;
+			} else if (tescModes.get(spv::ExecutionModeIsolines)) {
+				reflectData.patchKind = spv::ExecutionModeIsolines;
+			} else if (teseModes.get(spv::ExecutionModeTriangles)) {
+				reflectData.patchKind = spv::ExecutionModeTriangles;
+			} else if (teseModes.get(spv::ExecutionModeQuads)) {
+				reflectData.patchKind = spv::ExecutionModeQuads;
+			} else if (teseModes.get(spv::ExecutionModeIsolines)) {
+				reflectData.patchKind = spv::ExecutionModeIsolines;
+			} else {
+				errorLog = "Neither tessellation shader specifies a patch input mode (Triangles, Quads, or Isolines).";
+				return false;
+			}
+
+			if (tescModes.get(spv::ExecutionModeVertexOrderCw)) {
+				reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
+			} else if (tescModes.get(spv::ExecutionModeVertexOrderCcw)) {
+				reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
+			} else if (teseModes.get(spv::ExecutionModeVertexOrderCw)) {
+				reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
+			} else if (teseModes.get(spv::ExecutionModeVertexOrderCcw)) {
+				reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
+			} else {
+				errorLog = "Neither tessellation shader specifies a winding order mode (VertexOrderCw or VertexOrderCcw).";
+				return false;
+			}
+
+			reflectData.pointMode = tescModes.get(spv::ExecutionModePointMode) || teseModes.get(spv::ExecutionModePointMode);
+
+			if (tescModes.get(spv::ExecutionModeSpacingEqual)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
+			} else if (tescModes.get(spv::ExecutionModeSpacingFractionalEven)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
+			} else if (tescModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
+			} else if (teseModes.get(spv::ExecutionModeSpacingEqual)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
+			} else if (teseModes.get(spv::ExecutionModeSpacingFractionalEven)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
+			} else if (teseModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
+				reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
+			} else {
+				errorLog = "Neither tessellation shader specifies a partition mode (SpacingEqual, SpacingFractionalOdd, or SpacingFractionalEven).";
+				return false;
+			}
+
+			if (tescModes.get(spv::ExecutionModeOutputVertices)) {
+				reflectData.numControlPoints = tescReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
+			} else if (teseModes.get(spv::ExecutionModeOutputVertices)) {
+				reflectData.numControlPoints = teseReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
+			} else {
+				errorLog = "Neither tessellation shader specifies the number of output control points.";
+				return false;
+			}
+
+			return true;
+
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+		} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
+			errorLog = ex.what();
+			return false;
+		}
+#endif
+	}
 
 	/** Given a shader in SPIR-V format, returns output reflection data. */
-	bool getShaderOutputs(const std::vector<uint32_t>& spirv, spv::ExecutionModel model, const std::string& entryName, std::vector<SPIRVShaderOutput>& outputs, std::string& errorLog);
+	template<typename Vs, typename Vo>
+	static inline bool getShaderOutputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
+										Vo& outputs, std::string& errorLog) {
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+		try {
+#endif
+			SPIRV_CROSS_NAMESPACE::Parser parser(spirv);
+			parser.parse();
+			SPIRV_CROSS_NAMESPACE::CompilerReflection reflect(parser.get_parsed_ir());
+			if (!entryName.empty()) {
+				reflect.set_entry_point(entryName, model);
+			}
+			reflect.compile();
+			reflect.update_active_builtins();
+
+			outputs.clear();
+
+			auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
+			parser.get_parsed_ir().for_each_typed_id<SPIRV_CROSS_NAMESPACE::SPIRVariable>([&reflect, &outputs, model, addSat](uint32_t varID, const SPIRV_CROSS_NAMESPACE::SPIRVariable& var) {
+				if (var.storage != spv::StorageClassOutput) { return; }
+
+				bool isUsed = true;
+				const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
+				bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
+				auto biType = spv::BuiltInMax;
+				if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
+					biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);
+					isUsed = reflect.has_active_builtin(biType, var.storage);
+				}
+				uint32_t loc = -1;
+				if (reflect.has_decoration(varID, spv::DecorationLocation)) {
+					loc = reflect.get_decoration(varID, spv::DecorationLocation);
+				}
+				if (model == spv::ExecutionModelTessellationControl && !patch)
+					type = &reflect.get_type(type->parent_type);
+
+				if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
+					for (uint32_t idx = 0; idx < type->member_types.size(); idx++) {
+						// Each member may have a location decoration. If not, each member
+						// gets an incrementing location.
+						uint32_t memberLoc = addSat(loc, idx);
+						if (reflect.has_member_decoration(type->self, idx, spv::DecorationLocation)) {
+							memberLoc = reflect.get_member_decoration(type->self, idx, spv::DecorationLocation);
+						}
+						patch = reflect.has_member_decoration(type->self, idx, spv::DecorationPatch);
+						if (reflect.has_member_decoration(type->self, idx, spv::DecorationBuiltIn)) {
+							biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, idx, spv::DecorationBuiltIn);
+							isUsed = reflect.has_active_builtin(biType, var.storage);
+						}
+						const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[idx]);
+						if (memberType.columns > 1) {
+							for (uint32_t i = 0; i < memberType.columns; i++) {
+								outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
+							}
+						} else if (!memberType.array.empty()) {
+							for (uint32_t i = 0; i < memberType.array[0]; i++) {
+								outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
+							}
+						} else {
+							outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, biType, patch, isUsed});
+						}
+					}
+				} else if (type->columns > 1) {
+					for (uint32_t i = 0; i < type->columns; i++) {
+						outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
+					}
+				} else if (!type->array.empty()) {
+					for (uint32_t i = 0; i < type->array[0]; i++) {
+						outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
+					}
+				} else {
+					outputs.push_back({type->basetype, type->vecsize, loc, biType, patch, isUsed});
+				}
+			});
+			// Sort outputs by ascending location.
+			std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
+				return a.location < b.location;
+			});
+			// Assign locations to outputs that don't have one.
+			uint32_t loc = -1;
+			for (SPIRVShaderOutput& out : outputs) {
+				if (out.location == uint32_t(-1)) { out.location = loc + 1; }
+				loc = out.location;
+			}
+			return true;
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+		} catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
+			errorLog = ex.what();
+			return false;
+		}
+#endif
+	}
 
 }
 #endif
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
index 6ee2d97..6e71501 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
@@ -103,12 +103,9 @@
 
 MVK_PUBLIC_SYMBOL bool MSLVertexAttribute::matches(const MSLVertexAttribute& other) const {
 	if (vertexAttribute.location != other.vertexAttribute.location) { return false; }
-	if (vertexAttribute.msl_buffer != other.vertexAttribute.msl_buffer) { return false; }
-	if (vertexAttribute.msl_offset != other.vertexAttribute.msl_offset) { return false; }
-	if (vertexAttribute.msl_stride != other.vertexAttribute.msl_stride) { return false; }
 	if (vertexAttribute.format != other.vertexAttribute.format) { return false; }
 	if (vertexAttribute.builtin != other.vertexAttribute.builtin) { return false; }
-	if (!!vertexAttribute.per_instance != !!other.vertexAttribute.per_instance) { return false; }
+	if (binding != other.binding) { return false; }
 	return true;
 }
 
@@ -136,9 +133,22 @@
 		if (constExprSampler.lod_clamp_min != other.constExprSampler.lod_clamp_min) { return false; }
 		if (constExprSampler.lod_clamp_max != other.constExprSampler.lod_clamp_max) { return false; }
 		if (constExprSampler.max_anisotropy != other.constExprSampler.max_anisotropy) { return false; }
+
+		if (constExprSampler.planes != other.constExprSampler.planes) { return false; }
+		if (constExprSampler.resolution != other.constExprSampler.resolution) { return false; }
+		if (constExprSampler.chroma_filter != other.constExprSampler.chroma_filter) { return false; }
+		if (constExprSampler.x_chroma_offset != other.constExprSampler.x_chroma_offset) { return false; }
+		if (constExprSampler.y_chroma_offset != other.constExprSampler.y_chroma_offset) { return false; }
+		for(uint32_t i = 0; i < 4; ++i)
+			if (constExprSampler.swizzle[i] != other.constExprSampler.swizzle[i]) { return false; }
+		if (constExprSampler.ycbcr_model != other.constExprSampler.ycbcr_model) { return false; }
+		if (constExprSampler.ycbcr_range != other.constExprSampler.ycbcr_range) { return false; }
+		if (constExprSampler.bpc != other.constExprSampler.bpc) { return false; }
+
 		if (constExprSampler.compare_enable != other.constExprSampler.compare_enable) { return false; }
 		if (constExprSampler.lod_clamp_enable != other.constExprSampler.lod_clamp_enable) { return false; }
 		if (constExprSampler.anisotropy_enable != other.constExprSampler.anisotropy_enable) { return false; }
+		if (constExprSampler.ycbcr_conversion_enable != other.constExprSampler.ycbcr_conversion_enable) { return false; }
 	}
 
 	return true;
@@ -158,12 +168,12 @@
     return false;
 }
 
-// Check them all in case inactive VA's duplicate buffers used by active VA's.
-MVK_PUBLIC_SYMBOL bool SPIRVToMSLConversionConfiguration::isVertexBufferUsed(uint32_t mslBuffer) const {
-    for (auto& va : vertexAttributes) {
-        if ((va.vertexAttribute.msl_buffer == mslBuffer) && va.isUsedByShader) { return true; }
-    }
-    return false;
+MVK_PUBLIC_SYMBOL uint32_t SPIRVToMSLConversionConfiguration::countVertexAttributesAt(uint32_t binding) const {
+	uint32_t vaCnt = 0;
+	for (auto& va : vertexAttributes) {
+		if ((va.binding == binding) && va.isUsedByShader) { vaCnt++; }
+	}
+	return vaCnt;
 }
 
 MVK_PUBLIC_SYMBOL void SPIRVToMSLConversionConfiguration::markAllAttributesAndResourcesUsed() {
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
index 6cb0cea..0d5ddb7 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
@@ -74,6 +74,7 @@
 	typedef struct MSLVertexAttribute {
 		SPIRV_CROSS_NAMESPACE::MSLVertexAttr vertexAttribute;
 
+		uint32_t binding = 0;
 		bool isUsedByShader = false;
 
 		/**
@@ -135,8 +136,11 @@
         /** Returns whether the vertex attribute at the specified location is used by the shader. */
         bool isVertexAttributeLocationUsed(uint32_t location) const;
 
-        /** Returns whether the vertex buffer at the specified Metal binding index is used by the shader. */
-        bool isVertexBufferUsed(uint32_t mslBuffer) const;
+		/** Returns the number of vertex attributes bound to the specified Vulkan buffer binding, and used by the shader. */
+		uint32_t countVertexAttributesAt(uint32_t binding) const;
+
+        /** Returns whether the vertex buffer at the specified Vulkan binding is used by the shader. */
+		bool isVertexBufferUsed(uint32_t binding) const { return countVertexAttributesAt(binding) > 0; }
 
 		/** Marks all vertex attributes and resources as being used by the shader. */
 		void markAllAttributesAndResourcesUsed();
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
index 62fb66e..e0d366a 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
@@ -7,8 +7,6 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
-		450A4F5F220CB180007203D7 /* SPIRVReflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */; };
-		450A4F60220CB180007203D7 /* SPIRVReflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */; };
 		450A4F61220CB180007203D7 /* SPIRVReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F5E220CB180007203D7 /* SPIRVReflection.h */; };
 		450A4F62220CB180007203D7 /* SPIRVReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F5E220CB180007203D7 /* SPIRVReflection.h */; };
 		A909408A1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */; };
@@ -81,7 +79,6 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
-		450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SPIRVReflection.cpp; sourceTree = "<group>"; };
 		450A4F5E220CB180007203D7 /* SPIRVReflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPIRVReflection.h; sourceTree = "<group>"; };
 		A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SPIRVToMSLConverter.cpp; sourceTree = "<group>"; };
 		A9093F5B1C58013E0094110D /* SPIRVToMSLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPIRVToMSLConverter.h; sourceTree = "<group>"; };
@@ -175,7 +172,6 @@
 				A925B70A1C7754B2006E7ECD /* FileSupport.mm */,
 				A928C9171D0488DC00071B88 /* SPIRVConversion.h */,
 				A928C9181D0488DC00071B88 /* SPIRVConversion.mm */,
-				450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */,
 				450A4F5E220CB180007203D7 /* SPIRVReflection.h */,
 				A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */,
 				A9093F5B1C58013E0094110D /* SPIRVToMSLConverter.h */,
@@ -415,7 +411,7 @@
 		A9F55D25198BE6A7004EC31B /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 1140;
+				LastUpgradeCheck = 1150;
 				ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
 				TargetAttributes = {
 					A9092A8C1A81717B00051823 = {
@@ -648,7 +644,6 @@
 				A909408A1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */,
 				A9C70F66221B321700FBA31A /* SPIRVSupport.cpp in Sources */,
 				A928C91B1D0488DC00071B88 /* SPIRVConversion.mm in Sources */,
-				450A4F5F220CB180007203D7 /* SPIRVReflection.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -660,7 +655,6 @@
 				A909408B1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */,
 				A9C70F67221B321700FBA31A /* SPIRVSupport.cpp in Sources */,
 				A928C91C1D0488DC00071B88 /* SPIRVConversion.mm in Sources */,
-				450A4F60220CB180007203D7 /* SPIRVReflection.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -711,8 +705,6 @@
 		A93747401A9A8B2900F29B34 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
 				CLANG_WARN_UNREACHABLE_CODE = NO;
 				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
@@ -722,15 +714,12 @@
 				PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A93747411A9A8B2900F29B34 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
 				CLANG_WARN_UNREACHABLE_CODE = NO;
 				GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
@@ -740,7 +729,6 @@
 				PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -775,8 +763,6 @@
 		A93903BD1C57E9D700FE90DC /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
@@ -786,15 +772,12 @@
 				PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Debug;
 		};
 		A93903BE1C57E9D700FE90DC /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
-				ARCHS = arm64;
-				BITCODE_GENERATION_MODE = bitcode;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"$(inherited)",
 					"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
@@ -804,7 +787,6 @@
 				PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
 				SDKROOT = iphoneos;
 				TARGETED_DEVICE_FAMILY = "1,2";
-				VALID_ARCHS = arm64;
 			};
 			name = Release;
 		};
@@ -840,6 +822,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
@@ -853,9 +836,10 @@
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
-				CLANG_WARN_UNREACHABLE_CODE = NO;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = NO;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -872,8 +856,8 @@
 				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
 				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_PARAMETER = YES;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
@@ -886,7 +870,6 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				ONLY_ACTIVE_ARCH = YES;
 				SKIP_INSTALL = YES;
-				VALID_ARCHS = x86_64;
 			};
 			name = Debug;
 		};
@@ -894,6 +877,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
 				CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
 				CLANG_CXX_LIBRARY = "libc++";
 				CLANG_ENABLE_MODULES = NO;
@@ -907,9 +891,10 @@
 				CLANG_WARN_INT_CONVERSION = YES;
 				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+				CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO;
 				CLANG_WARN_SUSPICIOUS_MOVE = YES;
-				CLANG_WARN_UNREACHABLE_CODE = NO;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = NO;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = YES;
 				ENABLE_NS_ASSERTIONS = NO;
@@ -926,8 +911,8 @@
 				GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
 				GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
-				GCC_WARN_UNUSED_PARAMETER = YES;
 				GCC_WARN_UNUSED_VARIABLE = NO;
 				HEADER_SEARCH_PATHS = (
 					"$(inherited)",
@@ -940,7 +925,6 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				SKIP_INSTALL = YES;
 				VALIDATE_PRODUCT = YES;
-				VALID_ARCHS = x86_64;
 			};
 			name = Release;
 		};
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
index 9c5e88e..4a06e22 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
index 555a788..a4a66d6 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
index a3d1947..8c280b7 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
index 445228e..10e1218 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
index 9b5bad7..4fcf339 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1140"
+   LastUpgradeVersion = "1150"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm
index 91d2dc9..5b72b69 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverterTool/OSSupport.mm
@@ -19,6 +19,7 @@
 #include "OSSupport.h"
 #include "FileSupport.h"
 #include "MoltenVKShaderConverterTool.h"
+#include "MVKOSExtensions.h"
 
 #import <Foundation/Foundation.h>
 #import <Metal/Metal.h>
@@ -71,13 +72,9 @@
 
 	MTLLanguageVersion mslVerEnum = (MTLLanguageVersion)0;
 	if (mslVer(2, 1, 0)) {
-		if (@available(macOS 10.14, *)) {
-			mslVerEnum = MTLLanguageVersion2_1;
-		}
+		mslVerEnum = MTLLanguageVersion2_1;
 	} else if (mslVer(2, 0, 0)) {
-		if (@available(macOS 10.13, *)) {
-			mslVerEnum = MTLLanguageVersion2_0;
-		}
+		mslVerEnum = MTLLanguageVersion2_0;
 	} else if (mslVer(1, 2, 0)) {
 		mslVerEnum = MTLLanguageVersion1_2;
 	} else if (mslVer(1, 1, 0)) {
diff --git a/Scripts/packagePregenSpirvToolsHeaders b/Scripts/packagePregenSpirvToolsHeaders
index d77620d..0ccaf8a 100755
--- a/Scripts/packagePregenSpirvToolsHeaders
+++ b/Scripts/packagePregenSpirvToolsHeaders
@@ -14,6 +14,11 @@
 TPLT_DIR=../Templates/spirv-tools
 TPLT_BLD_DIR="${TPLT_DIR}/build"
 
+# Ensure the SPIRV-Tools library is fully built
+cd ".."
+./fetchDependencies --build-spirv-tools
+cd -  > /dev/null
+
 rm -rf "${TPLT_BLD_DIR}"
 mkdir -p "${TPLT_BLD_DIR}"
 cp -a "${SPV_TLS_BLD_DIR}/"*.h "${SPV_TLS_BLD_DIR}/"*.inc "${TPLT_BLD_DIR}"
diff --git a/Templates/spirv-tools/build.zip b/Templates/spirv-tools/build.zip
index 7e83de0..281160e 100644
--- a/Templates/spirv-tools/build.zip
+++ b/Templates/spirv-tools/build.zip
Binary files differ
diff --git a/fetchDependencies b/fetchDependencies
index 68547d1..827ca6e 100755
--- a/fetchDependencies
+++ b/fetchDependencies
@@ -4,7 +4,7 @@
 #
 # fetchDependencies - Retrieves the correct versions of all dependencies
 #
-# macOS usage: ./fetchDependencies [-v] [--debug] [--skip-spirv-tools-build]
+# macOS usage: ./fetchDependencies [-v] [--debug] [--build-spirv-tools]
 #                                  [--v-headers-root path] [--spirv-cross-root path] [--glslang-root path]
 #
 #      --debug
@@ -16,10 +16,15 @@
 #              This repository does need to be built and the build directory must be in the
 #              specified directory. It should be built the same way this script builds it.
 #
-#      --skip-spirv-tools-build
-#              Skip the spirv-tools build and install a template of pre-generated SPIRV-Tools header files
-#              instead. The primary purpose of this is to allow Travis CI to skip the SPIRV-Tools build
-#              because Travis cannot support the required use of Python3 by the SPIRV-Tools build.
+#      --build-spirv-tools
+#              Build the full spirv-tools distribution. Normally this is not needed, because
+#              MoltenVK includes a template of pre-generated SPIRV-Tools header files, which
+#              is all that is needed. Avoiding the spirv-tools build saves significant time
+#              during the running of this script, and is necessary during CI because Travis CI
+#              cannot support the required use of Python3 by the spirv-tools build. This flag
+#              is used by the packagePregenSpirvToolsHeaders script which regenerates the
+#              spirv-tools header files and repackages the Templates/spirv-tools/build.zip
+#              file when the spirv-tools library version is upgraded.
 #
 #      --spirv-cross-root path
 #              "path" specifies a directory path to a KhronosGroup/SPIRV-Cross repository.
@@ -41,7 +46,7 @@
 V_HEADERS_ROOT=""
 SPIRV_CROSS_ROOT=""
 GLSLANG_ROOT=""
-SKIP_SPV_TLS_BLD=""
+BLD_SPV_TLS=""
 
 while (( "$#" )); do
   case "$1" in
@@ -53,8 +58,12 @@
          XC_BUILD_VERBOSITY=""
          shift 1
          ;;
-       --skip-spirv-tools-build)
-         SKIP_SPV_TLS_BLD="Y"
+       --build-spirv-tools)
+         BLD_SPV_TLS="Y"
+         shift 1
+         ;;
+       --skip-spirv-tools-build)	#deprecated
+         BLD_SPV_TLS=""
          shift 1
          ;;
        --v-headers-root)
@@ -229,11 +238,11 @@
 
 # Build the embedded spirv-tools, or use option of pre-generated headers
 SPV_TLS_DIR="${REPO_NAME}/External/spirv-tools"
-if [ ! "$SKIP_SPV_TLS_BLD" = "" ]; then
+if [ "$BLD_SPV_TLS" = "Y" ]; then
+	build_repo "${SPV_TLS_DIR}"
+else
 	unzip -o -q -d "${SPV_TLS_DIR}" ../Templates/spirv-tools/build.zip
 	rm -rf "${SPV_TLS_DIR}/__MACOSX"
-else
-	build_repo "${SPV_TLS_DIR}"
 fi