Home | History | Annotate | Download | only in val
      1 // Copyright (c) 2016 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 // Validation tests for Data Rules.
     16 
     17 #include <sstream>
     18 #include <string>
     19 #include <utility>
     20 
     21 #include "gmock/gmock.h"
     22 #include "test/unit_spirv.h"
     23 #include "test/val/val_fixtures.h"
     24 
     25 namespace spvtools {
     26 namespace val {
     27 namespace {
     28 
     29 using ::testing::HasSubstr;
     30 using ::testing::MatchesRegex;
     31 
     32 using ValidateData = spvtest::ValidateBase<std::pair<std::string, bool>>;
     33 
     34 std::string HeaderWith(std::string cap) {
     35   return std::string("OpCapability Shader OpCapability Linkage OpCapability ") +
     36          cap + " OpMemoryModel Logical GLSL450 ";
     37 }
     38 
     39 std::string WebGPUHeaderWith(std::string cap) {
     40   return R"(
     41 OpCapability Shader
     42 OpCapability )" +
     43          cap + R"(
     44 OpCapability VulkanMemoryModelKHR
     45 OpExtension "SPV_KHR_vulkan_memory_model"
     46 OpMemoryModel Logical VulkanKHR
     47 )";
     48 }
     49 
     50 std::string webgpu_header = R"(
     51 OpCapability Shader
     52 OpCapability VulkanMemoryModelKHR
     53 OpExtension "SPV_KHR_vulkan_memory_model"
     54 OpMemoryModel Logical VulkanKHR
     55 )";
     56 
     57 std::string header = R"(
     58      OpCapability Shader
     59      OpCapability Linkage
     60      OpMemoryModel Logical GLSL450
     61 )";
     62 std::string header_with_addresses = R"(
     63      OpCapability Addresses
     64      OpCapability Kernel
     65      OpCapability GenericPointer
     66      OpCapability Linkage
     67      OpMemoryModel Physical32 OpenCL
     68 )";
     69 std::string header_with_vec16_cap = R"(
     70      OpCapability Shader
     71      OpCapability Vector16
     72      OpCapability Linkage
     73      OpMemoryModel Logical GLSL450
     74 )";
     75 std::string header_with_int8 = R"(
     76      OpCapability Shader
     77      OpCapability Linkage
     78      OpCapability Int8
     79      OpMemoryModel Logical GLSL450
     80 )";
     81 std::string header_with_int16 = R"(
     82      OpCapability Shader
     83      OpCapability Linkage
     84      OpCapability Int16
     85      OpMemoryModel Logical GLSL450
     86 )";
     87 std::string header_with_int64 = R"(
     88      OpCapability Shader
     89      OpCapability Linkage
     90      OpCapability Int64
     91      OpMemoryModel Logical GLSL450
     92 )";
     93 std::string header_with_float16 = R"(
     94      OpCapability Shader
     95      OpCapability Linkage
     96      OpCapability Float16
     97      OpMemoryModel Logical GLSL450
     98 )";
     99 std::string header_with_float16_buffer = R"(
    100      OpCapability Shader
    101      OpCapability Linkage
    102      OpCapability Float16Buffer
    103      OpMemoryModel Logical GLSL450
    104 )";
    105 std::string header_with_float64 = R"(
    106      OpCapability Shader
    107      OpCapability Linkage
    108      OpCapability Float64
    109      OpMemoryModel Logical GLSL450
    110 )";
    111 
    112 std::string invalid_comp_error = "Illegal number of components";
    113 std::string missing_cap_error = "requires the Vector16 capability";
    114 std::string missing_int8_cap_error = "requires the Int8 capability";
    115 std::string missing_int16_cap_error =
    116     "requires the Int16 capability,"
    117     " or an extension that explicitly enables 16-bit integers.";
    118 std::string missing_int64_cap_error = "requires the Int64 capability";
    119 std::string missing_float16_cap_error =
    120     "requires the Float16 or Float16Buffer capability,"
    121     " or an extension that explicitly enables 16-bit floating point.";
    122 std::string missing_float64_cap_error = "requires the Float64 capability";
    123 std::string invalid_num_bits_error = "Invalid number of bits";
    124 
    125 TEST_F(ValidateData, vec0) {
    126   std::string str = header + R"(
    127 %1 = OpTypeFloat 32
    128 %2 = OpTypeVector %1 0
    129 )";
    130   CompileSuccessfully(str.c_str());
    131   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    132   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
    133 }
    134 
    135 TEST_F(ValidateData, vec1) {
    136   std::string str = header + R"(
    137 %1 = OpTypeFloat 32
    138 %2 = OpTypeVector %1 1
    139 )";
    140   CompileSuccessfully(str.c_str());
    141   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    142   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
    143 }
    144 
    145 TEST_F(ValidateData, vec2) {
    146   std::string str = header + R"(
    147 %1 = OpTypeFloat 32
    148 %2 = OpTypeVector %1 2
    149 )";
    150   CompileSuccessfully(str.c_str());
    151   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    152 }
    153 
    154 TEST_F(ValidateData, vec3) {
    155   std::string str = header + R"(
    156 %1 = OpTypeFloat 32
    157 %2 = OpTypeVector %1 3
    158 )";
    159   CompileSuccessfully(str.c_str());
    160   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    161 }
    162 
    163 TEST_F(ValidateData, vec4) {
    164   std::string str = header + R"(
    165 %1 = OpTypeFloat 32
    166 %2 = OpTypeVector %1 4
    167 )";
    168   CompileSuccessfully(str.c_str());
    169   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    170 }
    171 
    172 TEST_F(ValidateData, vec5) {
    173   std::string str = header + R"(
    174 %1 = OpTypeFloat 32
    175 %2 = OpTypeVector %1 5
    176 )";
    177   CompileSuccessfully(str.c_str());
    178   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    179   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
    180 }
    181 
    182 TEST_F(ValidateData, vec8) {
    183   std::string str = header + R"(
    184 %1 = OpTypeFloat 32
    185 %2 = OpTypeVector %1 8
    186 )";
    187   CompileSuccessfully(str.c_str());
    188   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    189   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
    190 }
    191 
    192 TEST_F(ValidateData, vec8_with_capability) {
    193   std::string str = header_with_vec16_cap + R"(
    194 %1 = OpTypeFloat 32
    195 %2 = OpTypeVector %1 8
    196 )";
    197   CompileSuccessfully(str.c_str());
    198   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    199 }
    200 
    201 TEST_F(ValidateData, vec16) {
    202   std::string str = header + R"(
    203 %1 = OpTypeFloat 32
    204 %2 = OpTypeVector %1 8
    205 )";
    206   CompileSuccessfully(str.c_str());
    207   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    208   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
    209 }
    210 
    211 TEST_F(ValidateData, vec16_with_capability) {
    212   std::string str = header_with_vec16_cap + R"(
    213 %1 = OpTypeFloat 32
    214 %2 = OpTypeVector %1 16
    215 )";
    216   CompileSuccessfully(str.c_str());
    217   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    218 }
    219 
    220 TEST_F(ValidateData, vec15) {
    221   std::string str = header + R"(
    222 %1 = OpTypeFloat 32
    223 %2 = OpTypeVector %1 15
    224 )";
    225   CompileSuccessfully(str.c_str());
    226   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    227   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
    228 }
    229 
    230 TEST_F(ValidateData, int8_good) {
    231   std::string str = header_with_int8 + "%2 = OpTypeInt 8 0";
    232   CompileSuccessfully(str.c_str());
    233   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    234 }
    235 
    236 TEST_F(ValidateData, int8_bad) {
    237   std::string str = header + "%2 = OpTypeInt 8 1";
    238   CompileSuccessfully(str.c_str());
    239   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    240   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int8_cap_error));
    241 }
    242 
    243 TEST_F(ValidateData, int8_with_storage_buffer_8bit_access_good) {
    244   std::string str = HeaderWith(
    245                         "StorageBuffer8BitAccess "
    246                         "OpExtension \"SPV_KHR_8bit_storage\"") +
    247                     " %2 = OpTypeInt 8 0";
    248   CompileSuccessfully(str.c_str());
    249   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
    250 }
    251 
    252 TEST_F(ValidateData, int8_with_uniform_and_storage_buffer_8bit_access_good) {
    253   std::string str = HeaderWith(
    254                         "UniformAndStorageBuffer8BitAccess "
    255                         "OpExtension \"SPV_KHR_8bit_storage\"") +
    256                     " %2 = OpTypeInt 8 0";
    257   CompileSuccessfully(str.c_str());
    258   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
    259 }
    260 
    261 TEST_F(ValidateData, int8_with_storage_push_constant_8_good) {
    262   std::string str = HeaderWith(
    263                         "StoragePushConstant8 "
    264                         "OpExtension \"SPV_KHR_8bit_storage\"") +
    265                     " %2 = OpTypeInt 8 0";
    266   CompileSuccessfully(str.c_str());
    267   EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString();
    268 }
    269 
    270 TEST_F(ValidateData, webgpu_int8_bad) {
    271   std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0";
    272   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    273   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
    274             ValidateInstructions(SPV_ENV_WEBGPU_0));
    275   EXPECT_THAT(
    276       getDiagnosticString(),
    277       HasSubstr("Capability Int8 is not allowed by WebGPU specification (or "
    278                 "requires extension)\n"
    279                 "  OpCapability Int8\n"));
    280 }
    281 
    282 TEST_F(ValidateData, int16_good) {
    283   std::string str = header_with_int16 + "%2 = OpTypeInt 16 1";
    284   CompileSuccessfully(str.c_str());
    285   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    286 }
    287 
    288 TEST_F(ValidateData, storage_uniform_buffer_block_16_good) {
    289   std::string str = HeaderWith(
    290                         "StorageUniformBufferBlock16 "
    291                         "OpExtension \"SPV_KHR_16bit_storage\"") +
    292                     "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
    293   CompileSuccessfully(str.c_str());
    294   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    295 }
    296 
    297 TEST_F(ValidateData, storage_uniform_16_good) {
    298   std::string str =
    299       HeaderWith("StorageUniform16 OpExtension \"SPV_KHR_16bit_storage\"") +
    300       "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
    301   CompileSuccessfully(str.c_str());
    302   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    303 }
    304 
    305 TEST_F(ValidateData, storage_push_constant_16_good) {
    306   std::string str = HeaderWith(
    307                         "StoragePushConstant16 "
    308                         "OpExtension \"SPV_KHR_16bit_storage\"") +
    309                     "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
    310   CompileSuccessfully(str.c_str());
    311   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    312 }
    313 
    314 TEST_F(ValidateData, storage_input_output_16_good) {
    315   std::string str = HeaderWith(
    316                         "StorageInputOutput16 "
    317                         "OpExtension \"SPV_KHR_16bit_storage\"") +
    318                     "%2 = OpTypeInt 16 1 %3 = OpTypeFloat 16";
    319   CompileSuccessfully(str.c_str());
    320   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    321 }
    322 
    323 TEST_F(ValidateData, amd_gpu_shader_half_float_fetch_16_good) {
    324   std::string str = R"(
    325      OpCapability Shader
    326      OpCapability Linkage
    327      OpExtension "SPV_AMD_gpu_shader_half_float_fetch"
    328      OpMemoryModel Logical GLSL450
    329      %2 = OpTypeFloat 16)";
    330   CompileSuccessfully(str.c_str());
    331   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    332 }
    333 
    334 TEST_F(ValidateData, int16_bad) {
    335   std::string str = header + "%2 = OpTypeInt 16 1";
    336   CompileSuccessfully(str.c_str());
    337   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    338   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error));
    339 }
    340 
    341 TEST_F(ValidateData, webgpu_int16_bad) {
    342   std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1";
    343   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    344   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
    345             ValidateInstructions(SPV_ENV_WEBGPU_0));
    346   EXPECT_THAT(
    347       getDiagnosticString(),
    348       HasSubstr("Capability Int16 is not allowed by WebGPU specification (or "
    349                 "requires extension)\n"
    350                 "  OpCapability Int16\n"));
    351 }
    352 
    353 TEST_F(ValidateData, webgpu_int32_good) {
    354   std::string str = webgpu_header + R"(
    355           OpEntryPoint Fragment %func "func"
    356           OpExecutionMode %func OriginUpperLeft
    357 %uint_t = OpTypeInt 32 0
    358   %void = OpTypeVoid
    359 %func_t = OpTypeFunction %void
    360   %func = OpFunction %void None %func_t
    361      %1 = OpLabel
    362           OpReturn
    363           OpFunctionEnd
    364 )";
    365   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    366   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
    367 }
    368 
    369 TEST_F(ValidateData, int64_good) {
    370   std::string str = header_with_int64 + "%2 = OpTypeInt 64 1";
    371   CompileSuccessfully(str.c_str());
    372   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    373 }
    374 
    375 TEST_F(ValidateData, int64_bad) {
    376   std::string str = header + "%2 = OpTypeInt 64 1";
    377   CompileSuccessfully(str.c_str());
    378   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    379   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error));
    380 }
    381 
    382 TEST_F(ValidateData, webgpu_int64_bad) {
    383   std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1";
    384   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    385   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
    386             ValidateInstructions(SPV_ENV_WEBGPU_0));
    387   EXPECT_THAT(
    388       getDiagnosticString(),
    389       HasSubstr("Capability Int64 is not allowed by WebGPU specification (or "
    390                 "requires extension)\n"
    391                 "  OpCapability Int64\n"));
    392 }
    393 
    394 // Number of bits in an integer may be only one of: {8,16,32,64}
    395 TEST_F(ValidateData, int_invalid_num_bits) {
    396   std::string str = header + "%2 = OpTypeInt 48 1";
    397   CompileSuccessfully(str.c_str());
    398   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    399   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
    400 }
    401 
    402 TEST_F(ValidateData, float16_good) {
    403   std::string str = header_with_float16 + "%2 = OpTypeFloat 16";
    404   CompileSuccessfully(str.c_str());
    405   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    406 }
    407 
    408 TEST_F(ValidateData, float16_buffer_good) {
    409   std::string str = header_with_float16_buffer + "%2 = OpTypeFloat 16";
    410   CompileSuccessfully(str.c_str());
    411   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    412 }
    413 
    414 TEST_F(ValidateData, float16_bad) {
    415   std::string str = header + "%2 = OpTypeFloat 16";
    416   CompileSuccessfully(str.c_str());
    417   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    418   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error));
    419 }
    420 
    421 TEST_F(ValidateData, webgpu_float16_bad) {
    422   std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16";
    423   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    424   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
    425             ValidateInstructions(SPV_ENV_WEBGPU_0));
    426   EXPECT_THAT(
    427       getDiagnosticString(),
    428       HasSubstr("Capability Float16 is not allowed by WebGPU specification (or "
    429                 "requires extension)\n"
    430                 "  OpCapability Float16\n"));
    431 }
    432 
    433 TEST_F(ValidateData, webgpu_float32_good) {
    434   std::string str = webgpu_header + R"(
    435            OpEntryPoint Fragment %func "func"
    436            OpExecutionMode %func OriginUpperLeft
    437 %float_t = OpTypeFloat 32
    438    %void = OpTypeVoid
    439  %func_t = OpTypeFunction %void
    440    %func = OpFunction %void None %func_t
    441       %1 = OpLabel
    442            OpReturn
    443            OpFunctionEnd
    444 )";
    445   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    446   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
    447 }
    448 
    449 TEST_F(ValidateData, float64_good) {
    450   std::string str = header_with_float64 + "%2 = OpTypeFloat 64";
    451   CompileSuccessfully(str.c_str());
    452   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    453 }
    454 
    455 TEST_F(ValidateData, float64_bad) {
    456   std::string str = header + "%2 = OpTypeFloat 64";
    457   CompileSuccessfully(str.c_str());
    458   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    459   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error));
    460 }
    461 
    462 TEST_F(ValidateData, webgpu_float64_bad) {
    463   std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64";
    464   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    465   ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY,
    466             ValidateInstructions(SPV_ENV_WEBGPU_0));
    467   EXPECT_THAT(
    468       getDiagnosticString(),
    469       HasSubstr("Capability Float64 is not allowed by WebGPU specification (or "
    470                 "requires extension)\n"
    471                 "  OpCapability Float64\n"));
    472 }
    473 
    474 // Number of bits in a float may be only one of: {16,32,64}
    475 TEST_F(ValidateData, float_invalid_num_bits) {
    476   std::string str = header + "%2 = OpTypeFloat 48";
    477   CompileSuccessfully(str.c_str());
    478   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    479   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_num_bits_error));
    480 }
    481 
    482 TEST_F(ValidateData, matrix_data_type_float) {
    483   std::string str = header + R"(
    484 %f32    =  OpTypeFloat 32
    485 %vec3   =  OpTypeVector %f32 3
    486 %mat33  =  OpTypeMatrix %vec3 3
    487 )";
    488   CompileSuccessfully(str.c_str());
    489   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    490 }
    491 
    492 TEST_F(ValidateData, ids_should_be_validated_before_data) {
    493   std::string str = header + R"(
    494 %f32    =  OpTypeFloat 32
    495 %mat33  =  OpTypeMatrix %vec3 3
    496 )";
    497   CompileSuccessfully(str.c_str());
    498   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    499   EXPECT_THAT(getDiagnosticString(),
    500               HasSubstr("ID 3[%3] has not been defined"));
    501 }
    502 
    503 TEST_F(ValidateData, matrix_bad_column_type) {
    504   std::string str = header + R"(
    505 %f32    =  OpTypeFloat 32
    506 %mat33  =  OpTypeMatrix %f32 3
    507 )";
    508   CompileSuccessfully(str.c_str());
    509   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    510   EXPECT_THAT(getDiagnosticString(),
    511               HasSubstr("Columns in a matrix must be of type vector"));
    512 }
    513 
    514 TEST_F(ValidateData, matrix_data_type_int) {
    515   std::string str = header + R"(
    516 %int32  =  OpTypeInt 32 1
    517 %vec3   =  OpTypeVector %int32 3
    518 %mat33  =  OpTypeMatrix %vec3 3
    519 )";
    520   CompileSuccessfully(str.c_str());
    521   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    522   EXPECT_THAT(getDiagnosticString(),
    523               HasSubstr("can only be parameterized with floating-point types"));
    524 }
    525 
    526 TEST_F(ValidateData, matrix_data_type_bool) {
    527   std::string str = header + R"(
    528 %boolt  =  OpTypeBool
    529 %vec3   =  OpTypeVector %boolt 3
    530 %mat33  =  OpTypeMatrix %vec3 3
    531 )";
    532   CompileSuccessfully(str.c_str());
    533   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    534   EXPECT_THAT(getDiagnosticString(),
    535               HasSubstr("can only be parameterized with floating-point types"));
    536 }
    537 
    538 TEST_F(ValidateData, matrix_with_0_columns) {
    539   std::string str = header + R"(
    540 %f32    =  OpTypeFloat 32
    541 %vec3   =  OpTypeVector %f32 3
    542 %mat33  =  OpTypeMatrix %vec3 0
    543 )";
    544   CompileSuccessfully(str.c_str());
    545   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    546   EXPECT_THAT(
    547       getDiagnosticString(),
    548       HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
    549 }
    550 
    551 TEST_F(ValidateData, matrix_with_1_column) {
    552   std::string str = header + R"(
    553 %f32    =  OpTypeFloat 32
    554 %vec3   =  OpTypeVector %f32 3
    555 %mat33  =  OpTypeMatrix %vec3 1
    556 )";
    557   CompileSuccessfully(str.c_str());
    558   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    559   EXPECT_THAT(
    560       getDiagnosticString(),
    561       HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
    562 }
    563 
    564 TEST_F(ValidateData, matrix_with_2_columns) {
    565   std::string str = header + R"(
    566 %f32    =  OpTypeFloat 32
    567 %vec3   =  OpTypeVector %f32 3
    568 %mat33  =  OpTypeMatrix %vec3 2
    569 )";
    570   CompileSuccessfully(str.c_str());
    571   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    572 }
    573 
    574 TEST_F(ValidateData, matrix_with_3_columns) {
    575   std::string str = header + R"(
    576 %f32    =  OpTypeFloat 32
    577 %vec3   =  OpTypeVector %f32 3
    578 %mat33  =  OpTypeMatrix %vec3 3
    579 )";
    580   CompileSuccessfully(str.c_str());
    581   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    582 }
    583 
    584 TEST_F(ValidateData, matrix_with_4_columns) {
    585   std::string str = header + R"(
    586 %f32    =  OpTypeFloat 32
    587 %vec3   =  OpTypeVector %f32 3
    588 %mat33  =  OpTypeMatrix %vec3 4
    589 )";
    590   CompileSuccessfully(str.c_str());
    591   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    592 }
    593 
    594 TEST_F(ValidateData, matrix_with_5_column) {
    595   std::string str = header + R"(
    596 %f32    =  OpTypeFloat 32
    597 %vec3   =  OpTypeVector %f32 3
    598 %mat33  =  OpTypeMatrix %vec3 5
    599 )";
    600   CompileSuccessfully(str.c_str());
    601   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
    602   EXPECT_THAT(
    603       getDiagnosticString(),
    604       HasSubstr("can only be parameterized as having only 2, 3, or 4 columns"));
    605 }
    606 
    607 TEST_F(ValidateData, specialize_int) {
    608   std::string str = header + R"(
    609 %i32 = OpTypeInt 32 1
    610 %len = OpSpecConstant %i32 2)";
    611   CompileSuccessfully(str.c_str());
    612   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    613 }
    614 
    615 TEST_F(ValidateData, specialize_float) {
    616   std::string str = header + R"(
    617 %f32 = OpTypeFloat 32
    618 %len = OpSpecConstant %f32 2)";
    619   CompileSuccessfully(str.c_str());
    620   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    621 }
    622 
    623 TEST_F(ValidateData, specialize_boolean) {
    624   std::string str = header + R"(
    625 %2 = OpTypeBool
    626 %3 = OpSpecConstantTrue %2
    627 %4 = OpSpecConstantFalse %2)";
    628   CompileSuccessfully(str.c_str());
    629   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    630 }
    631 
    632 TEST_F(ValidateData, specialize_boolean_to_int) {
    633   std::string str = header + R"(
    634 %2 = OpTypeInt 32 1
    635 %3 = OpSpecConstantTrue %2
    636 %4 = OpSpecConstantFalse %2)";
    637   CompileSuccessfully(str.c_str());
    638   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    639   EXPECT_THAT(getDiagnosticString(),
    640               HasSubstr("Specialization constant must be a boolean"));
    641 }
    642 
    643 TEST_F(ValidateData, missing_forward_pointer_decl) {
    644   std::string str = header_with_addresses + R"(
    645 %uintt = OpTypeInt 32 0
    646 %3 = OpTypeStruct %fwd_ptrt %uintt
    647 )";
    648   CompileSuccessfully(str.c_str());
    649   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    650   EXPECT_THAT(getDiagnosticString(),
    651               HasSubstr("must first be declared using OpTypeForwardPointer"));
    652 }
    653 
    654 TEST_F(ValidateData, missing_forward_pointer_decl_self_reference) {
    655   std::string str = header_with_addresses + R"(
    656 %uintt = OpTypeInt 32 0
    657 %3 = OpTypeStruct %3 %uintt
    658 )";
    659   CompileSuccessfully(str.c_str());
    660   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    661   EXPECT_THAT(getDiagnosticString(),
    662               HasSubstr("must first be declared using OpTypeForwardPointer"));
    663 }
    664 
    665 TEST_F(ValidateData, forward_pointer_missing_definition) {
    666   std::string str = header_with_addresses + R"(
    667 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
    668 %uintt = OpTypeInt 32 0
    669 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
    670 )";
    671   CompileSuccessfully(str.c_str());
    672   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    673   EXPECT_THAT(getDiagnosticString(),
    674               HasSubstr("forward referenced IDs have not been defined"));
    675 }
    676 
    677 TEST_F(ValidateData, forward_ref_bad_type) {
    678   std::string str = header_with_addresses + R"(
    679 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
    680 %uintt = OpTypeInt 32 0
    681 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
    682 %_ptr_Generic_struct_A = OpTypeFloat 32
    683 )";
    684   CompileSuccessfully(str.c_str());
    685   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    686   EXPECT_THAT(getDiagnosticString(),
    687               HasSubstr("Pointer type in OpTypeForwardPointer is not a pointer "
    688                         "type.\n  OpTypeForwardPointer %float Generic\n"));
    689 }
    690 
    691 TEST_F(ValidateData, forward_ref_points_to_non_struct) {
    692   std::string str = header_with_addresses + R"(
    693 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
    694 %uintt = OpTypeInt 32 0
    695 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
    696 %_ptr_Generic_struct_A = OpTypePointer Generic %uintt
    697 )";
    698   CompileSuccessfully(str.c_str());
    699   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    700   EXPECT_THAT(getDiagnosticString(),
    701               HasSubstr("A forward reference operand in an OpTypeStruct must "
    702                         "be an OpTypePointer that points to an OpTypeStruct. "
    703                         "Found OpTypePointer that points to OpTypeInt."));
    704 }
    705 
    706 TEST_F(ValidateData, struct_forward_pointer_good) {
    707   std::string str = header_with_addresses + R"(
    708 OpTypeForwardPointer %_ptr_Generic_struct_A Generic
    709 %uintt = OpTypeInt 32 0
    710 %struct_B = OpTypeStruct %uintt %_ptr_Generic_struct_A
    711 %struct_C = OpTypeStruct %uintt %struct_B
    712 %struct_A = OpTypeStruct %uintt %struct_C
    713 %_ptr_Generic_struct_A = OpTypePointer Generic %struct_C
    714 )";
    715   CompileSuccessfully(str.c_str());
    716   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    717 }
    718 
    719 TEST_F(ValidateData, ext_16bit_storage_caps_allow_free_fp_rounding_mode) {
    720   for (const char* cap : {"StorageUniform16", "StorageUniformBufferBlock16",
    721                           "StoragePushConstant16", "StorageInputOutput16"}) {
    722     for (const char* mode : {"RTE", "RTZ", "RTP", "RTN"}) {
    723       std::string str = std::string(R"(
    724         OpCapability Shader
    725         OpCapability Linkage
    726         OpCapability )") +
    727                         cap + R"(
    728         OpExtension "SPV_KHR_storage_buffer_storage_class"
    729         OpExtension "SPV_KHR_variable_pointers"
    730         OpExtension "SPV_KHR_16bit_storage"
    731         OpMemoryModel Logical GLSL450
    732         OpDecorate %_ FPRoundingMode )" + mode + R"(
    733         %half = OpTypeFloat 16
    734         %float = OpTypeFloat 32
    735         %float_1_25 = OpConstant %float 1.25
    736         %half_ptr = OpTypePointer StorageBuffer %half
    737         %half_ptr_var = OpVariable %half_ptr StorageBuffer
    738         %void = OpTypeVoid
    739         %func = OpTypeFunction %void
    740         %main = OpFunction %void None %func
    741         %main_entry = OpLabel
    742         %_ = OpFConvert %half %float_1_25
    743         OpStore %half_ptr_var %_
    744         OpReturn
    745         OpFunctionEnd
    746       )";
    747       CompileSuccessfully(str.c_str());
    748       ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
    749     }
    750   }
    751 }
    752 
    753 TEST_F(ValidateData, vulkan_disallow_free_fp_rounding_mode) {
    754   for (const char* mode : {"RTE", "RTZ"}) {
    755     for (const auto env : {SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1}) {
    756       std::string str = std::string(R"(
    757         OpCapability Shader
    758         OpExtension "SPV_KHR_storage_buffer_storage_class"
    759         OpExtension "SPV_KHR_variable_pointers"
    760         OpMemoryModel Logical GLSL450
    761         OpDecorate %_ FPRoundingMode )") +
    762                         mode + R"(
    763         %half = OpTypeFloat 16
    764         %float = OpTypeFloat 32
    765         %float_1_25 = OpConstant %float 1.25
    766         %half_ptr = OpTypePointer StorageBuffer %half
    767         %half_ptr_var = OpVariable %half_ptr StorageBuffer
    768         %void = OpTypeVoid
    769         %func = OpTypeFunction %void
    770         %main = OpFunction %void None %func
    771         %main_entry = OpLabel
    772         %_ = OpFConvert %half %float_1_25
    773         OpStore %half_ptr_var %_
    774         OpReturn
    775         OpFunctionEnd
    776       )";
    777       CompileSuccessfully(str.c_str());
    778       ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions(env));
    779       EXPECT_THAT(
    780           getDiagnosticString(),
    781           HasSubstr("Operand 2 of Decorate requires one of these capabilities: "
    782                     "StorageBuffer16BitAccess StorageUniform16 "
    783                     "StoragePushConstant16 StorageInputOutput16"));
    784     }
    785   }
    786 }
    787 
    788 TEST_F(ValidateData, void_array) {
    789   std::string str = header + R"(
    790    %void = OpTypeVoid
    791     %int = OpTypeInt 32 0
    792   %int_5 = OpConstant %int 5
    793   %array = OpTypeArray %void %int_5
    794   )";
    795 
    796   CompileSuccessfully(str.c_str());
    797   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    798   EXPECT_THAT(
    799       getDiagnosticString(),
    800       HasSubstr("OpTypeArray Element Type <id> '1[%void]' is a void type."));
    801 }
    802 
    803 TEST_F(ValidateData, void_runtime_array) {
    804   std::string str = header + R"(
    805    %void = OpTypeVoid
    806   %array = OpTypeRuntimeArray %void
    807   )";
    808 
    809   CompileSuccessfully(str.c_str());
    810   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
    811   EXPECT_THAT(
    812       getDiagnosticString(),
    813       HasSubstr(
    814           "OpTypeRuntimeArray Element Type <id> '1[%void]' is a void type."));
    815 }
    816 
    817 TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) {
    818   std::string str = R"(
    819               OpCapability Shader
    820               OpMemoryModel Logical GLSL450
    821               OpEntryPoint Fragment %func "func"
    822               OpExecutionMode %func OriginUpperLeft
    823               OpDecorate %array_t ArrayStride 4
    824               OpMemberDecorate %struct_t 0 Offset 0
    825               OpMemberDecorate %struct_t 1 Offset 4
    826               OpDecorate %struct_t Block
    827      %uint_t = OpTypeInt 32 0
    828    %array_t = OpTypeRuntimeArray %uint_t
    829   %struct_t = OpTypeStruct %uint_t %array_t
    830 %struct_ptr = OpTypePointer StorageBuffer %struct_t
    831          %2 = OpVariable %struct_ptr StorageBuffer
    832       %void = OpTypeVoid
    833     %func_t = OpTypeFunction %void
    834       %func = OpFunction %void None %func_t
    835          %1 = OpLabel
    836               OpReturn
    837               OpFunctionEnd
    838 )";
    839 
    840   CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
    841   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1));
    842 }
    843 
    844 TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) {
    845   std::string str = R"(
    846               OpCapability Shader
    847               OpMemoryModel Logical GLSL450
    848               OpEntryPoint Fragment %func "func"
    849               OpExecutionMode %func OriginUpperLeft
    850               OpDecorate %array_t ArrayStride 4
    851               OpMemberDecorate %struct_t 0 Offset 0
    852               OpMemberDecorate %struct_t 1 Offset 4
    853               OpDecorate %struct_t Block
    854      %uint_t = OpTypeInt 32 0
    855    %array_t = OpTypeRuntimeArray %uint_t
    856   %struct_t = OpTypeStruct %array_t %uint_t
    857 %struct_ptr = OpTypePointer StorageBuffer %struct_t
    858          %2 = OpVariable %struct_ptr StorageBuffer
    859       %void = OpTypeVoid
    860     %func_t = OpTypeFunction %void
    861       %func = OpFunction %void None %func_t
    862          %1 = OpLabel
    863               OpReturn
    864               OpFunctionEnd
    865 )";
    866 
    867   CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1);
    868   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1));
    869   EXPECT_THAT(getDiagnosticString(),
    870               HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for "
    871                         "the last member of an OpTypeStruct\n  %_struct_3 = "
    872                         "OpTypeStruct %_runtimearr_uint %uint\n"));
    873 }
    874 
    875 TEST_F(ValidateData, webgpu_RTA_array_at_end_of_struct) {
    876   std::string str = R"(
    877               OpCapability Shader
    878               OpCapability VulkanMemoryModelKHR
    879               OpExtension "SPV_KHR_vulkan_memory_model"
    880               OpMemoryModel Logical VulkanKHR
    881               OpEntryPoint Fragment %func "func"
    882               OpExecutionMode %func OriginUpperLeft
    883               OpDecorate %array_t ArrayStride 4
    884               OpMemberDecorate %struct_t 0 Offset 0
    885               OpMemberDecorate %struct_t 1 Offset 4
    886               OpDecorate %struct_t Block
    887      %uint_t = OpTypeInt 32 0
    888    %array_t = OpTypeRuntimeArray %uint_t
    889   %struct_t = OpTypeStruct %uint_t %array_t
    890 %struct_ptr = OpTypePointer StorageBuffer %struct_t
    891          %2 = OpVariable %struct_ptr StorageBuffer
    892       %void = OpTypeVoid
    893     %func_t = OpTypeFunction %void
    894       %func = OpFunction %void None %func_t
    895          %1 = OpLabel
    896               OpReturn
    897               OpFunctionEnd
    898 )";
    899 
    900   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    901   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
    902 }
    903 
    904 TEST_F(ValidateData, webgpu_RTA_not_at_end_of_struct) {
    905   std::string str = R"(
    906               OpCapability Shader
    907               OpCapability VulkanMemoryModelKHR
    908               OpExtension "SPV_KHR_vulkan_memory_model"
    909               OpMemoryModel Logical VulkanKHR
    910               OpEntryPoint Fragment %func "func"
    911               OpExecutionMode %func OriginUpperLeft
    912               OpDecorate %array_t ArrayStride 4
    913               OpMemberDecorate %struct_t 0 Offset 0
    914               OpMemberDecorate %struct_t 1 Offset 4
    915               OpDecorate %struct_t Block
    916      %uint_t = OpTypeInt 32 0
    917    %array_t = OpTypeRuntimeArray %uint_t
    918   %struct_t = OpTypeStruct %array_t %uint_t
    919 %struct_ptr = OpTypePointer StorageBuffer %struct_t
    920          %2 = OpVariable %struct_ptr StorageBuffer
    921       %void = OpTypeVoid
    922     %func_t = OpTypeFunction %void
    923       %func = OpFunction %void None %func_t
    924          %1 = OpLabel
    925               OpReturn
    926               OpFunctionEnd
    927 )";
    928 
    929   CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0);
    930   ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0));
    931   EXPECT_THAT(getDiagnosticString(),
    932               HasSubstr("In WebGPU, OpTypeRuntimeArray must only be used for "
    933                         "the last member of an OpTypeStruct\n  %_struct_3 = "
    934                         "OpTypeStruct %_runtimearr_uint %uint\n"));
    935 }
    936 
    937 }  // namespace
    938 }  // namespace val
    939 }  // namespace spvtools
    940