1 // Copyright (c) 2017 Valve Corporation
2 // Copyright (c) 2017 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <string>
17 
18 #include "source/opt/simplification_pass.h"
19 #include "test/opt/pass_fixture.h"
20 #include "test/opt/pass_utils.h"
21 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 using InsertExtractElimTest = PassTest<::testing::Test>;
27 
TEST_F(InsertExtractElimTest,Simple)28 TEST_F(InsertExtractElimTest, Simple) {
29   // Note: The SPIR-V assembly has had store/load elimination
30   // performed to allow the inserts and extracts to directly
31   // reference each other.
32   //
33   // #version 140
34   //
35   // in vec4 BaseColor;
36   //
37   // struct S_t {
38   //     vec4 v0;
39   //     vec4 v1;
40   // };
41   //
42   // void main()
43   // {
44   //     S_t s0;
45   //     s0.v1 = BaseColor;
46   //     gl_FragColor = s0.v1;
47   // }
48 
49   const std::string predefs =
50       R"(OpCapability Shader
51 %1 = OpExtInstImport "GLSL.std.450"
52 OpMemoryModel Logical GLSL450
53 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
54 OpExecutionMode %main OriginUpperLeft
55 OpSource GLSL 140
56 OpName %main "main"
57 OpName %S_t "S_t"
58 OpMemberName %S_t 0 "v0"
59 OpMemberName %S_t 1 "v1"
60 OpName %s0 "s0"
61 OpName %BaseColor "BaseColor"
62 OpName %gl_FragColor "gl_FragColor"
63 %void = OpTypeVoid
64 %8 = OpTypeFunction %void
65 %float = OpTypeFloat 32
66 %v4float = OpTypeVector %float 4
67 %S_t = OpTypeStruct %v4float %v4float
68 %_ptr_Function_S_t = OpTypePointer Function %S_t
69 %int = OpTypeInt 32 1
70 %int_1 = OpConstant %int 1
71 %_ptr_Input_v4float = OpTypePointer Input %v4float
72 %BaseColor = OpVariable %_ptr_Input_v4float Input
73 %_ptr_Function_v4float = OpTypePointer Function %v4float
74 %_ptr_Output_v4float = OpTypePointer Output %v4float
75 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
76 )";
77 
78   const std::string before =
79       R"(%main = OpFunction %void None %8
80 %17 = OpLabel
81 %s0 = OpVariable %_ptr_Function_S_t Function
82 %18 = OpLoad %v4float %BaseColor
83 %19 = OpLoad %S_t %s0
84 %20 = OpCompositeInsert %S_t %18 %19 1
85 OpStore %s0 %20
86 %21 = OpCompositeExtract %v4float %20 1
87 OpStore %gl_FragColor %21
88 OpReturn
89 OpFunctionEnd
90 )";
91 
92   const std::string after =
93       R"(%main = OpFunction %void None %8
94 %17 = OpLabel
95 %s0 = OpVariable %_ptr_Function_S_t Function
96 %18 = OpLoad %v4float %BaseColor
97 %19 = OpLoad %S_t %s0
98 %20 = OpCompositeInsert %S_t %18 %19 1
99 OpStore %s0 %20
100 OpStore %gl_FragColor %18
101 OpReturn
102 OpFunctionEnd
103 )";
104 
105   SinglePassRunAndCheck<SimplificationPass>(predefs + before, predefs + after,
106                                             true, true);
107 }
108 
TEST_F(InsertExtractElimTest,OptimizeAcrossNonConflictingInsert)109 TEST_F(InsertExtractElimTest, OptimizeAcrossNonConflictingInsert) {
110   // Note: The SPIR-V assembly has had store/load elimination
111   // performed to allow the inserts and extracts to directly
112   // reference each other.
113   //
114   // #version 140
115   //
116   // in vec4 BaseColor;
117   //
118   // struct S_t {
119   //     vec4 v0;
120   //     vec4 v1;
121   // };
122   //
123   // void main()
124   // {
125   //     S_t s0;
126   //     s0.v1 = BaseColor;
127   //     s0.v0[2] = 0.0;
128   //     gl_FragColor = s0.v1;
129   // }
130 
131   const std::string predefs =
132       R"(OpCapability Shader
133 %1 = OpExtInstImport "GLSL.std.450"
134 OpMemoryModel Logical GLSL450
135 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
136 OpExecutionMode %main OriginUpperLeft
137 OpSource GLSL 140
138 OpName %main "main"
139 OpName %S_t "S_t"
140 OpMemberName %S_t 0 "v0"
141 OpMemberName %S_t 1 "v1"
142 OpName %s0 "s0"
143 OpName %BaseColor "BaseColor"
144 OpName %gl_FragColor "gl_FragColor"
145 %void = OpTypeVoid
146 %8 = OpTypeFunction %void
147 %float = OpTypeFloat 32
148 %v4float = OpTypeVector %float 4
149 %S_t = OpTypeStruct %v4float %v4float
150 %_ptr_Function_S_t = OpTypePointer Function %S_t
151 %int = OpTypeInt 32 1
152 %int_1 = OpConstant %int 1
153 %float_0 = OpConstant %float 0
154 %_ptr_Input_v4float = OpTypePointer Input %v4float
155 %BaseColor = OpVariable %_ptr_Input_v4float Input
156 %_ptr_Function_v4float = OpTypePointer Function %v4float
157 %_ptr_Output_v4float = OpTypePointer Output %v4float
158 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
159 )";
160 
161   const std::string before =
162       R"(%main = OpFunction %void None %8
163 %18 = OpLabel
164 %s0 = OpVariable %_ptr_Function_S_t Function
165 %19 = OpLoad %v4float %BaseColor
166 %20 = OpLoad %S_t %s0
167 %21 = OpCompositeInsert %S_t %19 %20 1
168 %22 = OpCompositeInsert %S_t %float_0 %21 0 2
169 OpStore %s0 %22
170 %23 = OpCompositeExtract %v4float %22 1
171 OpStore %gl_FragColor %23
172 OpReturn
173 OpFunctionEnd
174 )";
175 
176   const std::string after =
177       R"(%main = OpFunction %void None %8
178 %18 = OpLabel
179 %s0 = OpVariable %_ptr_Function_S_t Function
180 %19 = OpLoad %v4float %BaseColor
181 %20 = OpLoad %S_t %s0
182 %21 = OpCompositeInsert %S_t %19 %20 1
183 %22 = OpCompositeInsert %S_t %float_0 %21 0 2
184 OpStore %s0 %22
185 OpStore %gl_FragColor %19
186 OpReturn
187 OpFunctionEnd
188 )";
189 
190   SinglePassRunAndCheck<SimplificationPass>(predefs + before, predefs + after,
191                                             true, true);
192 }
193 
TEST_F(InsertExtractElimTest,OptimizeOpaque)194 TEST_F(InsertExtractElimTest, OptimizeOpaque) {
195   // SPIR-V not representable in GLSL; not generatable from HLSL
196   // for the moment.
197 
198   const std::string predefs =
199       R"(OpCapability Shader
200 %1 = OpExtInstImport "GLSL.std.450"
201 OpMemoryModel Logical GLSL450
202 OpEntryPoint Fragment %main "main" %outColor %texCoords
203 OpExecutionMode %main OriginUpperLeft
204 OpSource GLSL 140
205 OpName %main "main"
206 OpName %S_t "S_t"
207 OpMemberName %S_t 0 "v0"
208 OpMemberName %S_t 1 "v1"
209 OpMemberName %S_t 2 "smp"
210 OpName %outColor "outColor"
211 OpName %sampler15 "sampler15"
212 OpName %s0 "s0"
213 OpName %texCoords "texCoords"
214 OpDecorate %sampler15 DescriptorSet 0
215 %void = OpTypeVoid
216 %9 = OpTypeFunction %void
217 %float = OpTypeFloat 32
218 %v2float = OpTypeVector %float 2
219 %v4float = OpTypeVector %float 4
220 %_ptr_Output_v4float = OpTypePointer Output %v4float
221 %outColor = OpVariable %_ptr_Output_v4float Output
222 %14 = OpTypeImage %float 2D 0 0 0 1 Unknown
223 %15 = OpTypeSampledImage %14
224 %S_t = OpTypeStruct %v2float %v2float %15
225 %_ptr_Function_S_t = OpTypePointer Function %S_t
226 %17 = OpTypeFunction %void %_ptr_Function_S_t
227 %_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15
228 %_ptr_Function_15 = OpTypePointer Function %15
229 %sampler15 = OpVariable %_ptr_UniformConstant_15 UniformConstant
230 %int = OpTypeInt 32 1
231 %int_0 = OpConstant %int 0
232 %int_2 = OpConstant %int 2
233 %_ptr_Function_v2float = OpTypePointer Function %v2float
234 %_ptr_Input_v2float = OpTypePointer Input %v2float
235 %texCoords = OpVariable %_ptr_Input_v2float Input
236 )";
237 
238   const std::string before =
239       R"(%main = OpFunction %void None %9
240 %25 = OpLabel
241 %s0 = OpVariable %_ptr_Function_S_t Function
242 %26 = OpLoad %v2float %texCoords
243 %27 = OpLoad %S_t %s0
244 %28 = OpCompositeInsert %S_t %26 %27 0
245 %29 = OpLoad %15 %sampler15
246 %30 = OpCompositeInsert %S_t %29 %28 2
247 OpStore %s0 %30
248 %31 = OpCompositeExtract %15 %30 2
249 %32 = OpCompositeExtract %v2float %30 0
250 %33 = OpImageSampleImplicitLod %v4float %31 %32
251 OpStore %outColor %33
252 OpReturn
253 OpFunctionEnd
254 )";
255 
256   const std::string after =
257       R"(%main = OpFunction %void None %9
258 %25 = OpLabel
259 %s0 = OpVariable %_ptr_Function_S_t Function
260 %26 = OpLoad %v2float %texCoords
261 %27 = OpLoad %S_t %s0
262 %28 = OpCompositeInsert %S_t %26 %27 0
263 %29 = OpLoad %15 %sampler15
264 %30 = OpCompositeInsert %S_t %29 %28 2
265 OpStore %s0 %30
266 %33 = OpImageSampleImplicitLod %v4float %29 %26
267 OpStore %outColor %33
268 OpReturn
269 OpFunctionEnd
270 )";
271 
272   SinglePassRunAndCheck<SimplificationPass>(predefs + before, predefs + after,
273                                             true, true);
274 }
275 
TEST_F(InsertExtractElimTest,OptimizeNestedStruct)276 TEST_F(InsertExtractElimTest, OptimizeNestedStruct) {
277   // The following HLSL has been pre-optimized to get the SPIR-V:
278   // struct S0
279   // {
280   //     int x;
281   //     SamplerState ss;
282   // };
283   //
284   // struct S1
285   // {
286   //     float b;
287   //     S0 s0;
288   // };
289   //
290   // struct S2
291   // {
292   //     int a1;
293   //     S1 resources;
294   // };
295   //
296   // SamplerState samp;
297   // Texture2D tex;
298   //
299   // float4 main(float4 vpos : VPOS) : COLOR0
300   // {
301   //     S1 s1;
302   //     S2 s2;
303   //     s1.s0.ss = samp;
304   //     s2.resources = s1;
305   //     return tex.Sample(s2.resources.s0.ss, float2(0.5));
306   // }
307 
308   const std::string predefs =
309       R"(OpCapability Shader
310 %1 = OpExtInstImport "GLSL.std.450"
311 OpMemoryModel Logical GLSL450
312 OpEntryPoint Fragment %main "main" %_entryPointOutput
313 OpExecutionMode %main OriginUpperLeft
314 OpSource HLSL 500
315 OpName %main "main"
316 OpName %S0 "S0"
317 OpMemberName %S0 0 "x"
318 OpMemberName %S0 1 "ss"
319 OpName %S1 "S1"
320 OpMemberName %S1 0 "b"
321 OpMemberName %S1 1 "s0"
322 OpName %samp "samp"
323 OpName %S2 "S2"
324 OpMemberName %S2 0 "a1"
325 OpMemberName %S2 1 "resources"
326 OpName %tex "tex"
327 OpName %_entryPointOutput "@entryPointOutput"
328 OpDecorate %samp DescriptorSet 0
329 OpDecorate %tex DescriptorSet 0
330 OpDecorate %_entryPointOutput Location 0
331 %void = OpTypeVoid
332 %10 = OpTypeFunction %void
333 %float = OpTypeFloat 32
334 %v4float = OpTypeVector %float 4
335 %_ptr_Function_v4float = OpTypePointer Function %v4float
336 %14 = OpTypeFunction %v4float %_ptr_Function_v4float
337 %int = OpTypeInt 32 1
338 %16 = OpTypeSampler
339 %S0 = OpTypeStruct %int %16
340 %S1 = OpTypeStruct %float %S0
341 %_ptr_Function_S1 = OpTypePointer Function %S1
342 %int_1 = OpConstant %int 1
343 %_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16
344 %samp = OpVariable %_ptr_UniformConstant_16 UniformConstant
345 %_ptr_Function_16 = OpTypePointer Function %16
346 %S2 = OpTypeStruct %int %S1
347 %_ptr_Function_S2 = OpTypePointer Function %S2
348 %22 = OpTypeImage %float 2D 0 0 0 1 Unknown
349 %_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22
350 %tex = OpVariable %_ptr_UniformConstant_22 UniformConstant
351 %24 = OpTypeSampledImage %22
352 %v2float = OpTypeVector %float 2
353 %float_0_5 = OpConstant %float 0.5
354 %27 = OpConstantComposite %v2float %float_0_5 %float_0_5
355 %_ptr_Input_v4float = OpTypePointer Input %v4float
356 %_ptr_Output_v4float = OpTypePointer Output %v4float
357 %_entryPointOutput = OpVariable %_ptr_Output_v4float Output
358 )";
359 
360   const std::string before =
361       R"(%main = OpFunction %void None %10
362 %30 = OpLabel
363 %31 = OpVariable %_ptr_Function_S1 Function
364 %32 = OpVariable %_ptr_Function_S2 Function
365 %33 = OpLoad %16 %samp
366 %34 = OpLoad %S1 %31
367 %35 = OpCompositeInsert %S1 %33 %34 1 1
368 OpStore %31 %35
369 %36 = OpLoad %S2 %32
370 %37 = OpCompositeInsert %S2 %35 %36 1
371 OpStore %32 %37
372 %38 = OpLoad %22 %tex
373 %39 = OpCompositeExtract %16 %37 1 1 1
374 %40 = OpSampledImage %24 %38 %39
375 %41 = OpImageSampleImplicitLod %v4float %40 %27
376 OpStore %_entryPointOutput %41
377 OpReturn
378 OpFunctionEnd
379 )";
380 
381   const std::string after =
382       R"(%main = OpFunction %void None %10
383 %30 = OpLabel
384 %31 = OpVariable %_ptr_Function_S1 Function
385 %32 = OpVariable %_ptr_Function_S2 Function
386 %33 = OpLoad %16 %samp
387 %34 = OpLoad %S1 %31
388 %35 = OpCompositeInsert %S1 %33 %34 1 1
389 OpStore %31 %35
390 %36 = OpLoad %S2 %32
391 %37 = OpCompositeInsert %S2 %35 %36 1
392 OpStore %32 %37
393 %38 = OpLoad %22 %tex
394 %40 = OpSampledImage %24 %38 %33
395 %41 = OpImageSampleImplicitLod %v4float %40 %27
396 OpStore %_entryPointOutput %41
397 OpReturn
398 OpFunctionEnd
399 )";
400 
401   SinglePassRunAndCheck<SimplificationPass>(predefs + before, predefs + after,
402                                             true, true);
403 }
404 
TEST_F(InsertExtractElimTest,ConflictingInsertPreventsOptimization)405 TEST_F(InsertExtractElimTest, ConflictingInsertPreventsOptimization) {
406   // Note: The SPIR-V assembly has had store/load elimination
407   // performed to allow the inserts and extracts to directly
408   // reference each other.
409   //
410   // #version 140
411   //
412   // in vec4 BaseColor;
413   //
414   // struct S_t {
415   //     vec4 v0;
416   //     vec4 v1;
417   // };
418   //
419   // void main()
420   // {
421   //     S_t s0;
422   //     s0.v1 = BaseColor;
423   //     s0.v1[2] = 0.0;
424   //     gl_FragColor = s0.v1;
425   // }
426 
427   const std::string assembly =
428       R"(OpCapability Shader
429 %1 = OpExtInstImport "GLSL.std.450"
430 OpMemoryModel Logical GLSL450
431 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
432 OpExecutionMode %main OriginUpperLeft
433 OpSource GLSL 140
434 OpName %main "main"
435 OpName %S_t "S_t"
436 OpMemberName %S_t 0 "v0"
437 OpMemberName %S_t 1 "v1"
438 OpName %s0 "s0"
439 OpName %BaseColor "BaseColor"
440 OpName %gl_FragColor "gl_FragColor"
441 %void = OpTypeVoid
442 %8 = OpTypeFunction %void
443 %float = OpTypeFloat 32
444 %v4float = OpTypeVector %float 4
445 %S_t = OpTypeStruct %v4float %v4float
446 %_ptr_Function_S_t = OpTypePointer Function %S_t
447 %int = OpTypeInt 32 1
448 %int_1 = OpConstant %int 1
449 %float_0 = OpConstant %float 0
450 %_ptr_Input_v4float = OpTypePointer Input %v4float
451 %BaseColor = OpVariable %_ptr_Input_v4float Input
452 %_ptr_Function_v4float = OpTypePointer Function %v4float
453 %_ptr_Output_v4float = OpTypePointer Output %v4float
454 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
455 %main = OpFunction %void None %8
456 %18 = OpLabel
457 %s0 = OpVariable %_ptr_Function_S_t Function
458 %19 = OpLoad %v4float %BaseColor
459 %20 = OpLoad %S_t %s0
460 %21 = OpCompositeInsert %S_t %19 %20 1
461 %22 = OpCompositeInsert %S_t %float_0 %21 1 2
462 OpStore %s0 %22
463 %23 = OpCompositeExtract %v4float %22 1
464 OpStore %gl_FragColor %23
465 OpReturn
466 OpFunctionEnd
467 )";
468 
469   SinglePassRunAndCheck<SimplificationPass>(assembly, assembly, true, true);
470 }
471 
TEST_F(InsertExtractElimTest,ConflictingInsertPreventsOptimization2)472 TEST_F(InsertExtractElimTest, ConflictingInsertPreventsOptimization2) {
473   // Note: The SPIR-V assembly has had store/load elimination
474   // performed to allow the inserts and extracts to directly
475   // reference each other.
476   //
477   // #version 140
478   //
479   // in vec4 BaseColor;
480   //
481   // struct S_t {
482   //     vec4 v0;
483   //     vec4 v1;
484   // };
485   //
486   // void main()
487   // {
488   //     S_t s0;
489   //     s0.v1[1] = 1.0; // dead
490   //     s0.v1 = Baseline;
491   //     gl_FragColor = vec4(s0.v1[1], 0.0, 0.0, 0.0);
492   // }
493 
494   const std::string before_predefs =
495       R"(OpCapability Shader
496 %1 = OpExtInstImport "GLSL.std.450"
497 OpMemoryModel Logical GLSL450
498 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
499 OpExecutionMode %main OriginUpperLeft
500 OpSource GLSL 140
501 OpName %main "main"
502 OpName %S_t "S_t"
503 OpMemberName %S_t 0 "v0"
504 OpMemberName %S_t 1 "v1"
505 OpName %s0 "s0"
506 OpName %BaseColor "BaseColor"
507 OpName %gl_FragColor "gl_FragColor"
508 %void = OpTypeVoid
509 %8 = OpTypeFunction %void
510 %float = OpTypeFloat 32
511 %v4float = OpTypeVector %float 4
512 %S_t = OpTypeStruct %v4float %v4float
513 %_ptr_Function_S_t = OpTypePointer Function %S_t
514 %int = OpTypeInt 32 1
515 %int_1 = OpConstant %int 1
516 %float_1 = OpConstant %float 1
517 %uint = OpTypeInt 32 0
518 %uint_1 = OpConstant %uint 1
519 %_ptr_Function_float = OpTypePointer Function %float
520 %_ptr_Input_v4float = OpTypePointer Input %v4float
521 %BaseColor = OpVariable %_ptr_Input_v4float Input
522 %_ptr_Function_v4float = OpTypePointer Function %v4float
523 %_ptr_Output_v4float = OpTypePointer Output %v4float
524 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
525 %float_0 = OpConstant %float 0
526 )";
527 
528   const std::string after_predefs =
529       R"(OpCapability Shader
530 %1 = OpExtInstImport "GLSL.std.450"
531 OpMemoryModel Logical GLSL450
532 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
533 OpExecutionMode %main OriginUpperLeft
534 OpSource GLSL 140
535 OpName %main "main"
536 OpName %S_t "S_t"
537 OpMemberName %S_t 0 "v0"
538 OpMemberName %S_t 1 "v1"
539 OpName %s0 "s0"
540 OpName %BaseColor "BaseColor"
541 OpName %gl_FragColor "gl_FragColor"
542 %void = OpTypeVoid
543 %8 = OpTypeFunction %void
544 %float = OpTypeFloat 32
545 %v4float = OpTypeVector %float 4
546 %S_t = OpTypeStruct %v4float %v4float
547 %_ptr_Function_S_t = OpTypePointer Function %S_t
548 %int = OpTypeInt 32 1
549 %int_1 = OpConstant %int 1
550 %float_1 = OpConstant %float 1
551 %uint = OpTypeInt 32 0
552 %uint_1 = OpConstant %uint 1
553 %_ptr_Function_float = OpTypePointer Function %float
554 %_ptr_Input_v4float = OpTypePointer Input %v4float
555 %BaseColor = OpVariable %_ptr_Input_v4float Input
556 %_ptr_Function_v4float = OpTypePointer Function %v4float
557 %_ptr_Output_v4float = OpTypePointer Output %v4float
558 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
559 %float_0 = OpConstant %float 0
560 )";
561 
562   const std::string before =
563       R"(%main = OpFunction %void None %8
564 %22 = OpLabel
565 %s0 = OpVariable %_ptr_Function_S_t Function
566 %23 = OpLoad %S_t %s0
567 %24 = OpCompositeInsert %S_t %float_1 %23 1 1
568 %25 = OpLoad %v4float %BaseColor
569 %26 = OpCompositeInsert %S_t %25 %24 1
570 %27 = OpCompositeExtract %float %26 1 1
571 %28 = OpCompositeConstruct %v4float %27 %float_0 %float_0 %float_0
572 OpStore %gl_FragColor %28
573 OpReturn
574 OpFunctionEnd
575 )";
576 
577   const std::string after =
578       R"(%main = OpFunction %void None %8
579 %22 = OpLabel
580 %s0 = OpVariable %_ptr_Function_S_t Function
581 %23 = OpLoad %S_t %s0
582 %24 = OpCompositeInsert %S_t %float_1 %23 1 1
583 %25 = OpLoad %v4float %BaseColor
584 %26 = OpCompositeInsert %S_t %25 %24 1
585 %27 = OpCompositeExtract %float %25 1
586 %28 = OpCompositeConstruct %v4float %27 %float_0 %float_0 %float_0
587 OpStore %gl_FragColor %28
588 OpReturn
589 OpFunctionEnd
590 )";
591 
592   SinglePassRunAndCheck<SimplificationPass>(before_predefs + before,
593                                             after_predefs + after, true, true);
594 }
595 
TEST_F(InsertExtractElimTest,MixWithConstants)596 TEST_F(InsertExtractElimTest, MixWithConstants) {
597   // Extract component of FMix with 0.0 or 1.0 as the a-value.
598   //
599   // Note: The SPIR-V assembly has had store/load elimination
600   // performed to allow the inserts and extracts to directly
601   // reference each other.
602   //
603   // #version 450
604   //
605   // layout (location=0) in float bc;
606   // layout (location=1) in float bc2;
607   // layout (location=2) in float m;
608   // layout (location=3) in float m2;
609   // layout (location=0) out vec4 OutColor;
610   //
611   // void main()
612   // {
613   //     vec4 bcv = vec4(bc, bc2, 0.0, 1.0);
614   //     vec4 bcv2 = vec4(bc2, bc, 1.0, 0.0);
615   //     vec4 v = mix(bcv, bcv2, vec4(0.0,1.0,m,m2));
616   //     OutColor = vec4(v.y);
617   // }
618 
619   const std::string predefs =
620       R"(OpCapability Shader
621 %1 = OpExtInstImport "GLSL.std.450"
622 OpMemoryModel Logical GLSL450
623 OpEntryPoint Fragment %main "main" %bc %bc2 %m %m2 %OutColor
624 OpExecutionMode %main OriginUpperLeft
625 OpSource GLSL 450
626 OpName %main "main"
627 OpName %bc "bc"
628 OpName %bc2 "bc2"
629 OpName %m "m"
630 OpName %m2 "m2"
631 OpName %OutColor "OutColor"
632 OpDecorate %bc Location 0
633 OpDecorate %bc2 Location 1
634 OpDecorate %m Location 2
635 OpDecorate %m2 Location 3
636 OpDecorate %OutColor Location 0
637 %void = OpTypeVoid
638 %9 = OpTypeFunction %void
639 %float = OpTypeFloat 32
640 %v4float = OpTypeVector %float 4
641 %_ptr_Function_v4float = OpTypePointer Function %v4float
642 %_ptr_Input_float = OpTypePointer Input %float
643 %bc = OpVariable %_ptr_Input_float Input
644 %bc2 = OpVariable %_ptr_Input_float Input
645 %float_0 = OpConstant %float 0
646 %float_1 = OpConstant %float 1
647 %m = OpVariable %_ptr_Input_float Input
648 %m2 = OpVariable %_ptr_Input_float Input
649 %_ptr_Output_v4float = OpTypePointer Output %v4float
650 %OutColor = OpVariable %_ptr_Output_v4float Output
651 %uint = OpTypeInt 32 0
652 %_ptr_Function_float = OpTypePointer Function %float
653 )";
654 
655   const std::string before =
656       R"(%main = OpFunction %void None %9
657 %19 = OpLabel
658 %20 = OpLoad %float %bc
659 %21 = OpLoad %float %bc2
660 %22 = OpCompositeConstruct %v4float %20 %21 %float_0 %float_1
661 %23 = OpLoad %float %bc2
662 %24 = OpLoad %float %bc
663 %25 = OpCompositeConstruct %v4float %23 %24 %float_1 %float_0
664 %26 = OpLoad %float %m
665 %27 = OpLoad %float %m2
666 %28 = OpCompositeConstruct %v4float %float_0 %float_1 %26 %27
667 %29 = OpExtInst %v4float %1 FMix %22 %25 %28
668 %30 = OpCompositeExtract %float %29 1
669 %31 = OpCompositeConstruct %v4float %30 %30 %30 %30
670 OpStore %OutColor %31
671 OpReturn
672 OpFunctionEnd
673 )";
674 
675   const std::string after =
676       R"(%main = OpFunction %void None %9
677 %19 = OpLabel
678 %20 = OpLoad %float %bc
679 %21 = OpLoad %float %bc2
680 %22 = OpCompositeConstruct %v4float %20 %21 %float_0 %float_1
681 %23 = OpLoad %float %bc2
682 %24 = OpLoad %float %bc
683 %25 = OpCompositeConstruct %v4float %23 %24 %float_1 %float_0
684 %26 = OpLoad %float %m
685 %27 = OpLoad %float %m2
686 %28 = OpCompositeConstruct %v4float %float_0 %float_1 %26 %27
687 %29 = OpExtInst %v4float %1 FMix %22 %25 %28
688 %31 = OpCompositeConstruct %v4float %24 %24 %24 %24
689 OpStore %OutColor %31
690 OpReturn
691 OpFunctionEnd
692 )";
693 
694   SinglePassRunAndCheck<SimplificationPass>(predefs + before, predefs + after,
695                                             true, true);
696 }
697 
TEST_F(InsertExtractElimTest,VectorShuffle1)698 TEST_F(InsertExtractElimTest, VectorShuffle1) {
699   // Extract component from first vector in VectorShuffle
700   //
701   // Note: The SPIR-V assembly has had store/load elimination
702   // performed to allow the inserts and extracts to directly
703   // reference each other.
704   //
705   // #version 450
706   //
707   // layout (location=0) in float bc;
708   // layout (location=1) in float bc2;
709   // layout (location=0) out vec4 OutColor;
710   //
711   // void main()
712   // {
713   //     vec4 bcv = vec4(bc, bc2, 0.0, 1.0);
714   //     vec4 v = bcv.zwxy;
715   //     OutColor = vec4(v.y);
716   // }
717 
718   const std::string predefs_before =
719       R"(OpCapability Shader
720 %1 = OpExtInstImport "GLSL.std.450"
721 OpMemoryModel Logical GLSL450
722 OpEntryPoint Fragment %main "main" %bc %bc2 %OutColor
723 OpExecutionMode %main OriginUpperLeft
724 OpSource GLSL 450
725 OpName %main "main"
726 OpName %bc "bc"
727 OpName %bc2 "bc2"
728 OpName %OutColor "OutColor"
729 OpDecorate %bc Location 0
730 OpDecorate %bc2 Location 1
731 OpDecorate %OutColor Location 0
732 %void = OpTypeVoid
733 %7 = OpTypeFunction %void
734 %float = OpTypeFloat 32
735 %v4float = OpTypeVector %float 4
736 %_ptr_Function_v4float = OpTypePointer Function %v4float
737 %_ptr_Input_float = OpTypePointer Input %float
738 %bc = OpVariable %_ptr_Input_float Input
739 %bc2 = OpVariable %_ptr_Input_float Input
740 %float_0 = OpConstant %float 0
741 %float_1 = OpConstant %float 1
742 %_ptr_Output_v4float = OpTypePointer Output %v4float
743 %OutColor = OpVariable %_ptr_Output_v4float Output
744 %uint = OpTypeInt 32 0
745 %_ptr_Function_float = OpTypePointer Function %float
746 )";
747 
748   const std::string predefs_after = predefs_before +
749                                     "%24 = OpConstantComposite %v4float "
750                                     "%float_1 %float_1 %float_1 %float_1\n";
751 
752   const std::string before =
753       R"(%main = OpFunction %void None %7
754 %17 = OpLabel
755 %18 = OpLoad %float %bc
756 %19 = OpLoad %float %bc2
757 %20 = OpCompositeConstruct %v4float %18 %19 %float_0 %float_1
758 %21 = OpVectorShuffle %v4float %20 %20 2 3 0 1
759 %22 = OpCompositeExtract %float %21 1
760 %23 = OpCompositeConstruct %v4float %22 %22 %22 %22
761 OpStore %OutColor %23
762 OpReturn
763 OpFunctionEnd
764 )";
765 
766   const std::string after =
767       R"(%main = OpFunction %void None %7
768 %17 = OpLabel
769 %18 = OpLoad %float %bc
770 %19 = OpLoad %float %bc2
771 %20 = OpCompositeConstruct %v4float %18 %19 %float_0 %float_1
772 %21 = OpVectorShuffle %v4float %20 %20 2 3 0 1
773 OpStore %OutColor %24
774 OpReturn
775 OpFunctionEnd
776 )";
777 
778   SinglePassRunAndCheck<SimplificationPass>(predefs_before + before,
779                                             predefs_after + after, true, true);
780 }
781 
TEST_F(InsertExtractElimTest,VectorShuffle2)782 TEST_F(InsertExtractElimTest, VectorShuffle2) {
783   // Extract component from second vector in VectorShuffle
784   // Identical to test VectorShuffle1 except for the vector
785   // shuffle index of 7.
786   //
787   // Note: The SPIR-V assembly has had store/load elimination
788   // performed to allow the inserts and extracts to directly
789   // reference each other.
790   //
791   // #version 450
792   //
793   // layout (location=0) in float bc;
794   // layout (location=1) in float bc2;
795   // layout (location=0) out vec4 OutColor;
796   //
797   // void main()
798   // {
799   //     vec4 bcv = vec4(bc, bc2, 0.0, 1.0);
800   //     vec4 v = bcv.zwxy;
801   //     OutColor = vec4(v.y);
802   // }
803 
804   const std::string predefs_before =
805       R"(OpCapability Shader
806 %1 = OpExtInstImport "GLSL.std.450"
807 OpMemoryModel Logical GLSL450
808 OpEntryPoint Fragment %main "main" %bc %bc2 %OutColor
809 OpExecutionMode %main OriginUpperLeft
810 OpSource GLSL 450
811 OpName %main "main"
812 OpName %bc "bc"
813 OpName %bc2 "bc2"
814 OpName %OutColor "OutColor"
815 OpDecorate %bc Location 0
816 OpDecorate %bc2 Location 1
817 OpDecorate %OutColor Location 0
818 %void = OpTypeVoid
819 %7 = OpTypeFunction %void
820 %float = OpTypeFloat 32
821 %v4float = OpTypeVector %float 4
822 %_ptr_Function_v4float = OpTypePointer Function %v4float
823 %_ptr_Input_float = OpTypePointer Input %float
824 %bc = OpVariable %_ptr_Input_float Input
825 %bc2 = OpVariable %_ptr_Input_float Input
826 %float_0 = OpConstant %float 0
827 %float_1 = OpConstant %float 1
828 %_ptr_Output_v4float = OpTypePointer Output %v4float
829 %OutColor = OpVariable %_ptr_Output_v4float Output
830 %uint = OpTypeInt 32 0
831 %_ptr_Function_float = OpTypePointer Function %float
832 )";
833 
834   const std::string predefs_after =
835       R"(OpCapability Shader
836 %1 = OpExtInstImport "GLSL.std.450"
837 OpMemoryModel Logical GLSL450
838 OpEntryPoint Fragment %main "main" %bc %bc2 %OutColor
839 OpExecutionMode %main OriginUpperLeft
840 OpSource GLSL 450
841 OpName %main "main"
842 OpName %bc "bc"
843 OpName %bc2 "bc2"
844 OpName %OutColor "OutColor"
845 OpDecorate %bc Location 0
846 OpDecorate %bc2 Location 1
847 OpDecorate %OutColor Location 0
848 %void = OpTypeVoid
849 %7 = OpTypeFunction %void
850 %float = OpTypeFloat 32
851 %v4float = OpTypeVector %float 4
852 %_ptr_Function_v4float = OpTypePointer Function %v4float
853 %_ptr_Input_float = OpTypePointer Input %float
854 %bc = OpVariable %_ptr_Input_float Input
855 %bc2 = OpVariable %_ptr_Input_float Input
856 %float_0 = OpConstant %float 0
857 %float_1 = OpConstant %float 1
858 %_ptr_Output_v4float = OpTypePointer Output %v4float
859 %OutColor = OpVariable %_ptr_Output_v4float Output
860 %uint = OpTypeInt 32 0
861 %_ptr_Function_float = OpTypePointer Function %float
862 %24 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
863 )";
864 
865   const std::string before =
866       R"(%main = OpFunction %void None %7
867 %17 = OpLabel
868 %18 = OpLoad %float %bc
869 %19 = OpLoad %float %bc2
870 %20 = OpCompositeConstruct %v4float %18 %19 %float_0 %float_1
871 %21 = OpVectorShuffle %v4float %20 %20 2 7 0 1
872 %22 = OpCompositeExtract %float %21 1
873 %23 = OpCompositeConstruct %v4float %22 %22 %22 %22
874 OpStore %OutColor %23
875 OpReturn
876 OpFunctionEnd
877 )";
878 
879   const std::string after =
880       R"(%main = OpFunction %void None %7
881 %17 = OpLabel
882 %18 = OpLoad %float %bc
883 %19 = OpLoad %float %bc2
884 %20 = OpCompositeConstruct %v4float %18 %19 %float_0 %float_1
885 %21 = OpVectorShuffle %v4float %20 %20 2 7 0 1
886 OpStore %OutColor %24
887 OpReturn
888 OpFunctionEnd
889 )";
890 
891   SinglePassRunAndCheck<SimplificationPass>(predefs_before + before,
892                                             predefs_after + after, true, true);
893 }
894 
895 // TODO(greg-lunarg): Add tests to verify handling of these cases:
896 //
897 
898 }  // namespace
899 }  // namespace opt
900 }  // namespace spvtools
901