layers: MR140, Add get_type_def helper in DrawState
diff --git a/layers/draw_state.cpp b/layers/draw_state.cpp
index 90285ae..2613ecc 100644
--- a/layers/draw_state.cpp
+++ b/layers/draw_state.cpp
@@ -195,6 +195,14 @@
     spirv_inst_iter end() const { return spirv_inst_iter(words.begin(), words.end()); }          /* just past last insn */
     /* given an offset into the module, produce an iterator there. */
     spirv_inst_iter at(unsigned offset) const { return spirv_inst_iter(words.begin(), words.begin() + offset); }
+
+    spirv_inst_iter get_type_def(unsigned type_id) const {
+        auto it = type_def_index.find(type_id);
+        if (it == type_def_index.end()) {
+            return end();
+        }
+        return at(it->second);
+    }
 };
 
 // TODO : Do we need to guard access to layer_data_map w/ lock?
@@ -400,40 +408,34 @@
 static char *
 describe_type(char *dst, shader_module const *src, unsigned type)
 {
-    auto type_def_it = src->type_def_index.find(type);
+    auto insn = src->get_type_def(type);
+    assert(insn != src->end());
 
-    if (type_def_it == src->type_def_index.end()) {
-        return dst + sprintf(dst, "undef");
-    }
-
-    unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
-    unsigned opcode = code[0] & 0x0ffffu;
-    switch (opcode) {
+    switch (insn.opcode()) {
         case spv::OpTypeBool:
             return dst + sprintf(dst, "bool");
         case spv::OpTypeInt:
-            return dst + sprintf(dst, "%cint%d", code[3] ? 's' : 'u', code[2]);
+            return dst + sprintf(dst, "%cint%d", insn.word(3) ? 's' : 'u', insn.word(2));
         case spv::OpTypeFloat:
-            return dst + sprintf(dst, "float%d", code[2]);
+            return dst + sprintf(dst, "float%d", insn.word(2));
         case spv::OpTypeVector:
-            dst += sprintf(dst, "vec%d of ", code[3]);
-            return describe_type(dst, src, code[2]);
+            dst += sprintf(dst, "vec%d of ", insn.word(3));
+            return describe_type(dst, src, insn.word(2));
         case spv::OpTypeMatrix:
-            dst += sprintf(dst, "mat%d of ", code[3]);
-            return describe_type(dst, src, code[2]);
+            dst += sprintf(dst, "mat%d of ", insn.word(3));
+            return describe_type(dst, src, insn.word(2));
         case spv::OpTypeArray:
-            dst += sprintf(dst, "arr[%d] of ", code[3]);
-            return describe_type(dst, src, code[2]);
+            dst += sprintf(dst, "arr[%d] of ", insn.word(3));
+            return describe_type(dst, src, insn.word(2));
         case spv::OpTypePointer:
-            dst += sprintf(dst, "ptr to %s ", storage_class_name(code[2]));
-            return describe_type(dst, src, code[3]);
+            dst += sprintf(dst, "ptr to %s ", storage_class_name(insn.word(2)));
+            return describe_type(dst, src, insn.word(3));
         case spv::OpTypeStruct:
             {
-                unsigned oplen = code[0] >> 16;
                 dst += sprintf(dst, "struct of (");
-                for (unsigned i = 2; i < oplen; i++) {
-                    dst = describe_type(dst, src, code[i]);
-                    dst += sprintf(dst, i == oplen-1 ? ")" : ", ");
+                for (unsigned i = 2; i < insn.len(); i++) {
+                    dst = describe_type(dst, src, insn.word(i));
+                    dst += sprintf(dst, i == insn.len()-1 ? ")" : ", ");
                 }
                 return dst;
             }
@@ -447,49 +449,37 @@
 static bool
 types_match(shader_module const *a, shader_module const *b, unsigned a_type, unsigned b_type, bool b_arrayed)
 {
-    auto a_type_def_it = a->type_def_index.find(a_type);
-    auto b_type_def_it = b->type_def_index.find(b_type);
-
-    if (a_type_def_it == a->type_def_index.end()) {
-        return false;
-    }
-
-    if (b_type_def_it == b->type_def_index.end()) {
-        return false;
-    }
-
     /* walk two type trees together, and complain about differences */
-    unsigned int const *a_code = (unsigned int const *)&a->words[a_type_def_it->second];
-    unsigned int const *b_code = (unsigned int const *)&b->words[b_type_def_it->second];
+    auto a_insn = a->get_type_def(a_type);
+    auto b_insn = b->get_type_def(b_type);
+    assert(a_insn != a->end());
+    assert(b_insn != b->end());
 
-    unsigned a_opcode = a_code[0] & 0x0ffffu;
-    unsigned b_opcode = b_code[0] & 0x0ffffu;
-
-    if (b_arrayed && b_opcode == spv::OpTypeArray) {
+    if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
         /* we probably just found the extra level of arrayness in b_type: compare the type inside it to a_type */
-        return types_match(a, b, a_type, b_code[2], false);
+        return types_match(a, b, a_type, b_insn.word(2), false);
     }
 
-    if (a_opcode != b_opcode) {
+    if (a_insn.opcode() != b_insn.opcode()) {
         return false;
     }
 
-    switch (a_opcode) {
+    switch (a_insn.opcode()) {
         /* if b_arrayed and we hit a leaf type, then we can't match -- there's nowhere for the extra OpTypeArray to be! */
         case spv::OpTypeBool:
             return true && !b_arrayed;
         case spv::OpTypeInt:
             /* match on width, signedness */
-            return a_code[2] == b_code[2] && a_code[3] == b_code[3] && !b_arrayed;
+            return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3) && !b_arrayed;
         case spv::OpTypeFloat:
             /* match on width */
-            return a_code[2] == b_code[2] && !b_arrayed;
+            return a_insn.word(2) == b_insn.word(2) && !b_arrayed;
         case spv::OpTypeVector:
         case spv::OpTypeMatrix:
         case spv::OpTypeArray:
             /* match on element type, count. these all have the same layout. we don't get here if
              * b_arrayed -- that is handled above. */
-            return !b_arrayed && types_match(a, b, a_code[2], b_code[2], b_arrayed) && a_code[3] == b_code[3];
+            return !b_arrayed && types_match(a, b, a_insn.word(2), b_insn.word(2), b_arrayed) && a_insn.word(3) == b_insn.word(3);
         case spv::OpTypeStruct:
             /* match on all element types */
             {
@@ -498,15 +488,12 @@
                     return false;
                 }
 
-                unsigned a_len = a_code[0] >> 16;
-                unsigned b_len = b_code[0] >> 16;
-
-                if (a_len != b_len) {
+                if (a_insn.len() != b_insn.len()) {
                     return false;   /* structs cannot match if member counts differ */
                 }
 
-                for (unsigned i = 2; i < a_len; i++) {
-                    if (!types_match(a, b, a_code[i], b_code[i], b_arrayed)) {
+                for (unsigned i = 2; i < a_insn.len(); i++) {
+                    if (!types_match(a, b, a_insn.word(i), b_insn.word(i), b_arrayed)) {
                         return false;
                     }
                 }
@@ -515,7 +502,7 @@
             }
         case spv::OpTypePointer:
             /* match on pointee type. storage class is expected to differ */
-            return types_match(a, b, a_code[3], b_code[3], b_arrayed);
+            return types_match(a, b, a_insn.word(3), b_insn.word(3), b_arrayed);
 
         default:
             /* remaining types are CLisms, or may not appear in the interfaces we
@@ -540,13 +527,8 @@
 static unsigned
 get_locations_consumed_by_type(shader_module const *src, unsigned type, bool strip_array_level)
 {
-    auto type_def_it = src->type_def_index.find(type);
-
-    if (type_def_it == src->type_def_index.end()) {
-        return 1;       /* This is actually broken SPIR-V... */
-    }
-
-    auto insn = src->at(type_def_it->second);
+    auto insn = src->get_type_def(type);
+    assert(insn != src->end());
 
     switch (insn.opcode()) {
         case spv::OpTypePointer:
@@ -592,26 +574,19 @@
                                 uint32_t type_id)
 {
     /* Walk down the type_id presented, trying to determine whether it's actually an interface block. */
-    std::unordered_map<unsigned, unsigned>::const_iterator type_def_it;
+    auto type = src->get_type_def(type_id);
+
     while (true) {
 
-        type_def_it = src->type_def_index.find(type_id);
-        if (type_def_it == src->type_def_index.end()) {
-            return; /* this is actually broken SPIR-V */
+        if (type.opcode() == spv::OpTypePointer) {
+            type = src->get_type_def(type.word(3));
         }
-
-        unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
-        unsigned opcode = code[0] & 0x0ffffu;
-
-        if (opcode == spv::OpTypePointer) {
-            type_id = code[3];
-        }
-        else if (opcode == spv::OpTypeArray && is_array_of_verts) {
-            type_id = code[2];
+        else if (type.opcode() == spv::OpTypeArray && is_array_of_verts) {
+            type = src->get_type_def(type.word(2));
             is_array_of_verts = false;
         }
-        else if (opcode == spv::OpTypeStruct) {
-            if (blocks.find(type_id) == blocks.end()) {
+        else if (type.opcode() == spv::OpTypeStruct) {
+            if (blocks.find(type.word(1)) == blocks.end()) {
                 /* This isn't an interface block. */
                 return;
             }
@@ -626,11 +601,11 @@
         }
     }
 
-    /* Walk OpMemberDecorate for type_id. */
+    /* Walk all the OpMemberDecorate for type's result id. */
     for (auto insn : *src) {
-        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type_id) {
+        if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
             unsigned member_index = insn.word(2);
-            unsigned member_type_id = src->at(type_def_it->second).word(2 + member_index);
+            unsigned member_type_id = type.word(2 + member_index);
 
             if (insn.word(3) == spv::DecorationLocation) {
                 unsigned location = insn.word(4);
@@ -906,27 +881,22 @@
 static unsigned
 get_fundamental_type(shader_module const *src, unsigned type)
 {
-    auto type_def_it = src->type_def_index.find(type);
+    auto insn = src->get_type_def(type);
+    assert(insn != src->end());
 
-    if (type_def_it == src->type_def_index.end()) {
-        return FORMAT_TYPE_UNDEFINED;
-    }
-
-    unsigned int const *code = (unsigned int const *)&src->words[type_def_it->second];
-    unsigned opcode = code[0] & 0x0ffffu;
-    switch (opcode) {
+    switch (insn.opcode()) {
         case spv::OpTypeInt:
-            return code[3] ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
+            return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
         case spv::OpTypeFloat:
             return FORMAT_TYPE_FLOAT;
         case spv::OpTypeVector:
-            return get_fundamental_type(src, code[2]);
+            return get_fundamental_type(src, insn.word(2));
         case spv::OpTypeMatrix:
-            return get_fundamental_type(src, code[2]);
+            return get_fundamental_type(src, insn.word(2));
         case spv::OpTypeArray:
-            return get_fundamental_type(src, code[2]);
+            return get_fundamental_type(src, insn.word(2));
         case spv::OpTypePointer:
-            return get_fundamental_type(src, code[3]);
+            return get_fundamental_type(src, insn.word(3));
         default:
             return FORMAT_TYPE_UNDEFINED;
     }
@@ -1042,7 +1012,6 @@
      * are currently dense, but the parallel with matching between shader stages is nice.
      */
 
-    /* TODO: Figure out compile error with cb->attachmentCount */
     while ((outputs.size() > 0 && it != outputs.end()) || attachment < color_formats.size()) {
         if (attachment == color_formats.size() || ( it != outputs.end() && it->first < attachment)) {
             if (log_msg(my_data->report_data, VK_DEBUG_REPORT_WARN_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, /*dev*/0, __LINE__, SHADER_CHECKER_OUTPUT_NOT_CONSUMED, "SC",