1 // Copyright (c) 2017 Pierre Moreau 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 #include <iostream> 16 #include <memory> 17 #include <string> 18 #include <vector> 19 20 #include "gmock/gmock.h" 21 #include "source/opt/build_module.h" 22 #include "source/opt/ir_context.h" 23 #include "source/opt/pass_manager.h" 24 #include "source/opt/remove_duplicates_pass.h" 25 #include "source/spirv_constant.h" 26 #include "test/unit_spirv.h" 27 28 namespace spvtools { 29 namespace opt { 30 namespace { 31 32 class RemoveDuplicatesTest : public ::testing::Test { 33 public: 34 RemoveDuplicatesTest() 35 : tools_(SPV_ENV_UNIVERSAL_1_2), 36 context_(), 37 consumer_([this](spv_message_level_t level, const char*, 38 const spv_position_t& position, const char* message) { 39 if (!error_message_.empty()) error_message_ += "\n"; 40 switch (level) { 41 case SPV_MSG_FATAL: 42 case SPV_MSG_INTERNAL_ERROR: 43 case SPV_MSG_ERROR: 44 error_message_ += "ERROR"; 45 break; 46 case SPV_MSG_WARNING: 47 error_message_ += "WARNING"; 48 break; 49 case SPV_MSG_INFO: 50 error_message_ += "INFO"; 51 break; 52 case SPV_MSG_DEBUG: 53 error_message_ += "DEBUG"; 54 break; 55 } 56 error_message_ += 57 ": " + std::to_string(position.index) + ": " + message; 58 }), 59 disassemble_options_(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER), 60 error_message_() { 61 tools_.SetMessageConsumer(consumer_); 62 } 63 64 void TearDown() override { error_message_.clear(); } 65 66 std::string RunPass(const std::string& text) { 67 context_ = spvtools::BuildModule(SPV_ENV_UNIVERSAL_1_2, consumer_, text); 68 if (!context_.get()) return std::string(); 69 70 PassManager manager; 71 manager.SetMessageConsumer(consumer_); 72 manager.AddPass<RemoveDuplicatesPass>(); 73 74 Pass::Status pass_res = manager.Run(context_.get()); 75 if (pass_res == Pass::Status::Failure) return std::string(); 76 77 return ModuleToText(); 78 } 79 80 // Disassembles |binary| and outputs the result in |text|. If |text| is a 81 // null pointer, SPV_ERROR_INVALID_POINTER is returned. 82 spv_result_t Disassemble(const std::vector<uint32_t>& binary, 83 std::string* text) { 84 if (!text) return SPV_ERROR_INVALID_POINTER; 85 return tools_.Disassemble(binary, text, disassemble_options_) 86 ? SPV_SUCCESS 87 : SPV_ERROR_INVALID_BINARY; 88 } 89 90 // Returns the accumulated error messages for the test. 91 std::string GetErrorMessage() const { return error_message_; } 92 93 std::string ToText(const std::vector<Instruction*>& inst) { 94 std::vector<uint32_t> binary = {SpvMagicNumber, 0x10200, 0u, 2u, 0u}; 95 for (const Instruction* i : inst) 96 i->ToBinaryWithoutAttachedDebugInsts(&binary); 97 std::string text; 98 Disassemble(binary, &text); 99 return text; 100 } 101 102 std::string ModuleToText() { 103 std::vector<uint32_t> binary; 104 context_->module()->ToBinary(&binary, false); 105 std::string text; 106 Disassemble(binary, &text); 107 return text; 108 } 109 110 private: 111 spvtools::SpirvTools 112 tools_; // An instance for calling SPIRV-Tools functionalities. 113 std::unique_ptr<IRContext> context_; 114 spvtools::MessageConsumer consumer_; 115 uint32_t disassemble_options_; 116 std::string error_message_; 117 }; 118 119 TEST_F(RemoveDuplicatesTest, DuplicateCapabilities) { 120 const std::string spirv = R"( 121 OpCapability Shader 122 OpCapability Linkage 123 OpCapability Shader 124 OpMemoryModel Logical GLSL450 125 )"; 126 const std::string after = R"(OpCapability Shader 127 OpCapability Linkage 128 OpMemoryModel Logical GLSL450 129 )"; 130 131 EXPECT_EQ(RunPass(spirv), after); 132 EXPECT_EQ(GetErrorMessage(), ""); 133 } 134 135 TEST_F(RemoveDuplicatesTest, DuplicateExtInstImports) { 136 const std::string spirv = R"( 137 OpCapability Shader 138 OpCapability Linkage 139 %1 = OpExtInstImport "OpenCL.std" 140 %2 = OpExtInstImport "OpenCL.std" 141 %3 = OpExtInstImport "GLSL.std.450" 142 OpMemoryModel Logical GLSL450 143 )"; 144 const std::string after = R"(OpCapability Shader 145 OpCapability Linkage 146 %1 = OpExtInstImport "OpenCL.std" 147 %3 = OpExtInstImport "GLSL.std.450" 148 OpMemoryModel Logical GLSL450 149 )"; 150 151 EXPECT_EQ(RunPass(spirv), after); 152 EXPECT_EQ(GetErrorMessage(), ""); 153 } 154 155 TEST_F(RemoveDuplicatesTest, DuplicateTypes) { 156 const std::string spirv = R"( 157 OpCapability Shader 158 OpCapability Linkage 159 OpMemoryModel Logical GLSL450 160 %1 = OpTypeInt 32 0 161 %2 = OpTypeInt 32 0 162 %3 = OpTypeStruct %1 %2 163 )"; 164 const std::string after = R"(OpCapability Shader 165 OpCapability Linkage 166 OpMemoryModel Logical GLSL450 167 %1 = OpTypeInt 32 0 168 %3 = OpTypeStruct %1 %1 169 )"; 170 171 EXPECT_EQ(RunPass(spirv), after); 172 EXPECT_EQ(GetErrorMessage(), ""); 173 } 174 175 TEST_F(RemoveDuplicatesTest, SameTypeDifferentMemberDecoration) { 176 const std::string spirv = R"( 177 OpCapability Shader 178 OpCapability Linkage 179 OpMemoryModel Logical GLSL450 180 OpDecorate %1 GLSLPacked 181 %2 = OpTypeInt 32 0 182 %1 = OpTypeStruct %2 %2 183 %3 = OpTypeStruct %2 %2 184 )"; 185 const std::string after = R"(OpCapability Shader 186 OpCapability Linkage 187 OpMemoryModel Logical GLSL450 188 OpDecorate %1 GLSLPacked 189 %2 = OpTypeInt 32 0 190 %1 = OpTypeStruct %2 %2 191 %3 = OpTypeStruct %2 %2 192 )"; 193 194 EXPECT_EQ(RunPass(spirv), after); 195 EXPECT_EQ(GetErrorMessage(), ""); 196 } 197 198 TEST_F(RemoveDuplicatesTest, SameTypeAndMemberDecoration) { 199 const std::string spirv = R"( 200 OpCapability Shader 201 OpCapability Linkage 202 OpMemoryModel Logical GLSL450 203 OpDecorate %1 GLSLPacked 204 OpDecorate %2 GLSLPacked 205 %3 = OpTypeInt 32 0 206 %1 = OpTypeStruct %3 %3 207 %2 = OpTypeStruct %3 %3 208 )"; 209 const std::string after = R"(OpCapability Shader 210 OpCapability Linkage 211 OpMemoryModel Logical GLSL450 212 OpDecorate %1 GLSLPacked 213 %3 = OpTypeInt 32 0 214 %1 = OpTypeStruct %3 %3 215 )"; 216 217 EXPECT_EQ(RunPass(spirv), after); 218 EXPECT_EQ(GetErrorMessage(), ""); 219 } 220 221 TEST_F(RemoveDuplicatesTest, SameTypeAndDifferentName) { 222 const std::string spirv = R"( 223 OpCapability Shader 224 OpCapability Linkage 225 OpMemoryModel Logical GLSL450 226 OpName %1 "Type1" 227 OpName %2 "Type2" 228 %3 = OpTypeInt 32 0 229 %1 = OpTypeStruct %3 %3 230 %2 = OpTypeStruct %3 %3 231 )"; 232 const std::string after = R"(OpCapability Shader 233 OpCapability Linkage 234 OpMemoryModel Logical GLSL450 235 OpName %1 "Type1" 236 %3 = OpTypeInt 32 0 237 %1 = OpTypeStruct %3 %3 238 )"; 239 240 EXPECT_EQ(RunPass(spirv), after); 241 EXPECT_EQ(GetErrorMessage(), ""); 242 } 243 244 // Check that #1033 has been fixed. 245 TEST_F(RemoveDuplicatesTest, DoNotRemoveDifferentOpDecorationGroup) { 246 const std::string spirv = R"( 247 OpCapability Shader 248 OpCapability Linkage 249 OpMemoryModel Logical GLSL450 250 OpDecorate %1 Constant 251 %1 = OpDecorationGroup 252 OpDecorate %2 Restrict 253 %2 = OpDecorationGroup 254 OpGroupDecorate %3 %1 %2 255 %4 = OpTypeInt 32 0 256 %3 = OpVariable %4 Uniform 257 )"; 258 const std::string after = R"(OpCapability Shader 259 OpCapability Linkage 260 OpMemoryModel Logical GLSL450 261 OpDecorate %1 Constant 262 %1 = OpDecorationGroup 263 OpDecorate %2 Restrict 264 %2 = OpDecorationGroup 265 OpGroupDecorate %3 %1 %2 266 %4 = OpTypeInt 32 0 267 %3 = OpVariable %4 Uniform 268 )"; 269 270 EXPECT_EQ(RunPass(spirv), after); 271 EXPECT_EQ(GetErrorMessage(), ""); 272 } 273 274 TEST_F(RemoveDuplicatesTest, DifferentDecorationGroup) { 275 const std::string spirv = R"( 276 OpCapability Shader 277 OpCapability Linkage 278 OpMemoryModel Logical GLSL450 279 OpDecorate %1 Constant 280 OpDecorate %1 Restrict 281 %1 = OpDecorationGroup 282 OpDecorate %2 Constant 283 %2 = OpDecorationGroup 284 OpGroupDecorate %1 %3 285 OpGroupDecorate %2 %4 286 %5 = OpTypeInt 32 0 287 %3 = OpVariable %5 Uniform 288 %4 = OpVariable %5 Uniform 289 )"; 290 const std::string after = R"(OpCapability Shader 291 OpCapability Linkage 292 OpMemoryModel Logical GLSL450 293 OpDecorate %1 Constant 294 OpDecorate %1 Restrict 295 %1 = OpDecorationGroup 296 OpDecorate %2 Constant 297 %2 = OpDecorationGroup 298 OpGroupDecorate %1 %3 299 OpGroupDecorate %2 %4 300 %5 = OpTypeInt 32 0 301 %3 = OpVariable %5 Uniform 302 %4 = OpVariable %5 Uniform 303 )"; 304 305 EXPECT_EQ(RunPass(spirv), after); 306 EXPECT_EQ(GetErrorMessage(), ""); 307 } 308 309 // Test what happens when a type is a resource type. For now we are merging 310 // them, but, if we want to merge types and make reflection work (issue #1372), 311 // we will not be able to merge %2 and %3 below. 312 TEST_F(RemoveDuplicatesTest, DontMergeNestedResourceTypes) { 313 const std::string spirv = R"(OpCapability Shader 314 OpMemoryModel Logical GLSL450 315 OpSource HLSL 600 316 OpName %1 "PositionAdjust" 317 OpMemberName %1 0 "XAdjust" 318 OpName %2 "NormalAdjust" 319 OpMemberName %2 0 "XDir" 320 OpMemberName %3 0 "AdjustXYZ" 321 OpMemberName %3 1 "AdjustDir" 322 OpName %4 "Constants" 323 OpMemberDecorate %1 0 Offset 0 324 OpMemberDecorate %2 0 Offset 0 325 OpMemberDecorate %3 0 Offset 0 326 OpMemberDecorate %3 1 Offset 16 327 OpDecorate %3 Block 328 OpDecorate %4 DescriptorSet 0 329 OpDecorate %4 Binding 0 330 %5 = OpTypeFloat 32 331 %6 = OpTypeVector %5 3 332 %1 = OpTypeStruct %6 333 %2 = OpTypeStruct %6 334 %3 = OpTypeStruct %1 %2 335 %7 = OpTypePointer Uniform %3 336 %4 = OpVariable %7 Uniform 337 )"; 338 339 const std::string result = R"(OpCapability Shader 340 OpMemoryModel Logical GLSL450 341 OpSource HLSL 600 342 OpName %1 "PositionAdjust" 343 OpMemberName %1 0 "XAdjust" 344 OpMemberName %3 0 "AdjustXYZ" 345 OpMemberName %3 1 "AdjustDir" 346 OpName %4 "Constants" 347 OpMemberDecorate %1 0 Offset 0 348 OpMemberDecorate %3 0 Offset 0 349 OpMemberDecorate %3 1 Offset 16 350 OpDecorate %3 Block 351 OpDecorate %4 DescriptorSet 0 352 OpDecorate %4 Binding 0 353 %5 = OpTypeFloat 32 354 %6 = OpTypeVector %5 3 355 %1 = OpTypeStruct %6 356 %3 = OpTypeStruct %1 %1 357 %7 = OpTypePointer Uniform %3 358 %4 = OpVariable %7 Uniform 359 )"; 360 361 EXPECT_EQ(RunPass(spirv), result); 362 EXPECT_EQ(GetErrorMessage(), ""); 363 } 364 365 // See comment for DontMergeNestedResourceTypes. 366 TEST_F(RemoveDuplicatesTest, DontMergeResourceTypes) { 367 const std::string spirv = R"(OpCapability Shader 368 OpMemoryModel Logical GLSL450 369 OpSource HLSL 600 370 OpName %1 "PositionAdjust" 371 OpMemberName %1 0 "XAdjust" 372 OpName %2 "NormalAdjust" 373 OpMemberName %2 0 "XDir" 374 OpName %3 "Constants" 375 OpMemberDecorate %1 0 Offset 0 376 OpMemberDecorate %2 0 Offset 0 377 OpDecorate %3 DescriptorSet 0 378 OpDecorate %3 Binding 0 379 OpDecorate %4 DescriptorSet 1 380 OpDecorate %4 Binding 0 381 %5 = OpTypeFloat 32 382 %6 = OpTypeVector %5 3 383 %1 = OpTypeStruct %6 384 %2 = OpTypeStruct %6 385 %7 = OpTypePointer Uniform %1 386 %8 = OpTypePointer Uniform %2 387 %3 = OpVariable %7 Uniform 388 %4 = OpVariable %8 Uniform 389 )"; 390 391 const std::string result = R"(OpCapability Shader 392 OpMemoryModel Logical GLSL450 393 OpSource HLSL 600 394 OpName %1 "PositionAdjust" 395 OpMemberName %1 0 "XAdjust" 396 OpName %3 "Constants" 397 OpMemberDecorate %1 0 Offset 0 398 OpDecorate %3 DescriptorSet 0 399 OpDecorate %3 Binding 0 400 OpDecorate %4 DescriptorSet 1 401 OpDecorate %4 Binding 0 402 %5 = OpTypeFloat 32 403 %6 = OpTypeVector %5 3 404 %1 = OpTypeStruct %6 405 %7 = OpTypePointer Uniform %1 406 %3 = OpVariable %7 Uniform 407 %4 = OpVariable %7 Uniform 408 )"; 409 410 EXPECT_EQ(RunPass(spirv), result); 411 EXPECT_EQ(GetErrorMessage(), ""); 412 } 413 414 // See comment for DontMergeNestedResourceTypes. 415 TEST_F(RemoveDuplicatesTest, DontMergeResourceTypesContainingArray) { 416 const std::string spirv = R"(OpCapability Shader 417 OpMemoryModel Logical GLSL450 418 OpSource HLSL 600 419 OpName %1 "PositionAdjust" 420 OpMemberName %1 0 "XAdjust" 421 OpName %2 "NormalAdjust" 422 OpMemberName %2 0 "XDir" 423 OpName %3 "Constants" 424 OpMemberDecorate %1 0 Offset 0 425 OpMemberDecorate %2 0 Offset 0 426 OpDecorate %3 DescriptorSet 0 427 OpDecorate %3 Binding 0 428 OpDecorate %4 DescriptorSet 1 429 OpDecorate %4 Binding 0 430 %5 = OpTypeFloat 32 431 %6 = OpTypeVector %5 3 432 %1 = OpTypeStruct %6 433 %2 = OpTypeStruct %6 434 %7 = OpTypeInt 32 0 435 %8 = OpConstant %7 4 436 %9 = OpTypeArray %1 %8 437 %10 = OpTypeArray %2 %8 438 %11 = OpTypePointer Uniform %9 439 %12 = OpTypePointer Uniform %10 440 %3 = OpVariable %11 Uniform 441 %4 = OpVariable %12 Uniform 442 )"; 443 444 const std::string result = R"(OpCapability Shader 445 OpMemoryModel Logical GLSL450 446 OpSource HLSL 600 447 OpName %1 "PositionAdjust" 448 OpMemberName %1 0 "XAdjust" 449 OpName %3 "Constants" 450 OpMemberDecorate %1 0 Offset 0 451 OpDecorate %3 DescriptorSet 0 452 OpDecorate %3 Binding 0 453 OpDecorate %4 DescriptorSet 1 454 OpDecorate %4 Binding 0 455 %5 = OpTypeFloat 32 456 %6 = OpTypeVector %5 3 457 %1 = OpTypeStruct %6 458 %7 = OpTypeInt 32 0 459 %8 = OpConstant %7 4 460 %9 = OpTypeArray %1 %8 461 %11 = OpTypePointer Uniform %9 462 %3 = OpVariable %11 Uniform 463 %4 = OpVariable %11 Uniform 464 )"; 465 466 EXPECT_EQ(RunPass(spirv), result); 467 EXPECT_EQ(GetErrorMessage(), ""); 468 } 469 470 // Test that we merge the type of a resource with a type that is not the type 471 // a resource. The resource type appears first in this case. We must keep 472 // the resource type. 473 TEST_F(RemoveDuplicatesTest, MergeResourceTypeWithNonresourceType1) { 474 const std::string spirv = R"(OpCapability Shader 475 OpMemoryModel Logical GLSL450 476 OpSource HLSL 600 477 OpName %1 "PositionAdjust" 478 OpMemberName %1 0 "XAdjust" 479 OpName %2 "NormalAdjust" 480 OpMemberName %2 0 "XDir" 481 OpName %3 "Constants" 482 OpMemberDecorate %1 0 Offset 0 483 OpMemberDecorate %2 0 Offset 0 484 OpDecorate %3 DescriptorSet 0 485 OpDecorate %3 Binding 0 486 %4 = OpTypeFloat 32 487 %5 = OpTypeVector %4 3 488 %1 = OpTypeStruct %5 489 %2 = OpTypeStruct %5 490 %6 = OpTypePointer Uniform %1 491 %7 = OpTypePointer Uniform %2 492 %3 = OpVariable %6 Uniform 493 %8 = OpVariable %7 Uniform 494 )"; 495 496 const std::string result = R"(OpCapability Shader 497 OpMemoryModel Logical GLSL450 498 OpSource HLSL 600 499 OpName %1 "PositionAdjust" 500 OpMemberName %1 0 "XAdjust" 501 OpName %3 "Constants" 502 OpMemberDecorate %1 0 Offset 0 503 OpDecorate %3 DescriptorSet 0 504 OpDecorate %3 Binding 0 505 %4 = OpTypeFloat 32 506 %5 = OpTypeVector %4 3 507 %1 = OpTypeStruct %5 508 %6 = OpTypePointer Uniform %1 509 %3 = OpVariable %6 Uniform 510 %8 = OpVariable %6 Uniform 511 )"; 512 513 EXPECT_EQ(RunPass(spirv), result); 514 EXPECT_EQ(GetErrorMessage(), ""); 515 } 516 517 // Test that we merge the type of a resource with a type that is not the type 518 // a resource. The resource type appears second in this case. We must keep 519 // the resource type. 520 // 521 // See comment for DontMergeNestedResourceTypes. 522 TEST_F(RemoveDuplicatesTest, MergeResourceTypeWithNonresourceType2) { 523 const std::string spirv = R"(OpCapability Shader 524 OpMemoryModel Logical GLSL450 525 OpSource HLSL 600 526 OpName %1 "PositionAdjust" 527 OpMemberName %1 0 "XAdjust" 528 OpName %2 "NormalAdjust" 529 OpMemberName %2 0 "XDir" 530 OpName %3 "Constants" 531 OpMemberDecorate %1 0 Offset 0 532 OpMemberDecorate %2 0 Offset 0 533 OpDecorate %3 DescriptorSet 0 534 OpDecorate %3 Binding 0 535 %4 = OpTypeFloat 32 536 %5 = OpTypeVector %4 3 537 %1 = OpTypeStruct %5 538 %2 = OpTypeStruct %5 539 %6 = OpTypePointer Uniform %1 540 %7 = OpTypePointer Uniform %2 541 %8 = OpVariable %6 Uniform 542 %3 = OpVariable %7 Uniform 543 )"; 544 545 const std::string result = R"(OpCapability Shader 546 OpMemoryModel Logical GLSL450 547 OpSource HLSL 600 548 OpName %1 "PositionAdjust" 549 OpMemberName %1 0 "XAdjust" 550 OpName %3 "Constants" 551 OpMemberDecorate %1 0 Offset 0 552 OpDecorate %3 DescriptorSet 0 553 OpDecorate %3 Binding 0 554 %4 = OpTypeFloat 32 555 %5 = OpTypeVector %4 3 556 %1 = OpTypeStruct %5 557 %6 = OpTypePointer Uniform %1 558 %8 = OpVariable %6 Uniform 559 %3 = OpVariable %6 Uniform 560 )"; 561 562 EXPECT_EQ(RunPass(spirv), result); 563 EXPECT_EQ(GetErrorMessage(), ""); 564 } 565 566 // In this test, %8 and %9 are the same and only %9 is used in a resource. 567 // However, we cannot merge them unless we also merge %2 and %3, which cannot 568 // happen because both are used in resources. 569 // 570 // If we try to avoid replaces resource types, then remove duplicates should 571 // have not change in this case. That is not currently implemented. 572 TEST_F(RemoveDuplicatesTest, MergeResourceTypeWithNonresourceType3) { 573 const std::string spirv = R"(OpCapability Shader 574 OpMemoryModel Logical GLSL450 575 OpEntryPoint GLCompute %1 "main" 576 OpSource HLSL 600 577 OpName %2 "PositionAdjust" 578 OpMemberName %2 0 "XAdjust" 579 OpName %3 "NormalAdjust" 580 OpMemberName %3 0 "XDir" 581 OpName %4 "Constants" 582 OpMemberDecorate %2 0 Offset 0 583 OpMemberDecorate %3 0 Offset 0 584 OpDecorate %4 DescriptorSet 0 585 OpDecorate %4 Binding 0 586 OpDecorate %5 DescriptorSet 1 587 OpDecorate %5 Binding 0 588 %6 = OpTypeFloat 32 589 %7 = OpTypeVector %6 3 590 %2 = OpTypeStruct %7 591 %3 = OpTypeStruct %7 592 %8 = OpTypePointer Uniform %3 593 %9 = OpTypePointer Uniform %2 594 %10 = OpTypeStruct %3 595 %11 = OpTypePointer Uniform %10 596 %5 = OpVariable %9 Uniform 597 %4 = OpVariable %11 Uniform 598 %12 = OpTypeVoid 599 %13 = OpTypeFunction %12 600 %14 = OpTypeInt 32 0 601 %15 = OpConstant %14 0 602 %1 = OpFunction %12 None %13 603 %16 = OpLabel 604 %17 = OpAccessChain %8 %4 %15 605 OpReturn 606 OpFunctionEnd 607 )"; 608 609 const std::string result = R"(OpCapability Shader 610 OpMemoryModel Logical GLSL450 611 OpEntryPoint GLCompute %1 "main" 612 OpSource HLSL 600 613 OpName %2 "PositionAdjust" 614 OpMemberName %2 0 "XAdjust" 615 OpName %4 "Constants" 616 OpMemberDecorate %2 0 Offset 0 617 OpDecorate %4 DescriptorSet 0 618 OpDecorate %4 Binding 0 619 OpDecorate %5 DescriptorSet 1 620 OpDecorate %5 Binding 0 621 %6 = OpTypeFloat 32 622 %7 = OpTypeVector %6 3 623 %2 = OpTypeStruct %7 624 %8 = OpTypePointer Uniform %2 625 %10 = OpTypeStruct %2 626 %11 = OpTypePointer Uniform %10 627 %5 = OpVariable %8 Uniform 628 %4 = OpVariable %11 Uniform 629 %12 = OpTypeVoid 630 %13 = OpTypeFunction %12 631 %14 = OpTypeInt 32 0 632 %15 = OpConstant %14 0 633 %1 = OpFunction %12 None %13 634 %16 = OpLabel 635 %17 = OpAccessChain %8 %4 %15 636 OpReturn 637 OpFunctionEnd 638 )"; 639 640 EXPECT_EQ(RunPass(spirv), result); 641 EXPECT_EQ(GetErrorMessage(), ""); 642 } 643 644 } // namespace 645 } // namespace opt 646 } // namespace spvtools 647