Add new test case for image functions and fix issues caught by this test
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 0154913..72292e6 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -1757,11 +1757,10 @@
             break;
         }
 
-        if (lvalue) {
+        if (lvalue)
             arguments.push_back(builder.accessChainGetLValue());
-        } else {
+        else
             arguments.push_back(builder.accessChainLoad(convertGlslangToSpvType(glslangArguments[i]->getAsTyped()->getType())));
-        }
     }
 }
 
@@ -1820,16 +1819,37 @@
 
     // Check for image functions other than queries
     if (node->isImage()) {
-        if (node->getOp() == glslang::EOpImageLoad) {
-            return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), arguments);
-        }
-        else if (node->getOp() == glslang::EOpImageStore) {
-            builder.createNoResultOp(spv::OpImageWrite, arguments);
-            return spv::NoResult;
-        }
-        else {
-            // Process image atomic operations. GLSL "IMAGE_PARAMS" will involve in constructing an image texel
-            // pointer and this pointer, as the first source operand, is required by SPIR-V atomic operations.
+        // Process image load/store
+        if (node->getOp() == glslang::EOpImageLoad ||
+            node->getOp() == glslang::EOpImageStore) {
+            std::vector<spv::Id> operands;
+            auto opIt = arguments.begin();
+            operands.push_back(*(opIt++));
+            operands.push_back(*(opIt++));
+            if (sampler.ms) {
+                // For MS, image operand mask has to be added to indicate the presence of "sample" operand.
+                spv::Id sample = *(opIt++);
+                for (; opIt != arguments.end(); ++opIt)
+                    operands.push_back(*opIt);
+
+                operands.push_back(spv::ImageOperandsSampleMask);
+                operands.push_back(sample);
+            } else {
+                for (; opIt != arguments.end(); ++opIt)
+                    operands.push_back(*opIt);
+            }
+
+            if (node->getOp() == glslang::EOpImageLoad)
+                return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
+            else {
+                builder.createNoResultOp(spv::OpImageWrite, operands);
+                return spv::NoResult;
+            }
+        } else {
+            // Process image atomic operations
+
+            // GLSL "IMAGE_PARAMS" will involve in constructing an image texel pointer and this pointer,
+            // as the first source operand, is required by SPIR-V atomic operations.
             std::vector<spv::Id> imageParams;
             auto opIt = arguments.begin();
             imageParams.push_back(*(opIt++));
@@ -1885,8 +1905,8 @@
     if (cracked.lod) {
         params.lod = arguments[2];
         ++extraArgs;
-    } else if (cracked.sample) {
-        params.sample = arguments[2]; // For MS, sample should be specified
+    } else if (sampler.ms) {
+        params.sample = arguments[2]; // For MS, "sample" should be specified
         ++extraArgs;
     }
     if (cracked.grad) {
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index cefe7aa..336aa24 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -159,8 +159,9 @@
     }
     Id getImageType(Id resultId) const
     {
-        assert(isSampledImageType(getTypeId(resultId)));
-        return module.getInstruction(getTypeId(resultId))->getIdOperand(0);
+        Id typeId = getTypeId(resultId);
+        assert(isImageType(typeId) || isSampledImageType(typeId));
+        return isSampledImageType(typeId) ? module.getInstruction(typeId)->getIdOperand(0) : typeId;
     }
     bool isArrayedImageType(Id typeId) const
     {
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index ff0d780..ccc163d 100755
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -1635,10 +1635,12 @@
 
     InstructionDesc[OpImageRead].operands.push(OperandId, "'Image'");
     InstructionDesc[OpImageRead].operands.push(OperandId, "'Coordinate'");
+    InstructionDesc[OpImageRead].operands.push(OperandOptionalImage, "");
 
     InstructionDesc[OpImageWrite].operands.push(OperandId, "'Image'");
     InstructionDesc[OpImageWrite].operands.push(OperandId, "'Coordinate'");
     InstructionDesc[OpImageWrite].operands.push(OperandId, "'Texel'");
+    InstructionDesc[OpImageWrite].operands.push(OperandOptionalImage, "");
 
     InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Sampled Image'");
     InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Coordinate'");