diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index d8369d20069e4374251c64e917a1c36eaeba90d2..315546db0650e1aaf92b72aee988370a11fd4ebb 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -2612,7 +2612,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
         spvType = builder.makeFloatType(64);
         break;
     case glslang::EbtFloat16:
-        builder.addCapability(spv::CapabilityFloat16);
 #if AMD_EXTENSIONS
         if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
             builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
@@ -2627,16 +2626,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
         else
             spvType = builder.makeBoolType();
         break;
-   case glslang::EbtInt8:
-        builder.addCapability(spv::CapabilityInt8);
+    case glslang::EbtInt8:
         spvType = builder.makeIntType(8);
         break;
     case glslang::EbtUint8:
-        builder.addCapability(spv::CapabilityInt8);
         spvType = builder.makeUintType(8);
         break;
-   case glslang::EbtInt16:
-        builder.addCapability(spv::CapabilityInt16);
+    case glslang::EbtInt16:
 #ifdef AMD_EXTENSIONS
         if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
             builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
@@ -2644,7 +2640,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
         spvType = builder.makeIntType(16);
         break;
     case glslang::EbtUint16:
-        builder.addCapability(spv::CapabilityInt16);
 #ifdef AMD_EXTENSIONS
         if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
             builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 5a7bb5ce2cf1c40f63dc814914f2ebf738953801..093a740f9077658ac5d4849de5516094e54cc00a 100755
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -194,10 +194,8 @@ Id Builder::makeIntegerType(int width, bool hasSign)
     // deal with capabilities
     switch (width) {
     case 8:
-        addCapability(CapabilityInt8);
-        break;
     case 16:
-        addCapability(CapabilityInt16);
+        // these are currently handled by storage-type declarations and post processing
         break;
     case 64:
         addCapability(CapabilityInt64);
@@ -229,7 +227,7 @@ Id Builder::makeFloatType(int width)
     // deal with capabilities
     switch (width) {
     case 16:
-        addCapability(CapabilityFloat16);
+        // currently handled by storage-type declarations and post processing
         break;
     case 64:
         addCapability(CapabilityFloat64);
@@ -520,12 +518,6 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
     Op typeClass = instr->getOpCode();
     switch (typeClass)
     {
-    case OpTypeVoid:
-    case OpTypeBool:
-    case OpTypeInt:
-    case OpTypeFloat:
-    case OpTypeStruct:
-        return typeClass;
     case OpTypeVector:
     case OpTypeMatrix:
     case OpTypeArray:
@@ -534,8 +526,7 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
     case OpTypePointer:
         return getMostBasicTypeClass(instr->getIdOperand(1));
     default:
-        assert(0);
-        return OpTypeFloat;
+        return typeClass;
     }
 }
 
@@ -622,6 +613,36 @@ Id Builder::getContainedTypeId(Id typeId) const
     return getContainedTypeId(typeId, 0);
 }
 
+// Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
+// of width 'width'. The 'width' is only consumed for int and float types.
+// Returns false otherwise.
+bool Builder::containsType(Id typeId, spv::Op typeOp, int width) const
+{
+    const Instruction& instr = *module.getInstruction(typeId);
+
+    Op typeClass = instr.getOpCode();
+    switch (typeClass)
+    {
+    case OpTypeInt:
+    case OpTypeFloat:
+        return typeClass == typeOp && instr.getImmediateOperand(0) == width;
+    case OpTypeStruct:
+        for (int m = 0; m < instr.getNumOperands(); ++m) {
+            if (containsType(instr.getIdOperand(m), typeOp, width))
+                return true;
+        }
+        return false;
+    case OpTypeVector:
+    case OpTypeMatrix:
+    case OpTypeArray:
+    case OpTypeRuntimeArray:
+    case OpTypePointer:
+        return containsType(getContainedTypeId(typeId), typeOp, width);
+    default:
+        return typeClass == typeOp;
+    }
+}
+
 // See if a scalar constant of this type has already been created, so it
 // can be reused rather than duplicated.  (Required by the specification).
 Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 01698b35378ec92e39e2b57317b07ac275fce3e1..b09ba04c3472c26b6169bb5f4d58a55faef7f417 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -167,6 +167,7 @@ public:
     bool isImageType(Id typeId)        const { return getTypeClass(typeId) == OpTypeImage; }
     bool isSamplerType(Id typeId)      const { return getTypeClass(typeId) == OpTypeSampler; }
     bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
+    bool containsType(Id typeId, Op typeOp, int width) const;
 
     bool isConstantOpCode(Op opcode) const;
     bool isSpecConstantOpCode(Op opcode) const;
@@ -569,9 +570,11 @@ public:
     void postProcess();
 
     // Hook to visit each instruction in a block in a function
-    void postProcess(Instruction& inst);
+    void postProcess(const Instruction&);
     // Hook to visit each instruction in a reachable block in a function.
-    void postProcessReachable(Instruction& inst);
+    void postProcessReachable(const Instruction&);
+    // Hook to visit each non-32-bit sized float/int operation in a block.
+    void postProcessType(const Instruction&, spv::Id typeId);
 
     void dump(std::vector<unsigned int>&) const;
 
diff --git a/SPIRV/SpvPostProcess.cpp b/SPIRV/SpvPostProcess.cpp
index df6ba81729fbef7f46efa8b3909943f6783aa974..d9abd91e67afbbd7b554221a9f94fa3d72cc7efd 100755
--- a/SPIRV/SpvPostProcess.cpp
+++ b/SPIRV/SpvPostProcess.cpp
@@ -61,8 +61,78 @@ namespace spv {
 
 namespace spv {
 
+// Hook to visit each operand type and result type of an instruction.
+// Will be called multiple times for one instruction, once for each typed
+// operand and the result.
+void Builder::postProcessType(const Instruction& inst, Id typeId)
+{
+    // Characterize the type being questioned
+    Id basicTypeOp = getMostBasicTypeClass(typeId);
+    int width = 0;
+    if (basicTypeOp == OpTypeFloat || basicTypeOp == OpTypeInt)
+        width = getScalarTypeWidth(typeId);
+
+    // Do opcode-specific checks
+    switch (inst.getOpCode()) {
+    case OpLoad:
+    case OpStore:
+        if (basicTypeOp == OpTypeStruct) {
+            if (containsType(typeId, OpTypeInt, 8))
+                addCapability(CapabilityInt8);
+            if (containsType(typeId, OpTypeInt, 16))
+                addCapability(CapabilityInt16);
+            if (containsType(typeId, OpTypeFloat, 16))
+                addCapability(CapabilityFloat16);
+        } else {
+            StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
+            if (width == 8) {
+                switch (storageClass) {
+                case StorageClassUniform:
+                case StorageClassStorageBuffer:
+                case StorageClassPushConstant:
+                    break;
+                default:
+                    addCapability(CapabilityInt8);
+                    break;
+                }
+            } else if (width == 16) {
+                switch (storageClass) {
+                case StorageClassUniform:
+                case StorageClassStorageBuffer:
+                case StorageClassPushConstant:
+                case StorageClassInput:
+                case StorageClassOutput:
+                    break;
+                default:
+                    if (basicTypeOp == OpTypeInt)
+                        addCapability(CapabilityInt16);
+                    if (basicTypeOp == OpTypeFloat)
+                        addCapability(CapabilityFloat16);
+                    break;
+                }
+            }
+        }
+        break;
+    case OpAccessChain:
+    case OpPtrAccessChain:
+    case OpCopyObject:
+    case OpFConvert:
+    case OpSConvert:
+    case OpUConvert:
+        break;
+    default:
+        if (basicTypeOp == OpTypeFloat && width == 16)
+            addCapability(CapabilityFloat16);
+        if (basicTypeOp == OpTypeInt && width == 16)
+            addCapability(CapabilityInt16);
+        if (basicTypeOp == OpTypeInt && width == 8)
+            addCapability(CapabilityInt8);
+        break;
+    }
+}
+
 // Called for each instruction that resides in a block.
-void Builder::postProcess(Instruction& inst)
+void Builder::postProcess(const Instruction& inst)
 {
     // Add capabilities based simply on the opcode.
     switch (inst.getOpCode()) {
@@ -104,10 +174,22 @@ void Builder::postProcess(Instruction& inst)
     default:
         break;
     }
+
+    // Checks based on type
+    if (inst.getTypeId() != NoType)
+        postProcessType(inst, inst.getTypeId());
+    for (int op = 0; op < inst.getNumOperands(); ++op) {
+        if (inst.isIdOperand(op)) {
+            // In blocks, these are always result ids, but we are relying on
+            // getTypeId() to return NoType for things like OpLabel.
+            if (getTypeId(inst.getIdOperand(op)) != NoType)
+                postProcessType(inst, getTypeId(inst.getIdOperand(op)));
+        }
+    }
 }
 
 // Called for each instruction in a reachable block.
-void Builder::postProcessReachable(Instruction& inst)
+void Builder::postProcessReachable(const Instruction& inst)
 {
     // did have code here, but questionable to do so without deleting the instructions
 }
diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h
index 14d997dd8aaadfe598395f992dc69e19544049a4..2532b178b9657d1ddf7d2570b0751ba4d5e80390 100755
--- a/SPIRV/spvIR.h
+++ b/SPIRV/spvIR.h
@@ -127,7 +127,7 @@ public:
             addImmediateOperand(word);
         }
     }
-    bool isIdOperand(int op) { return idOperand[op]; }
+    bool isIdOperand(int op) const { return idOperand[op]; }
     void setBlock(Block* b) { block = b; }
     Block* getBlock() const { return block; }
     Op getOpCode() const { return opCode; }
diff --git a/Test/baseResults/spv.16bitstorage-int.frag.out b/Test/baseResults/spv.16bitstorage-int.frag.out
index 9de223cac5479e54b4177db15b371425fc5823c1..dd7d1b1c98c5c6a4cb1d6acc9d143b217104f647 100755
--- a/Test/baseResults/spv.16bitstorage-int.frag.out
+++ b/Test/baseResults/spv.16bitstorage-int.frag.out
@@ -4,7 +4,6 @@ spv.16bitstorage-int.frag
 // Id's are bound by 171
 
                               Capability Shader
-                              Capability Int16
                               Capability StorageUniformBufferBlock16
                               Capability StorageUniform16
                               Extension  "SPV_AMD_gpu_shader_int16"
diff --git a/Test/baseResults/spv.16bitstorage-uint.frag.out b/Test/baseResults/spv.16bitstorage-uint.frag.out
index def7c57e586104553589f788569a02ad5959b15f..3a13826f8a2ce6cf5ddae14edf02523e698b8613 100755
--- a/Test/baseResults/spv.16bitstorage-uint.frag.out
+++ b/Test/baseResults/spv.16bitstorage-uint.frag.out
@@ -4,7 +4,6 @@ spv.16bitstorage-uint.frag
 // Id's are bound by 173
 
                               Capability Shader
-                              Capability Int16
                               Capability StorageUniformBufferBlock16
                               Capability StorageUniform16
                               Extension  "SPV_AMD_gpu_shader_int16"
diff --git a/Test/baseResults/spv.16bitstorage.frag.out b/Test/baseResults/spv.16bitstorage.frag.out
index ebf48e9f4c41124da9e17323b56d0bd53eee695d..cf536e8be320ecffbd2ac92224e8dc12e27742f0 100755
--- a/Test/baseResults/spv.16bitstorage.frag.out
+++ b/Test/baseResults/spv.16bitstorage.frag.out
@@ -4,7 +4,6 @@ spv.16bitstorage.frag
 // Id's are bound by 173
 
                               Capability Shader
-                              Capability Float16
                               Capability StorageUniformBufferBlock16
                               Capability StorageUniform16
                               Extension  "SPV_AMD_gpu_shader_half_float"
diff --git a/Test/baseResults/spv.8bitstorage-int.frag.out b/Test/baseResults/spv.8bitstorage-int.frag.out
index 94e7ab5b01fbe1f76d31df95e5ef868637988b30..55a8b3bd708e3f393861f7903bcca20466fd6ed6 100755
--- a/Test/baseResults/spv.8bitstorage-int.frag.out
+++ b/Test/baseResults/spv.8bitstorage-int.frag.out
@@ -4,7 +4,6 @@ spv.8bitstorage-int.frag
 // Id's are bound by 171
 
                               Capability Shader
-                              Capability Int8
                               Capability CapabilityStorageBuffer8BitAccess
                               Capability CapabilityUniformAndStorageBuffer8BitAccess
                               Extension  "SPV_KHR_8bit_storage"
diff --git a/Test/baseResults/spv.8bitstorage-uint.frag.out b/Test/baseResults/spv.8bitstorage-uint.frag.out
index f4e7b6d679cf28a2c400783f2397ad56b84f9ddf..461cec4f30740c17a3a8f2301c97885b561a46f5 100755
--- a/Test/baseResults/spv.8bitstorage-uint.frag.out
+++ b/Test/baseResults/spv.8bitstorage-uint.frag.out
@@ -4,7 +4,6 @@ spv.8bitstorage-uint.frag
 // Id's are bound by 173
 
                               Capability Shader
-                              Capability Int8
                               Capability CapabilityStorageBuffer8BitAccess
                               Capability CapabilityUniformAndStorageBuffer8BitAccess
                               Extension  "SPV_KHR_8bit_storage"