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