Home | History | Annotate | Download | only in opt
      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