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