Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2017 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // Validates correctness of image instructions.
     16 
     17 #include "source/val/validate.h"
     18 
     19 #include <string>
     20 
     21 #include "source/diagnostic.h"
     22 #include "source/opcode.h"
     23 #include "source/spirv_target_env.h"
     24 #include "source/util/bitutils.h"
     25 #include "source/val/instruction.h"
     26 #include "source/val/validate_scopes.h"
     27 #include "source/val/validation_state.h"
     28 
     29 namespace spvtools {
     30 namespace val {
     31 namespace {
     32 
     33 // Performs compile time check that all SpvImageOperandsXXX cases are handled in
     34 // this module. If SpvImageOperandsXXX list changes, this function will fail the
     35 // build.
     36 // For all other purposes this is a dummy function.
     37 bool CheckAllImageOperandsHandled() {
     38   SpvImageOperandsMask enum_val = SpvImageOperandsBiasMask;
     39 
     40   // Some improvised code to prevent the compiler from considering enum_val
     41   // constant and optimizing the switch away.
     42   uint32_t stack_var = 0;
     43   if (reinterpret_cast<uintptr_t>(&stack_var) % 256)
     44     enum_val = SpvImageOperandsLodMask;
     45 
     46   switch (enum_val) {
     47     // Please update the validation rules in this module if you are changing
     48     // the list of image operands, and add new enum values to this switch.
     49     case SpvImageOperandsMaskNone:
     50       return false;
     51     case SpvImageOperandsBiasMask:
     52     case SpvImageOperandsLodMask:
     53     case SpvImageOperandsGradMask:
     54     case SpvImageOperandsConstOffsetMask:
     55     case SpvImageOperandsOffsetMask:
     56     case SpvImageOperandsConstOffsetsMask:
     57     case SpvImageOperandsSampleMask:
     58     case SpvImageOperandsMinLodMask:
     59 
     60     // TODO(dneto): Support image operands related to the Vulkan memory model.
     61     // https://gitlab.khronos.org/spirv/spirv-tools/issues/32
     62     case SpvImageOperandsMakeTexelAvailableKHRMask:
     63     case SpvImageOperandsMakeTexelVisibleKHRMask:
     64     case SpvImageOperandsNonPrivateTexelKHRMask:
     65     case SpvImageOperandsVolatileTexelKHRMask:
     66       return true;
     67   }
     68   return false;
     69 }
     70 
     71 // Used by GetImageTypeInfo. See OpTypeImage spec for more information.
     72 struct ImageTypeInfo {
     73   uint32_t sampled_type = 0;
     74   SpvDim dim = SpvDimMax;
     75   uint32_t depth = 0;
     76   uint32_t arrayed = 0;
     77   uint32_t multisampled = 0;
     78   uint32_t sampled = 0;
     79   SpvImageFormat format = SpvImageFormatMax;
     80   SpvAccessQualifier access_qualifier = SpvAccessQualifierMax;
     81 };
     82 
     83 // Provides information on image type. |id| should be object of either
     84 // OpTypeImage or OpTypeSampledImage type. Returns false in case of failure
     85 // (not a valid id, failed to parse the instruction, etc).
     86 bool GetImageTypeInfo(const ValidationState_t& _, uint32_t id,
     87                       ImageTypeInfo* info) {
     88   if (!id || !info) return false;
     89 
     90   const Instruction* inst = _.FindDef(id);
     91   assert(inst);
     92 
     93   if (inst->opcode() == SpvOpTypeSampledImage) {
     94     inst = _.FindDef(inst->word(2));
     95     assert(inst);
     96   }
     97 
     98   if (inst->opcode() != SpvOpTypeImage) return false;
     99 
    100   const size_t num_words = inst->words().size();
    101   if (num_words != 9 && num_words != 10) return false;
    102 
    103   info->sampled_type = inst->word(2);
    104   info->dim = static_cast<SpvDim>(inst->word(3));
    105   info->depth = inst->word(4);
    106   info->arrayed = inst->word(5);
    107   info->multisampled = inst->word(6);
    108   info->sampled = inst->word(7);
    109   info->format = static_cast<SpvImageFormat>(inst->word(8));
    110   info->access_qualifier = num_words < 10
    111                                ? SpvAccessQualifierMax
    112                                : static_cast<SpvAccessQualifier>(inst->word(9));
    113   return true;
    114 }
    115 
    116 bool IsImplicitLod(SpvOp opcode) {
    117   switch (opcode) {
    118     case SpvOpImageSampleImplicitLod:
    119     case SpvOpImageSampleDrefImplicitLod:
    120     case SpvOpImageSampleProjImplicitLod:
    121     case SpvOpImageSampleProjDrefImplicitLod:
    122     case SpvOpImageSparseSampleImplicitLod:
    123     case SpvOpImageSparseSampleDrefImplicitLod:
    124     case SpvOpImageSparseSampleProjImplicitLod:
    125     case SpvOpImageSparseSampleProjDrefImplicitLod:
    126       return true;
    127     default:
    128       break;
    129   }
    130   return false;
    131 }
    132 
    133 bool IsExplicitLod(SpvOp opcode) {
    134   switch (opcode) {
    135     case SpvOpImageSampleExplicitLod:
    136     case SpvOpImageSampleDrefExplicitLod:
    137     case SpvOpImageSampleProjExplicitLod:
    138     case SpvOpImageSampleProjDrefExplicitLod:
    139     case SpvOpImageSparseSampleExplicitLod:
    140     case SpvOpImageSparseSampleDrefExplicitLod:
    141     case SpvOpImageSparseSampleProjExplicitLod:
    142     case SpvOpImageSparseSampleProjDrefExplicitLod:
    143       return true;
    144     default:
    145       break;
    146   }
    147   return false;
    148 }
    149 
    150 // Returns true if the opcode is a Image instruction which applies
    151 // homogenous projection to the coordinates.
    152 bool IsProj(SpvOp opcode) {
    153   switch (opcode) {
    154     case SpvOpImageSampleProjImplicitLod:
    155     case SpvOpImageSampleProjDrefImplicitLod:
    156     case SpvOpImageSparseSampleProjImplicitLod:
    157     case SpvOpImageSparseSampleProjDrefImplicitLod:
    158     case SpvOpImageSampleProjExplicitLod:
    159     case SpvOpImageSampleProjDrefExplicitLod:
    160     case SpvOpImageSparseSampleProjExplicitLod:
    161     case SpvOpImageSparseSampleProjDrefExplicitLod:
    162       return true;
    163     default:
    164       break;
    165   }
    166   return false;
    167 }
    168 
    169 // Returns the number of components in a coordinate used to access a texel in
    170 // a single plane of an image with the given parameters.
    171 uint32_t GetPlaneCoordSize(const ImageTypeInfo& info) {
    172   uint32_t plane_size = 0;
    173   // If this switch breaks your build, please add new values below.
    174   switch (info.dim) {
    175     case SpvDim1D:
    176     case SpvDimBuffer:
    177       plane_size = 1;
    178       break;
    179     case SpvDim2D:
    180     case SpvDimRect:
    181     case SpvDimSubpassData:
    182       plane_size = 2;
    183       break;
    184     case SpvDim3D:
    185     case SpvDimCube:
    186       // For Cube direction vector is used instead of UV.
    187       plane_size = 3;
    188       break;
    189     case SpvDimMax:
    190       assert(0);
    191       break;
    192   }
    193 
    194   return plane_size;
    195 }
    196 
    197 // Returns minimal number of coordinates based on image dim, arrayed and whether
    198 // the instruction uses projection coordinates.
    199 uint32_t GetMinCoordSize(SpvOp opcode, const ImageTypeInfo& info) {
    200   if (info.dim == SpvDimCube &&
    201       (opcode == SpvOpImageRead || opcode == SpvOpImageWrite ||
    202        opcode == SpvOpImageSparseRead)) {
    203     // These opcodes use UV for Cube, not direction vector.
    204     return 3;
    205   }
    206 
    207   return GetPlaneCoordSize(info) + info.arrayed + (IsProj(opcode) ? 1 : 0);
    208 }
    209 
    210 // Checks ImageOperand bitfield and respective operands.
    211 spv_result_t ValidateImageOperands(ValidationState_t& _,
    212                                    const Instruction* inst,
    213                                    const ImageTypeInfo& info, uint32_t mask,
    214                                    uint32_t word_index) {
    215   static const bool kAllImageOperandsHandled = CheckAllImageOperandsHandled();
    216   (void)kAllImageOperandsHandled;
    217 
    218   const SpvOp opcode = inst->opcode();
    219   const size_t num_words = inst->words().size();
    220 
    221   // NonPrivate and Volatile take no operand words.
    222   const uint32_t mask_bits_having_operands =
    223       mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
    224                        SpvImageOperandsVolatileTexelKHRMask);
    225   size_t expected_num_image_operand_words =
    226       spvtools::utils::CountSetBits(mask_bits_having_operands);
    227   if (mask & SpvImageOperandsGradMask) {
    228     // Grad uses two words.
    229     ++expected_num_image_operand_words;
    230   }
    231 
    232   if (expected_num_image_operand_words != num_words - word_index) {
    233     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    234            << "Number of image operand ids doesn't correspond to the bit mask";
    235   }
    236 
    237   if (spvtools::utils::CountSetBits(
    238           mask & (SpvImageOperandsOffsetMask | SpvImageOperandsConstOffsetMask |
    239                   SpvImageOperandsConstOffsetsMask)) > 1) {
    240     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    241            << "Image Operands Offset, ConstOffset, ConstOffsets cannot be used "
    242            << "together";
    243   }
    244 
    245   const bool is_implicit_lod = IsImplicitLod(opcode);
    246   const bool is_explicit_lod = IsExplicitLod(opcode);
    247 
    248   // The checks should be done in the order of definition of OperandImage.
    249 
    250   if (mask & SpvImageOperandsBiasMask) {
    251     if (!is_implicit_lod) {
    252       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    253              << "Image Operand Bias can only be used with ImplicitLod opcodes";
    254     }
    255 
    256     const uint32_t type_id = _.GetTypeId(inst->word(word_index++));
    257     if (!_.IsFloatScalarType(type_id)) {
    258       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    259              << "Expected Image Operand Bias to be float scalar";
    260     }
    261 
    262     if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
    263         info.dim != SpvDimCube) {
    264       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    265              << "Image Operand Bias requires 'Dim' parameter to be 1D, 2D, 3D "
    266                 "or Cube";
    267     }
    268 
    269     if (info.multisampled != 0) {
    270       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    271              << "Image Operand Bias requires 'MS' parameter to be 0";
    272     }
    273   }
    274 
    275   if (mask & SpvImageOperandsLodMask) {
    276     if (!is_explicit_lod && opcode != SpvOpImageFetch &&
    277         opcode != SpvOpImageSparseFetch) {
    278       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    279              << "Image Operand Lod can only be used with ExplicitLod opcodes "
    280              << "and OpImageFetch";
    281     }
    282 
    283     if (mask & SpvImageOperandsGradMask) {
    284       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    285              << "Image Operand bits Lod and Grad cannot be set at the same "
    286                 "time";
    287     }
    288 
    289     const uint32_t type_id = _.GetTypeId(inst->word(word_index++));
    290     if (is_explicit_lod) {
    291       if (!_.IsFloatScalarType(type_id)) {
    292         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    293                << "Expected Image Operand Lod to be float scalar when used "
    294                << "with ExplicitLod";
    295       }
    296     } else {
    297       if (!_.IsIntScalarType(type_id)) {
    298         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    299                << "Expected Image Operand Lod to be int scalar when used with "
    300                << "OpImageFetch";
    301       }
    302     }
    303 
    304     if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
    305         info.dim != SpvDimCube) {
    306       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    307              << "Image Operand Lod requires 'Dim' parameter to be 1D, 2D, 3D "
    308                 "or Cube";
    309     }
    310 
    311     if (info.multisampled != 0) {
    312       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    313              << "Image Operand Lod requires 'MS' parameter to be 0";
    314     }
    315   }
    316 
    317   if (mask & SpvImageOperandsGradMask) {
    318     if (!is_explicit_lod) {
    319       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    320              << "Image Operand Grad can only be used with ExplicitLod opcodes";
    321     }
    322 
    323     const uint32_t dx_type_id = _.GetTypeId(inst->word(word_index++));
    324     const uint32_t dy_type_id = _.GetTypeId(inst->word(word_index++));
    325     if (!_.IsFloatScalarOrVectorType(dx_type_id) ||
    326         !_.IsFloatScalarOrVectorType(dy_type_id)) {
    327       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    328              << "Expected both Image Operand Grad ids to be float scalars or "
    329              << "vectors";
    330     }
    331 
    332     const uint32_t plane_size = GetPlaneCoordSize(info);
    333     const uint32_t dx_size = _.GetDimension(dx_type_id);
    334     const uint32_t dy_size = _.GetDimension(dy_type_id);
    335     if (plane_size != dx_size) {
    336       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    337              << "Expected Image Operand Grad dx to have " << plane_size
    338              << " components, but given " << dx_size;
    339     }
    340 
    341     if (plane_size != dy_size) {
    342       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    343              << "Expected Image Operand Grad dy to have " << plane_size
    344              << " components, but given " << dy_size;
    345     }
    346 
    347     if (info.multisampled != 0) {
    348       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    349              << "Image Operand Grad requires 'MS' parameter to be 0";
    350     }
    351   }
    352 
    353   if (mask & SpvImageOperandsConstOffsetMask) {
    354     if (info.dim == SpvDimCube) {
    355       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    356              << "Image Operand ConstOffset cannot be used with Cube Image "
    357                 "'Dim'";
    358     }
    359 
    360     const uint32_t id = inst->word(word_index++);
    361     const uint32_t type_id = _.GetTypeId(id);
    362     if (!_.IsIntScalarOrVectorType(type_id)) {
    363       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    364              << "Expected Image Operand ConstOffset to be int scalar or "
    365              << "vector";
    366     }
    367 
    368     if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) {
    369       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    370              << "Expected Image Operand ConstOffset to be a const object";
    371     }
    372 
    373     const uint32_t plane_size = GetPlaneCoordSize(info);
    374     const uint32_t offset_size = _.GetDimension(type_id);
    375     if (plane_size != offset_size) {
    376       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    377              << "Expected Image Operand ConstOffset to have " << plane_size
    378              << " components, but given " << offset_size;
    379     }
    380   }
    381 
    382   if (mask & SpvImageOperandsOffsetMask) {
    383     if (info.dim == SpvDimCube) {
    384       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    385              << "Image Operand Offset cannot be used with Cube Image 'Dim'";
    386     }
    387 
    388     const uint32_t id = inst->word(word_index++);
    389     const uint32_t type_id = _.GetTypeId(id);
    390     if (!_.IsIntScalarOrVectorType(type_id)) {
    391       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    392              << "Expected Image Operand Offset to be int scalar or "
    393              << "vector";
    394     }
    395 
    396     const uint32_t plane_size = GetPlaneCoordSize(info);
    397     const uint32_t offset_size = _.GetDimension(type_id);
    398     if (plane_size != offset_size) {
    399       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    400              << "Expected Image Operand Offset to have " << plane_size
    401              << " components, but given " << offset_size;
    402     }
    403   }
    404 
    405   if (mask & SpvImageOperandsConstOffsetsMask) {
    406     if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather &&
    407         opcode != SpvOpImageSparseGather &&
    408         opcode != SpvOpImageSparseDrefGather) {
    409       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    410              << "Image Operand ConstOffsets can only be used with "
    411                 "OpImageGather and OpImageDrefGather";
    412     }
    413 
    414     if (info.dim == SpvDimCube) {
    415       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    416              << "Image Operand ConstOffsets cannot be used with Cube Image "
    417                 "'Dim'";
    418     }
    419 
    420     const uint32_t id = inst->word(word_index++);
    421     const uint32_t type_id = _.GetTypeId(id);
    422     const Instruction* type_inst = _.FindDef(type_id);
    423     assert(type_inst);
    424 
    425     if (type_inst->opcode() != SpvOpTypeArray) {
    426       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    427              << "Expected Image Operand ConstOffsets to be an array of size 4";
    428     }
    429 
    430     uint64_t array_size = 0;
    431     if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) {
    432       assert(0 && "Array type definition is corrupt");
    433     }
    434 
    435     if (array_size != 4) {
    436       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    437              << "Expected Image Operand ConstOffsets to be an array of size 4";
    438     }
    439 
    440     const uint32_t component_type = type_inst->word(2);
    441     if (!_.IsIntVectorType(component_type) ||
    442         _.GetDimension(component_type) != 2) {
    443       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    444              << "Expected Image Operand ConstOffsets array componenets to be "
    445                 "int vectors of size 2";
    446     }
    447 
    448     if (!spvOpcodeIsConstant(_.GetIdOpcode(id))) {
    449       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    450              << "Expected Image Operand ConstOffsets to be a const object";
    451     }
    452   }
    453 
    454   if (mask & SpvImageOperandsSampleMask) {
    455     if (opcode != SpvOpImageFetch && opcode != SpvOpImageRead &&
    456         opcode != SpvOpImageWrite && opcode != SpvOpImageSparseFetch &&
    457         opcode != SpvOpImageSparseRead) {
    458       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    459              << "Image Operand Sample can only be used with OpImageFetch, "
    460              << "OpImageRead, OpImageWrite, OpImageSparseFetch and "
    461              << "OpImageSparseRead";
    462     }
    463 
    464     if (info.multisampled == 0) {
    465       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    466              << "Image Operand Sample requires non-zero 'MS' parameter";
    467     }
    468 
    469     const uint32_t type_id = _.GetTypeId(inst->word(word_index++));
    470     if (!_.IsIntScalarType(type_id)) {
    471       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    472              << "Expected Image Operand Sample to be int scalar";
    473     }
    474   }
    475 
    476   if (mask & SpvImageOperandsMinLodMask) {
    477     if (!is_implicit_lod && !(mask & SpvImageOperandsGradMask)) {
    478       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    479              << "Image Operand MinLod can only be used with ImplicitLod "
    480              << "opcodes or together with Image Operand Grad";
    481     }
    482 
    483     const uint32_t type_id = _.GetTypeId(inst->word(word_index++));
    484     if (!_.IsFloatScalarType(type_id)) {
    485       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    486              << "Expected Image Operand MinLod to be float scalar";
    487     }
    488 
    489     if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
    490         info.dim != SpvDimCube) {
    491       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    492              << "Image Operand MinLod requires 'Dim' parameter to be 1D, 2D, "
    493                 "3D or Cube";
    494     }
    495 
    496     if (info.multisampled != 0) {
    497       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    498              << "Image Operand MinLod requires 'MS' parameter to be 0";
    499     }
    500   }
    501 
    502   if (mask & SpvImageOperandsMakeTexelAvailableKHRMask) {
    503     // Checked elsewhere: capability and memory model are correct.
    504     if (opcode != SpvOpImageWrite) {
    505       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    506              << "Image Operand MakeTexelAvailableKHR can only be used with Op"
    507              << spvOpcodeString(SpvOpImageWrite) << ": Op"
    508              << spvOpcodeString(opcode);
    509     }
    510 
    511     if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) {
    512       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    513              << "Image Operand MakeTexelAvailableKHR requires "
    514                 "NonPrivateTexelKHR is also specified: Op"
    515              << spvOpcodeString(opcode);
    516     }
    517 
    518     const auto available_scope = inst->word(word_index++);
    519     if (auto error = ValidateMemoryScope(_, inst, available_scope))
    520       return error;
    521   }
    522 
    523   if (mask & SpvImageOperandsMakeTexelVisibleKHRMask) {
    524     // Checked elsewhere: capability and memory model are correct.
    525     if (opcode != SpvOpImageRead && opcode != SpvOpImageSparseRead) {
    526       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    527              << "Image Operand MakeTexelVisibleKHR can only be used with Op"
    528              << spvOpcodeString(SpvOpImageRead) << " or Op"
    529              << spvOpcodeString(SpvOpImageSparseRead) << ": Op"
    530              << spvOpcodeString(opcode);
    531     }
    532 
    533     if (!(mask & SpvImageOperandsNonPrivateTexelKHRMask)) {
    534       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    535              << "Image Operand MakeTexelVisibleKHR requires NonPrivateTexelKHR "
    536                 "is also specified: Op"
    537              << spvOpcodeString(opcode);
    538     }
    539 
    540     const auto visible_scope = inst->word(word_index++);
    541     if (auto error = ValidateMemoryScope(_, inst, visible_scope)) return error;
    542   }
    543 
    544   return SPV_SUCCESS;
    545 }
    546 
    547 // Checks some of the validation rules which are common to multiple opcodes.
    548 spv_result_t ValidateImageCommon(ValidationState_t& _, const Instruction* inst,
    549                                  const ImageTypeInfo& info) {
    550   const SpvOp opcode = inst->opcode();
    551   if (IsProj(opcode)) {
    552     if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
    553         info.dim != SpvDimRect) {
    554       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    555              << "Expected Image 'Dim' parameter to be 1D, 2D, 3D or Rect";
    556     }
    557 
    558     if (info.multisampled != 0) {
    559       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    560              << "Image Image 'MS' parameter to be 0";
    561     }
    562 
    563     if (info.arrayed != 0) {
    564       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    565              << "Image Image 'arrayed' parameter to be 0";
    566     }
    567   }
    568 
    569   if (opcode == SpvOpImageRead || opcode == SpvOpImageSparseRead ||
    570       opcode == SpvOpImageWrite) {
    571     if (info.sampled == 0) {
    572     } else if (info.sampled == 2) {
    573       if (info.dim == SpvDim1D && !_.HasCapability(SpvCapabilityImage1D)) {
    574         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    575                << "Capability Image1D is required to access storage image";
    576       } else if (info.dim == SpvDimRect &&
    577                  !_.HasCapability(SpvCapabilityImageRect)) {
    578         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    579                << "Capability ImageRect is required to access storage image";
    580       } else if (info.dim == SpvDimBuffer &&
    581                  !_.HasCapability(SpvCapabilityImageBuffer)) {
    582         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    583                << "Capability ImageBuffer is required to access storage image";
    584       } else if (info.dim == SpvDimCube && info.arrayed == 1 &&
    585                  !_.HasCapability(SpvCapabilityImageCubeArray)) {
    586         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    587                << "Capability ImageCubeArray is required to access "
    588                << "storage image";
    589       }
    590 
    591       if (info.multisampled == 1 &&
    592           !_.HasCapability(SpvCapabilityImageMSArray)) {
    593 #if 0
    594         // TODO(atgoo (at) github.com) The description of this rule in the spec
    595         // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify
    596         // and reenable.
    597         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    598             << "Capability ImageMSArray is required to access storage "
    599             << "image";
    600 #endif
    601       }
    602     } else {
    603       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    604              << "Expected Image 'Sampled' parameter to be 0 or 2";
    605     }
    606   }
    607 
    608   return SPV_SUCCESS;
    609 }
    610 
    611 // Returns true if opcode is *ImageSparse*, false otherwise.
    612 bool IsSparse(SpvOp opcode) {
    613   switch (opcode) {
    614     case SpvOpImageSparseSampleImplicitLod:
    615     case SpvOpImageSparseSampleExplicitLod:
    616     case SpvOpImageSparseSampleDrefImplicitLod:
    617     case SpvOpImageSparseSampleDrefExplicitLod:
    618     case SpvOpImageSparseSampleProjImplicitLod:
    619     case SpvOpImageSparseSampleProjExplicitLod:
    620     case SpvOpImageSparseSampleProjDrefImplicitLod:
    621     case SpvOpImageSparseSampleProjDrefExplicitLod:
    622     case SpvOpImageSparseFetch:
    623     case SpvOpImageSparseGather:
    624     case SpvOpImageSparseDrefGather:
    625     case SpvOpImageSparseTexelsResident:
    626     case SpvOpImageSparseRead: {
    627       return true;
    628     }
    629 
    630     default: { return false; }
    631   }
    632 
    633   return false;
    634 }
    635 
    636 // Checks sparse image opcode result type and returns the second struct member.
    637 // Returns inst.type_id for non-sparse image opcodes.
    638 // Not valid for sparse image opcodes which do not return a struct.
    639 spv_result_t GetActualResultType(ValidationState_t& _, const Instruction* inst,
    640                                  uint32_t* actual_result_type) {
    641   const SpvOp opcode = inst->opcode();
    642 
    643   if (IsSparse(opcode)) {
    644     const Instruction* const type_inst = _.FindDef(inst->type_id());
    645     assert(type_inst);
    646 
    647     if (!type_inst || type_inst->opcode() != SpvOpTypeStruct) {
    648       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    649              << "Expected Result Type to be OpTypeStruct";
    650     }
    651 
    652     if (type_inst->words().size() != 4 ||
    653         !_.IsIntScalarType(type_inst->word(2))) {
    654       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    655              << "Expected Result Type to be a struct containing an int "
    656                 "scalar and a texel";
    657     }
    658 
    659     *actual_result_type = type_inst->word(3);
    660   } else {
    661     *actual_result_type = inst->type_id();
    662   }
    663 
    664   return SPV_SUCCESS;
    665 }
    666 
    667 // Returns a string describing actual result type of an opcode.
    668 // Not valid for sparse image opcodes which do not return a struct.
    669 const char* GetActualResultTypeStr(SpvOp opcode) {
    670   if (IsSparse(opcode)) return "Result Type's second member";
    671   return "Result Type";
    672 }
    673 
    674 spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) {
    675   assert(inst->type_id() == 0);
    676 
    677   ImageTypeInfo info;
    678   if (!GetImageTypeInfo(_, inst->word(1), &info)) {
    679     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    680            << "Corrupt image type definition";
    681   }
    682 
    683   if (spvIsVulkanEnv(_.context()->target_env)) {
    684     if ((!_.IsFloatScalarType(info.sampled_type) &&
    685          !_.IsIntScalarType(info.sampled_type)) ||
    686         32 != _.GetBitWidth(info.sampled_type)) {
    687       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    688              << "Expected Sampled Type to be a 32-bit int or float "
    689                 "scalar type for Vulkan environment";
    690     }
    691   } else {
    692     const SpvOp sampled_type_opcode = _.GetIdOpcode(info.sampled_type);
    693     if (sampled_type_opcode != SpvOpTypeVoid &&
    694         sampled_type_opcode != SpvOpTypeInt &&
    695         sampled_type_opcode != SpvOpTypeFloat) {
    696       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    697              << "Expected Sampled Type to be either void or"
    698              << " numerical scalar type";
    699     }
    700   }
    701 
    702   // Dim is checked elsewhere.
    703 
    704   if (info.depth > 2) {
    705     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    706            << "Invalid Depth " << info.depth << " (must be 0, 1 or 2)";
    707   }
    708 
    709   if (info.arrayed > 1) {
    710     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    711            << "Invalid Arrayed " << info.arrayed << " (must be 0 or 1)";
    712   }
    713 
    714   if (info.multisampled > 1) {
    715     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    716            << "Invalid MS " << info.multisampled << " (must be 0 or 1)";
    717   }
    718 
    719   if (info.sampled > 2) {
    720     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    721            << "Invalid Sampled " << info.sampled << " (must be 0, 1 or 2)";
    722   }
    723 
    724   if (info.dim == SpvDimSubpassData) {
    725     if (info.sampled != 2) {
    726       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    727              << "Dim SubpassData requires Sampled to be 2";
    728     }
    729 
    730     if (info.format != SpvImageFormatUnknown) {
    731       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    732              << "Dim SubpassData requires format Unknown";
    733     }
    734   }
    735 
    736   // Format and Access Qualifier are checked elsewhere.
    737 
    738   return SPV_SUCCESS;
    739 }
    740 
    741 spv_result_t ValidateTypeSampledImage(ValidationState_t& _,
    742                                       const Instruction* inst) {
    743   const uint32_t image_type = inst->word(2);
    744   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
    745     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    746            << "Expected Image to be of type OpTypeImage";
    747   }
    748   return SPV_SUCCESS;
    749 }
    750 
    751 spv_result_t ValidateSampledImage(ValidationState_t& _,
    752                                   const Instruction* inst) {
    753   if (_.GetIdOpcode(inst->type_id()) != SpvOpTypeSampledImage) {
    754     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    755            << "Expected Result Type to be OpTypeSampledImage.";
    756   }
    757 
    758   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
    759   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
    760     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    761            << "Expected Image to be of type OpTypeImage.";
    762   }
    763 
    764   ImageTypeInfo info;
    765   if (!GetImageTypeInfo(_, image_type, &info)) {
    766     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    767            << "Corrupt image type definition";
    768   }
    769 
    770   // TODO(atgoo (at) github.com) Check compatibility of result type and received
    771   // image.
    772 
    773   if (spvIsVulkanEnv(_.context()->target_env)) {
    774     if (info.sampled != 1) {
    775       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    776              << "Expected Image 'Sampled' parameter to be 1 "
    777              << "for Vulkan environment.";
    778     }
    779   } else {
    780     if (info.sampled != 0 && info.sampled != 1) {
    781       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    782              << "Expected Image 'Sampled' parameter to be 0 or 1";
    783     }
    784   }
    785 
    786   if (info.dim == SpvDimSubpassData) {
    787     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    788            << "Expected Image 'Dim' parameter to be not SubpassData.";
    789   }
    790 
    791   if (_.GetIdOpcode(_.GetOperandTypeId(inst, 3)) != SpvOpTypeSampler) {
    792     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    793            << "Expected Sampler to be of type OpTypeSampler";
    794   }
    795 
    796   // We need to validate 2 things:
    797   // * All OpSampledImage instructions must be in the same block in which their
    798   // Result <id> are consumed.
    799   // * Result <id> from OpSampledImage instructions must not appear as operands
    800   // to OpPhi instructions or OpSelect instructions, or any instructions other
    801   // than the image lookup and query instructions specified to take an operand
    802   // whose type is OpTypeSampledImage.
    803   std::vector<uint32_t> consumers = _.getSampledImageConsumers(inst->id());
    804   if (!consumers.empty()) {
    805     for (auto consumer_id : consumers) {
    806       const auto consumer_instr = _.FindDef(consumer_id);
    807       const auto consumer_opcode = consumer_instr->opcode();
    808       if (consumer_instr->block() != inst->block()) {
    809         return _.diag(SPV_ERROR_INVALID_ID, inst)
    810                << "All OpSampledImage instructions must be in the same block "
    811                   "in "
    812                   "which their Result <id> are consumed. OpSampledImage Result "
    813                   "Type <id> '"
    814                << _.getIdName(inst->id())
    815                << "' has a consumer in a different basic "
    816                   "block. The consumer instruction <id> is '"
    817                << _.getIdName(consumer_id) << "'.";
    818       }
    819       // TODO: The following check is incomplete. We should also check that the
    820       // Sampled Image is not used by instructions that should not take
    821       // SampledImage as an argument. We could find the list of valid
    822       // instructions by scanning for "Sampled Image" in the operand description
    823       // field in the grammar file.
    824       if (consumer_opcode == SpvOpPhi || consumer_opcode == SpvOpSelect) {
    825         return _.diag(SPV_ERROR_INVALID_ID, inst)
    826                << "Result <id> from OpSampledImage instruction must not appear "
    827                   "as "
    828                   "operands of Op"
    829                << spvOpcodeString(static_cast<SpvOp>(consumer_opcode)) << "."
    830                << " Found result <id> '" << _.getIdName(inst->id())
    831                << "' as an operand of <id> '" << _.getIdName(consumer_id)
    832                << "'.";
    833       }
    834     }
    835   }
    836   return SPV_SUCCESS;
    837 }
    838 
    839 spv_result_t ValidateImageTexelPointer(ValidationState_t& _,
    840                                        const Instruction* inst) {
    841   const auto result_type = _.FindDef(inst->type_id());
    842   if (result_type->opcode() != SpvOpTypePointer) {
    843     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    844            << "Expected Result Type to be OpTypePointer";
    845   }
    846 
    847   const auto storage_class = result_type->GetOperandAs<uint32_t>(1);
    848   if (storage_class != SpvStorageClassImage) {
    849     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    850            << "Expected Result Type to be OpTypePointer whose Storage Class "
    851               "operand is Image";
    852   }
    853 
    854   const auto ptr_type = result_type->GetOperandAs<uint32_t>(2);
    855   const auto ptr_opcode = _.GetIdOpcode(ptr_type);
    856   if (ptr_opcode != SpvOpTypeInt && ptr_opcode != SpvOpTypeFloat &&
    857       ptr_opcode != SpvOpTypeVoid) {
    858     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    859            << "Expected Result Type to be OpTypePointer whose Type operand "
    860               "must be a scalar numerical type or OpTypeVoid";
    861   }
    862 
    863   const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2));
    864   if (!image_ptr || image_ptr->opcode() != SpvOpTypePointer) {
    865     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    866            << "Expected Image to be OpTypePointer";
    867   }
    868 
    869   const auto image_type = image_ptr->GetOperandAs<uint32_t>(2);
    870   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
    871     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    872            << "Expected Image to be OpTypePointer with Type OpTypeImage";
    873   }
    874 
    875   ImageTypeInfo info;
    876   if (!GetImageTypeInfo(_, image_type, &info)) {
    877     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    878            << "Corrupt image type definition";
    879   }
    880 
    881   if (info.sampled_type != ptr_type) {
    882     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    883            << "Expected Image 'Sampled Type' to be the same as the Type "
    884               "pointed to by Result Type";
    885   }
    886 
    887   if (info.dim == SpvDimSubpassData) {
    888     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    889            << "Image Dim SubpassData cannot be used with OpImageTexelPointer";
    890   }
    891 
    892   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
    893   if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) {
    894     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    895            << "Expected Coordinate to be integer scalar or vector";
    896   }
    897 
    898   uint32_t expected_coord_size = 0;
    899   if (info.arrayed == 0) {
    900     expected_coord_size = GetPlaneCoordSize(info);
    901   } else if (info.arrayed == 1) {
    902     switch (info.dim) {
    903       case SpvDim1D:
    904         expected_coord_size = 2;
    905         break;
    906       case SpvDimCube:
    907       case SpvDim2D:
    908         expected_coord_size = 3;
    909         break;
    910       default:
    911         return _.diag(SPV_ERROR_INVALID_DATA, inst)
    912                << "Expected Image 'Dim' must be one of 1D, 2D, or Cube when "
    913                   "Arrayed is 1";
    914         break;
    915     }
    916   }
    917 
    918   const uint32_t actual_coord_size = _.GetDimension(coord_type);
    919   if (expected_coord_size != actual_coord_size) {
    920     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    921            << "Expected Coordinate to have " << expected_coord_size
    922            << " components, but given " << actual_coord_size;
    923   }
    924 
    925   const uint32_t sample_type = _.GetOperandTypeId(inst, 4);
    926   if (!sample_type || !_.IsIntScalarType(sample_type)) {
    927     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    928            << "Expected Sample to be integer scalar";
    929   }
    930 
    931   if (info.multisampled == 0) {
    932     uint64_t ms = 0;
    933     if (!_.GetConstantValUint64(inst->GetOperandAs<uint32_t>(4), &ms) ||
    934         ms != 0) {
    935       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    936              << "Expected Sample for Image with MS 0 to be a valid <id> for "
    937                 "the value 0";
    938     }
    939   }
    940   return SPV_SUCCESS;
    941 }
    942 
    943 spv_result_t ValidateImageLod(ValidationState_t& _, const Instruction* inst) {
    944   const SpvOp opcode = inst->opcode();
    945   uint32_t actual_result_type = 0;
    946   if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) {
    947     return error;
    948   }
    949 
    950   if (!_.IsIntVectorType(actual_result_type) &&
    951       !_.IsFloatVectorType(actual_result_type)) {
    952     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    953            << "Expected " << GetActualResultTypeStr(opcode)
    954            << " to be int or float vector type";
    955   }
    956 
    957   if (_.GetDimension(actual_result_type) != 4) {
    958     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    959            << "Expected " << GetActualResultTypeStr(opcode)
    960            << " to have 4 components";
    961   }
    962 
    963   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
    964   if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) {
    965     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    966            << "Expected Sampled Image to be of type OpTypeSampledImage";
    967   }
    968 
    969   ImageTypeInfo info;
    970   if (!GetImageTypeInfo(_, image_type, &info)) {
    971     return _.diag(SPV_ERROR_INVALID_DATA, inst)
    972            << "Corrupt image type definition";
    973   }
    974 
    975   if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
    976 
    977   if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
    978     const uint32_t texel_component_type =
    979         _.GetComponentType(actual_result_type);
    980     if (texel_component_type != info.sampled_type) {
    981       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    982              << "Expected Image 'Sampled Type' to be the same as "
    983              << GetActualResultTypeStr(opcode) << " components";
    984     }
    985   }
    986 
    987   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
    988   if ((opcode == SpvOpImageSampleExplicitLod ||
    989        opcode == SpvOpImageSparseSampleExplicitLod) &&
    990       _.HasCapability(SpvCapabilityKernel)) {
    991     if (!_.IsFloatScalarOrVectorType(coord_type) &&
    992         !_.IsIntScalarOrVectorType(coord_type)) {
    993       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    994              << "Expected Coordinate to be int or float scalar or vector";
    995     }
    996   } else {
    997     if (!_.IsFloatScalarOrVectorType(coord_type)) {
    998       return _.diag(SPV_ERROR_INVALID_DATA, inst)
    999              << "Expected Coordinate to be float scalar or vector";
   1000     }
   1001   }
   1002 
   1003   const uint32_t min_coord_size = GetMinCoordSize(opcode, info);
   1004   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1005   if (min_coord_size > actual_coord_size) {
   1006     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1007            << "Expected Coordinate to have at least " << min_coord_size
   1008            << " components, but given only " << actual_coord_size;
   1009   }
   1010 
   1011   if (inst->words().size() <= 5) {
   1012     assert(IsImplicitLod(opcode));
   1013     return SPV_SUCCESS;
   1014   }
   1015 
   1016   const uint32_t mask = inst->word(5);
   1017   if (spv_result_t result =
   1018           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
   1019     return result;
   1020 
   1021   return SPV_SUCCESS;
   1022 }
   1023 
   1024 spv_result_t ValidateImageDrefLod(ValidationState_t& _,
   1025                                   const Instruction* inst) {
   1026   const SpvOp opcode = inst->opcode();
   1027   uint32_t actual_result_type = 0;
   1028   if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) {
   1029     return error;
   1030   }
   1031 
   1032   if (!_.IsIntScalarType(actual_result_type) &&
   1033       !_.IsFloatScalarType(actual_result_type)) {
   1034     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1035            << "Expected " << GetActualResultTypeStr(opcode)
   1036            << " to be int or float scalar type";
   1037   }
   1038 
   1039   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1040   if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) {
   1041     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1042            << "Expected Sampled Image to be of type OpTypeSampledImage";
   1043   }
   1044 
   1045   ImageTypeInfo info;
   1046   if (!GetImageTypeInfo(_, image_type, &info)) {
   1047     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1048            << "Corrupt image type definition";
   1049   }
   1050 
   1051   if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
   1052 
   1053   if (actual_result_type != info.sampled_type) {
   1054     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1055            << "Expected Image 'Sampled Type' to be the same as "
   1056            << GetActualResultTypeStr(opcode);
   1057   }
   1058 
   1059   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
   1060   if (!_.IsFloatScalarOrVectorType(coord_type)) {
   1061     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1062            << "Expected Coordinate to be float scalar or vector";
   1063   }
   1064 
   1065   const uint32_t min_coord_size = GetMinCoordSize(opcode, info);
   1066   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1067   if (min_coord_size > actual_coord_size) {
   1068     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1069            << "Expected Coordinate to have at least " << min_coord_size
   1070            << " components, but given only " << actual_coord_size;
   1071   }
   1072 
   1073   const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
   1074   if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
   1075     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1076            << "Expected Dref to be of 32-bit float type";
   1077   }
   1078 
   1079   if (inst->words().size() <= 6) {
   1080     assert(IsImplicitLod(opcode));
   1081     return SPV_SUCCESS;
   1082   }
   1083 
   1084   const uint32_t mask = inst->word(6);
   1085   if (spv_result_t result =
   1086           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7))
   1087     return result;
   1088 
   1089   return SPV_SUCCESS;
   1090 }
   1091 
   1092 spv_result_t ValidateImageFetch(ValidationState_t& _, const Instruction* inst) {
   1093   uint32_t actual_result_type = 0;
   1094   if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) {
   1095     return error;
   1096   }
   1097 
   1098   const SpvOp opcode = inst->opcode();
   1099   if (!_.IsIntVectorType(actual_result_type) &&
   1100       !_.IsFloatVectorType(actual_result_type)) {
   1101     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1102            << "Expected " << GetActualResultTypeStr(opcode)
   1103            << " to be int or float vector type";
   1104   }
   1105 
   1106   if (_.GetDimension(actual_result_type) != 4) {
   1107     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1108            << "Expected " << GetActualResultTypeStr(opcode)
   1109            << " to have 4 components";
   1110   }
   1111 
   1112   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1113   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1114     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1115            << "Expected Image to be of type OpTypeImage";
   1116   }
   1117 
   1118   ImageTypeInfo info;
   1119   if (!GetImageTypeInfo(_, image_type, &info)) {
   1120     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1121            << "Corrupt image type definition";
   1122   }
   1123 
   1124   if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
   1125     const uint32_t result_component_type =
   1126         _.GetComponentType(actual_result_type);
   1127     if (result_component_type != info.sampled_type) {
   1128       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1129              << "Expected Image 'Sampled Type' to be the same as "
   1130              << GetActualResultTypeStr(opcode) << " components";
   1131     }
   1132   }
   1133 
   1134   if (info.dim == SpvDimCube) {
   1135     return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'Dim' cannot be Cube";
   1136   }
   1137 
   1138   if (info.sampled != 1) {
   1139     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1140            << "Expected Image 'Sampled' parameter to be 1";
   1141   }
   1142 
   1143   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
   1144   if (!_.IsIntScalarOrVectorType(coord_type)) {
   1145     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1146            << "Expected Coordinate to be int scalar or vector";
   1147   }
   1148 
   1149   const uint32_t min_coord_size = GetMinCoordSize(opcode, info);
   1150   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1151   if (min_coord_size > actual_coord_size) {
   1152     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1153            << "Expected Coordinate to have at least " << min_coord_size
   1154            << " components, but given only " << actual_coord_size;
   1155   }
   1156 
   1157   if (inst->words().size() <= 5) return SPV_SUCCESS;
   1158 
   1159   const uint32_t mask = inst->word(5);
   1160   if (spv_result_t result =
   1161           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
   1162     return result;
   1163 
   1164   return SPV_SUCCESS;
   1165 }
   1166 
   1167 spv_result_t ValidateImageGather(ValidationState_t& _,
   1168                                  const Instruction* inst) {
   1169   uint32_t actual_result_type = 0;
   1170   if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type))
   1171     return error;
   1172 
   1173   const SpvOp opcode = inst->opcode();
   1174   if (!_.IsIntVectorType(actual_result_type) &&
   1175       !_.IsFloatVectorType(actual_result_type)) {
   1176     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1177            << "Expected " << GetActualResultTypeStr(opcode)
   1178            << " to be int or float vector type";
   1179   }
   1180 
   1181   if (_.GetDimension(actual_result_type) != 4) {
   1182     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1183            << "Expected " << GetActualResultTypeStr(opcode)
   1184            << " to have 4 components";
   1185   }
   1186 
   1187   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1188   if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) {
   1189     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1190            << "Expected Sampled Image to be of type OpTypeSampledImage";
   1191   }
   1192 
   1193   ImageTypeInfo info;
   1194   if (!GetImageTypeInfo(_, image_type, &info)) {
   1195     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1196            << "Corrupt image type definition";
   1197   }
   1198 
   1199   if (opcode == SpvOpImageDrefGather || opcode == SpvOpImageSparseDrefGather ||
   1200       _.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
   1201     const uint32_t result_component_type =
   1202         _.GetComponentType(actual_result_type);
   1203     if (result_component_type != info.sampled_type) {
   1204       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1205              << "Expected Image 'Sampled Type' to be the same as "
   1206              << GetActualResultTypeStr(opcode) << " components";
   1207     }
   1208   }
   1209 
   1210   if (info.dim != SpvDim2D && info.dim != SpvDimCube &&
   1211       info.dim != SpvDimRect) {
   1212     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1213            << "Expected Image 'Dim' cannot be Cube";
   1214   }
   1215 
   1216   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
   1217   if (!_.IsFloatScalarOrVectorType(coord_type)) {
   1218     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1219            << "Expected Coordinate to be float scalar or vector";
   1220   }
   1221 
   1222   const uint32_t min_coord_size = GetMinCoordSize(opcode, info);
   1223   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1224   if (min_coord_size > actual_coord_size) {
   1225     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1226            << "Expected Coordinate to have at least " << min_coord_size
   1227            << " components, but given only " << actual_coord_size;
   1228   }
   1229 
   1230   if (opcode == SpvOpImageGather || opcode == SpvOpImageSparseGather) {
   1231     const uint32_t component_index_type = _.GetOperandTypeId(inst, 4);
   1232     if (!_.IsIntScalarType(component_index_type) ||
   1233         _.GetBitWidth(component_index_type) != 32) {
   1234       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1235              << "Expected Component to be 32-bit int scalar";
   1236     }
   1237   } else {
   1238     assert(opcode == SpvOpImageDrefGather ||
   1239            opcode == SpvOpImageSparseDrefGather);
   1240     const uint32_t dref_type = _.GetOperandTypeId(inst, 4);
   1241     if (!_.IsFloatScalarType(dref_type) || _.GetBitWidth(dref_type) != 32) {
   1242       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1243              << "Expected Dref to be of 32-bit float type";
   1244     }
   1245   }
   1246 
   1247   if (inst->words().size() <= 6) return SPV_SUCCESS;
   1248 
   1249   const uint32_t mask = inst->word(6);
   1250   if (spv_result_t result =
   1251           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 7))
   1252     return result;
   1253 
   1254   return SPV_SUCCESS;
   1255 }
   1256 
   1257 spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) {
   1258   const SpvOp opcode = inst->opcode();
   1259   uint32_t actual_result_type = 0;
   1260   if (spv_result_t error = GetActualResultType(_, inst, &actual_result_type)) {
   1261     return error;
   1262   }
   1263 
   1264   if (!_.IsIntScalarOrVectorType(actual_result_type) &&
   1265       !_.IsFloatScalarOrVectorType(actual_result_type)) {
   1266     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1267            << "Expected " << GetActualResultTypeStr(opcode)
   1268            << " to be int or float scalar or vector type";
   1269   }
   1270 
   1271 #if 0
   1272   // TODO(atgoo (at) github.com) Disabled until the spec is clarified.
   1273   if (_.GetDimension(actual_result_type) != 4) {
   1274     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1275            << "Expected " << GetActualResultTypeStr(opcode)
   1276            << " to have 4 components";
   1277   }
   1278 #endif
   1279 
   1280   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1281   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1282     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1283            << "Expected Image to be of type OpTypeImage";
   1284   }
   1285 
   1286   ImageTypeInfo info;
   1287   if (!GetImageTypeInfo(_, image_type, &info)) {
   1288     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1289            << "Corrupt image type definition";
   1290   }
   1291 
   1292   if (info.dim == SpvDimSubpassData) {
   1293     if (opcode == SpvOpImageSparseRead) {
   1294       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1295              << "Image Dim SubpassData cannot be used with ImageSparseRead";
   1296     }
   1297 
   1298     _.function(inst->function()->id())
   1299         ->RegisterExecutionModelLimitation(
   1300             SpvExecutionModelFragment,
   1301             std::string("Dim SubpassData requires Fragment execution model: ") +
   1302                 spvOpcodeString(opcode));
   1303   }
   1304 
   1305   if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
   1306     const uint32_t result_component_type =
   1307         _.GetComponentType(actual_result_type);
   1308     if (result_component_type != info.sampled_type) {
   1309       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1310              << "Expected Image 'Sampled Type' to be the same as "
   1311              << GetActualResultTypeStr(opcode) << " components";
   1312     }
   1313   }
   1314 
   1315   if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
   1316 
   1317   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
   1318   if (!_.IsIntScalarOrVectorType(coord_type)) {
   1319     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1320            << "Expected Coordinate to be int scalar or vector";
   1321   }
   1322 
   1323   const uint32_t min_coord_size = GetMinCoordSize(opcode, info);
   1324   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1325   if (min_coord_size > actual_coord_size) {
   1326     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1327            << "Expected Coordinate to have at least " << min_coord_size
   1328            << " components, but given only " << actual_coord_size;
   1329   }
   1330 
   1331   if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData &&
   1332       !_.HasCapability(SpvCapabilityStorageImageReadWithoutFormat)) {
   1333     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1334            << "Capability StorageImageReadWithoutFormat is required to "
   1335            << "read storage image";
   1336   }
   1337 
   1338   if (inst->words().size() <= 5) return SPV_SUCCESS;
   1339 
   1340   const uint32_t mask = inst->word(5);
   1341   if (spv_result_t result =
   1342           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 6))
   1343     return result;
   1344 
   1345   return SPV_SUCCESS;
   1346 }
   1347 
   1348 spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) {
   1349   const uint32_t image_type = _.GetOperandTypeId(inst, 0);
   1350   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1351     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1352            << "Expected Image to be of type OpTypeImage";
   1353   }
   1354 
   1355   ImageTypeInfo info;
   1356   if (!GetImageTypeInfo(_, image_type, &info)) {
   1357     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1358            << "Corrupt image type definition";
   1359   }
   1360 
   1361   if (info.dim == SpvDimSubpassData) {
   1362     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1363            << "Image 'Dim' cannot be SubpassData";
   1364   }
   1365 
   1366   if (spv_result_t result = ValidateImageCommon(_, inst, info)) return result;
   1367 
   1368   const uint32_t coord_type = _.GetOperandTypeId(inst, 1);
   1369   if (!_.IsIntScalarOrVectorType(coord_type)) {
   1370     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1371            << "Expected Coordinate to be int scalar or vector";
   1372   }
   1373 
   1374   const uint32_t min_coord_size = GetMinCoordSize(inst->opcode(), info);
   1375   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1376   if (min_coord_size > actual_coord_size) {
   1377     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1378            << "Expected Coordinate to have at least " << min_coord_size
   1379            << " components, but given only " << actual_coord_size;
   1380   }
   1381 
   1382   // TODO(atgoo (at) github.com) The spec doesn't explicitely say what the type
   1383   // of texel should be.
   1384   const uint32_t texel_type = _.GetOperandTypeId(inst, 2);
   1385   if (!_.IsIntScalarOrVectorType(texel_type) &&
   1386       !_.IsFloatScalarOrVectorType(texel_type)) {
   1387     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1388            << "Expected Texel to be int or float vector or scalar";
   1389   }
   1390 
   1391 #if 0
   1392   // TODO: See above.
   1393   if (_.GetDimension(texel_type) != 4) {
   1394     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1395         << "Expected Texel to have 4 components";
   1396   }
   1397 #endif
   1398 
   1399   if (_.GetIdOpcode(info.sampled_type) != SpvOpTypeVoid) {
   1400     const uint32_t texel_component_type = _.GetComponentType(texel_type);
   1401     if (texel_component_type != info.sampled_type) {
   1402       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1403              << "Expected Image 'Sampled Type' to be the same as Texel "
   1404              << "components";
   1405     }
   1406   }
   1407 
   1408   if (info.format == SpvImageFormatUnknown && info.dim != SpvDimSubpassData &&
   1409       !_.HasCapability(SpvCapabilityStorageImageWriteWithoutFormat)) {
   1410     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1411            << "Capability StorageImageWriteWithoutFormat is required to "
   1412               "write "
   1413            << "to storage image";
   1414   }
   1415 
   1416   if (inst->words().size() <= 4) return SPV_SUCCESS;
   1417 
   1418   const uint32_t mask = inst->word(4);
   1419   if (spv_result_t result =
   1420           ValidateImageOperands(_, inst, info, mask, /* word_index = */ 5))
   1421     return result;
   1422 
   1423   return SPV_SUCCESS;
   1424 }
   1425 
   1426 spv_result_t ValidateImage(ValidationState_t& _, const Instruction* inst) {
   1427   const uint32_t result_type = inst->type_id();
   1428   if (_.GetIdOpcode(result_type) != SpvOpTypeImage) {
   1429     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1430            << "Expected Result Type to be OpTypeImage";
   1431   }
   1432 
   1433   const uint32_t sampled_image_type = _.GetOperandTypeId(inst, 2);
   1434   const Instruction* sampled_image_type_inst = _.FindDef(sampled_image_type);
   1435   assert(sampled_image_type_inst);
   1436 
   1437   if (sampled_image_type_inst->opcode() != SpvOpTypeSampledImage) {
   1438     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1439            << "Expected Sample Image to be of type OpTypeSampleImage";
   1440   }
   1441 
   1442   if (sampled_image_type_inst->word(2) != result_type) {
   1443     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1444            << "Expected Sample Image image type to be equal to Result Type";
   1445   }
   1446 
   1447   return SPV_SUCCESS;
   1448 }
   1449 
   1450 spv_result_t ValidateImageQuerySizeLod(ValidationState_t& _,
   1451                                        const Instruction* inst) {
   1452   const uint32_t result_type = inst->type_id();
   1453   if (!_.IsIntScalarOrVectorType(result_type)) {
   1454     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1455            << "Expected Result Type to be int scalar or vector type";
   1456   }
   1457 
   1458   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1459   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1460     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1461            << "Expected Image to be of type OpTypeImage";
   1462   }
   1463 
   1464   ImageTypeInfo info;
   1465   if (!GetImageTypeInfo(_, image_type, &info)) {
   1466     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1467            << "Corrupt image type definition";
   1468   }
   1469 
   1470   uint32_t expected_num_components = info.arrayed;
   1471   switch (info.dim) {
   1472     case SpvDim1D:
   1473       expected_num_components += 1;
   1474       break;
   1475     case SpvDim2D:
   1476     case SpvDimCube:
   1477       expected_num_components += 2;
   1478       break;
   1479     case SpvDim3D:
   1480       expected_num_components += 3;
   1481       break;
   1482     default:
   1483       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1484              << "Image 'Dim' must be 1D, 2D, 3D or Cube";
   1485   }
   1486 
   1487   if (info.multisampled != 0) {
   1488     return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 0";
   1489   }
   1490 
   1491   uint32_t result_num_components = _.GetDimension(result_type);
   1492   if (result_num_components != expected_num_components) {
   1493     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1494            << "Result Type has " << result_num_components << " components, "
   1495            << "but " << expected_num_components << " expected";
   1496   }
   1497 
   1498   const uint32_t lod_type = _.GetOperandTypeId(inst, 3);
   1499   if (!_.IsIntScalarType(lod_type)) {
   1500     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1501            << "Expected Level of Detail to be int scalar";
   1502   }
   1503   return SPV_SUCCESS;
   1504 }
   1505 
   1506 spv_result_t ValidateImageQuerySize(ValidationState_t& _,
   1507                                     const Instruction* inst) {
   1508   const uint32_t result_type = inst->type_id();
   1509   if (!_.IsIntScalarOrVectorType(result_type)) {
   1510     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1511            << "Expected Result Type to be int scalar or vector type";
   1512   }
   1513 
   1514   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1515   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1516     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1517            << "Expected Image to be of type OpTypeImage";
   1518   }
   1519 
   1520   ImageTypeInfo info;
   1521   if (!GetImageTypeInfo(_, image_type, &info)) {
   1522     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1523            << "Corrupt image type definition";
   1524   }
   1525 
   1526   uint32_t expected_num_components = info.arrayed;
   1527   switch (info.dim) {
   1528     case SpvDim1D:
   1529     case SpvDimBuffer:
   1530       expected_num_components += 1;
   1531       break;
   1532     case SpvDim2D:
   1533     case SpvDimCube:
   1534     case SpvDimRect:
   1535       expected_num_components += 2;
   1536       break;
   1537     case SpvDim3D:
   1538       expected_num_components += 3;
   1539       break;
   1540     default:
   1541       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1542              << "Image 'Dim' must be 1D, Buffer, 2D, Cube, 3D or Rect";
   1543   }
   1544 
   1545   if (info.dim == SpvDim1D || info.dim == SpvDim2D || info.dim == SpvDim3D ||
   1546       info.dim == SpvDimCube) {
   1547     if (info.multisampled != 1 && info.sampled != 0 && info.sampled != 2) {
   1548       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1549              << "Image must have either 'MS'=1 or 'Sampled'=0 or 'Sampled'=2";
   1550     }
   1551   }
   1552 
   1553   uint32_t result_num_components = _.GetDimension(result_type);
   1554   if (result_num_components != expected_num_components) {
   1555     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1556            << "Result Type has " << result_num_components << " components, "
   1557            << "but " << expected_num_components << " expected";
   1558   }
   1559 
   1560   return SPV_SUCCESS;
   1561 }
   1562 
   1563 spv_result_t ValidateImageQueryFormatOrOrder(ValidationState_t& _,
   1564                                              const Instruction* inst) {
   1565   if (!_.IsIntScalarType(inst->type_id())) {
   1566     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1567            << "Expected Result Type to be int scalar type";
   1568   }
   1569 
   1570   if (_.GetIdOpcode(_.GetOperandTypeId(inst, 2)) != SpvOpTypeImage) {
   1571     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1572            << "Expected operand to be of type OpTypeImage";
   1573   }
   1574   return SPV_SUCCESS;
   1575 }
   1576 
   1577 spv_result_t ValidateImageQueryLod(ValidationState_t& _,
   1578                                    const Instruction* inst) {
   1579   _.function(inst->function()->id())
   1580       ->RegisterExecutionModelLimitation(
   1581           SpvExecutionModelFragment,
   1582           "OpImageQueryLod requires Fragment execution model");
   1583 
   1584   const uint32_t result_type = inst->type_id();
   1585   if (!_.IsFloatVectorType(result_type)) {
   1586     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1587            << "Expected Result Type to be float vector type";
   1588   }
   1589 
   1590   if (_.GetDimension(result_type) != 2) {
   1591     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1592            << "Expected Result Type to have 2 components";
   1593   }
   1594 
   1595   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1596   if (_.GetIdOpcode(image_type) != SpvOpTypeSampledImage) {
   1597     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1598            << "Expected Image operand to be of type OpTypeSampledImage";
   1599   }
   1600 
   1601   ImageTypeInfo info;
   1602   if (!GetImageTypeInfo(_, image_type, &info)) {
   1603     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1604            << "Corrupt image type definition";
   1605   }
   1606 
   1607   if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
   1608       info.dim != SpvDimCube) {
   1609     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1610            << "Image 'Dim' must be 1D, 2D, 3D or Cube";
   1611   }
   1612 
   1613   const uint32_t coord_type = _.GetOperandTypeId(inst, 3);
   1614   if (_.HasCapability(SpvCapabilityKernel)) {
   1615     if (!_.IsFloatScalarOrVectorType(coord_type) &&
   1616         !_.IsIntScalarOrVectorType(coord_type)) {
   1617       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1618              << "Expected Coordinate to be int or float scalar or vector";
   1619     }
   1620   } else {
   1621     if (!_.IsFloatScalarOrVectorType(coord_type)) {
   1622       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1623              << "Expected Coordinate to be float scalar or vector";
   1624     }
   1625   }
   1626 
   1627   const uint32_t min_coord_size = GetPlaneCoordSize(info);
   1628   const uint32_t actual_coord_size = _.GetDimension(coord_type);
   1629   if (min_coord_size > actual_coord_size) {
   1630     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1631            << "Expected Coordinate to have at least " << min_coord_size
   1632            << " components, but given only " << actual_coord_size;
   1633   }
   1634   return SPV_SUCCESS;
   1635 }
   1636 
   1637 spv_result_t ValidateImageSparseLod(ValidationState_t& _,
   1638                                     const Instruction* inst) {
   1639   return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1640          << "Instruction reserved for future use, use of this instruction "
   1641          << "is invalid";
   1642 }
   1643 
   1644 spv_result_t ValidateImageQueryLevelsOrSamples(ValidationState_t& _,
   1645                                                const Instruction* inst) {
   1646   if (!_.IsIntScalarType(inst->type_id())) {
   1647     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1648            << "Expected Result Type to be int scalar type";
   1649   }
   1650 
   1651   const uint32_t image_type = _.GetOperandTypeId(inst, 2);
   1652   if (_.GetIdOpcode(image_type) != SpvOpTypeImage) {
   1653     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1654            << "Expected Image to be of type OpTypeImage";
   1655   }
   1656 
   1657   ImageTypeInfo info;
   1658   if (!GetImageTypeInfo(_, image_type, &info)) {
   1659     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1660            << "Corrupt image type definition";
   1661   }
   1662 
   1663   const SpvOp opcode = inst->opcode();
   1664   if (opcode == SpvOpImageQueryLevels) {
   1665     if (info.dim != SpvDim1D && info.dim != SpvDim2D && info.dim != SpvDim3D &&
   1666         info.dim != SpvDimCube) {
   1667       return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1668              << "Image 'Dim' must be 1D, 2D, 3D or Cube";
   1669     }
   1670   } else {
   1671     assert(opcode == SpvOpImageQuerySamples);
   1672     if (info.dim != SpvDim2D) {
   1673       return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'Dim' must be 2D";
   1674     }
   1675 
   1676     if (info.multisampled != 1) {
   1677       return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image 'MS' must be 1";
   1678     }
   1679   }
   1680   return SPV_SUCCESS;
   1681 }
   1682 
   1683 spv_result_t ValidateImageSparseTexelsResident(ValidationState_t& _,
   1684                                                const Instruction* inst) {
   1685   if (!_.IsBoolScalarType(inst->type_id())) {
   1686     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1687            << "Expected Result Type to be bool scalar type";
   1688   }
   1689 
   1690   const uint32_t resident_code_type = _.GetOperandTypeId(inst, 2);
   1691   if (!_.IsIntScalarType(resident_code_type)) {
   1692     return _.diag(SPV_ERROR_INVALID_DATA, inst)
   1693            << "Expected Resident Code to be int scalar";
   1694   }
   1695 
   1696   return SPV_SUCCESS;
   1697 }
   1698 
   1699 }  // namespace
   1700 
   1701 // Validates correctness of image instructions.
   1702 spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) {
   1703   const SpvOp opcode = inst->opcode();
   1704   if (IsImplicitLod(opcode)) {
   1705     _.function(inst->function()->id())
   1706         ->RegisterExecutionModelLimitation(
   1707             SpvExecutionModelFragment,
   1708             "ImplicitLod instructions require Fragment execution model");
   1709   }
   1710 
   1711   switch (opcode) {
   1712     case SpvOpTypeImage:
   1713       return ValidateTypeImage(_, inst);
   1714     case SpvOpTypeSampledImage:
   1715       return ValidateTypeSampledImage(_, inst);
   1716     case SpvOpSampledImage:
   1717       return ValidateSampledImage(_, inst);
   1718     case SpvOpImageTexelPointer:
   1719       return ValidateImageTexelPointer(_, inst);
   1720 
   1721     case SpvOpImageSampleImplicitLod:
   1722     case SpvOpImageSampleExplicitLod:
   1723     case SpvOpImageSampleProjImplicitLod:
   1724     case SpvOpImageSampleProjExplicitLod:
   1725     case SpvOpImageSparseSampleImplicitLod:
   1726     case SpvOpImageSparseSampleExplicitLod:
   1727       return ValidateImageLod(_, inst);
   1728 
   1729     case SpvOpImageSampleDrefImplicitLod:
   1730     case SpvOpImageSampleDrefExplicitLod:
   1731     case SpvOpImageSampleProjDrefImplicitLod:
   1732     case SpvOpImageSampleProjDrefExplicitLod:
   1733     case SpvOpImageSparseSampleDrefImplicitLod:
   1734     case SpvOpImageSparseSampleDrefExplicitLod:
   1735       return ValidateImageDrefLod(_, inst);
   1736 
   1737     case SpvOpImageFetch:
   1738     case SpvOpImageSparseFetch:
   1739       return ValidateImageFetch(_, inst);
   1740 
   1741     case SpvOpImageGather:
   1742     case SpvOpImageDrefGather:
   1743     case SpvOpImageSparseGather:
   1744     case SpvOpImageSparseDrefGather:
   1745       return ValidateImageGather(_, inst);
   1746 
   1747     case SpvOpImageRead:
   1748     case SpvOpImageSparseRead:
   1749       return ValidateImageRead(_, inst);
   1750 
   1751     case SpvOpImageWrite:
   1752       return ValidateImageWrite(_, inst);
   1753 
   1754     case SpvOpImage:
   1755       return ValidateImage(_, inst);
   1756 
   1757     case SpvOpImageQueryFormat:
   1758     case SpvOpImageQueryOrder:
   1759       return ValidateImageQueryFormatOrOrder(_, inst);
   1760 
   1761     case SpvOpImageQuerySizeLod:
   1762       return ValidateImageQuerySizeLod(_, inst);
   1763     case SpvOpImageQuerySize:
   1764       return ValidateImageQuerySize(_, inst);
   1765     case SpvOpImageQueryLod:
   1766       return ValidateImageQueryLod(_, inst);
   1767 
   1768     case SpvOpImageQueryLevels:
   1769     case SpvOpImageQuerySamples:
   1770       return ValidateImageQueryLevelsOrSamples(_, inst);
   1771 
   1772     case SpvOpImageSparseSampleProjImplicitLod:
   1773     case SpvOpImageSparseSampleProjExplicitLod:
   1774     case SpvOpImageSparseSampleProjDrefImplicitLod:
   1775     case SpvOpImageSparseSampleProjDrefExplicitLod:
   1776       return ValidateImageSparseLod(_, inst);
   1777 
   1778     case SpvOpImageSparseTexelsResident:
   1779       return ValidateImageSparseTexelsResident(_, inst);
   1780 
   1781     default:
   1782       break;
   1783   }
   1784 
   1785   return SPV_SUCCESS;
   1786 }
   1787 
   1788 }  // namespace val
   1789 }  // namespace spvtools
   1790