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 "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using LocalSingleBlockLoadStoreElimTest = PassTest<::testing::Test>;
26 
TEST_F(LocalSingleBlockLoadStoreElimTest,SimpleStoreLoadElim)27 TEST_F(LocalSingleBlockLoadStoreElimTest, SimpleStoreLoadElim) {
28   // #version 140
29   //
30   // in vec4 BaseColor;
31   //
32   // void main()
33   // {
34   //     vec4 v = BaseColor;
35   //     gl_FragColor = v;
36   // }
37 
38   const std::string predefs_before =
39       R"(OpCapability Shader
40 %1 = OpExtInstImport "GLSL.std.450"
41 OpMemoryModel Logical GLSL450
42 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
43 OpExecutionMode %main OriginUpperLeft
44 OpSource GLSL 140
45 OpName %main "main"
46 OpName %v "v"
47 OpName %BaseColor "BaseColor"
48 OpName %gl_FragColor "gl_FragColor"
49 %void = OpTypeVoid
50 %7 = OpTypeFunction %void
51 %float = OpTypeFloat 32
52 %v4float = OpTypeVector %float 4
53 %_ptr_Function_v4float = OpTypePointer Function %v4float
54 %_ptr_Input_v4float = OpTypePointer Input %v4float
55 %BaseColor = OpVariable %_ptr_Input_v4float Input
56 %_ptr_Output_v4float = OpTypePointer Output %v4float
57 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
58 )";
59 
60   const std::string before =
61       R"(%main = OpFunction %void None %7
62 %13 = OpLabel
63 %v = OpVariable %_ptr_Function_v4float Function
64 %14 = OpLoad %v4float %BaseColor
65 OpStore %v %14
66 %15 = OpLoad %v4float %v
67 OpStore %gl_FragColor %15
68 OpReturn
69 OpFunctionEnd
70 )";
71 
72   const std::string after =
73       R"(%main = OpFunction %void None %7
74 %13 = OpLabel
75 %v = OpVariable %_ptr_Function_v4float Function
76 %14 = OpLoad %v4float %BaseColor
77 OpStore %v %14
78 OpStore %gl_FragColor %14
79 OpReturn
80 OpFunctionEnd
81 )";
82 
83   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
84       predefs_before + before, predefs_before + after, true, true);
85 }
86 
TEST_F(LocalSingleBlockLoadStoreElimTest,LSBElimForLinkage)87 TEST_F(LocalSingleBlockLoadStoreElimTest, LSBElimForLinkage) {
88   const std::string predefs_before =
89       R"(OpCapability Shader
90 OpCapability Linkage
91 %1 = OpExtInstImport "GLSL.std.450"
92 OpMemoryModel Logical GLSL450
93 OpSource HLSL 630
94 OpName %main "main"
95 OpName %v "v"
96 OpName %BaseColor "BaseColor"
97 OpName %gl_FragColor "gl_FragColor"
98 OpDecorate %main LinkageAttributes "main" Export
99 %void = OpTypeVoid
100 %7 = OpTypeFunction %void
101 %float = OpTypeFloat 32
102 %v4float = OpTypeVector %float 4
103 %_ptr_Function_v4float = OpTypePointer Function %v4float
104 %_ptr_Input_v4float = OpTypePointer Input %v4float
105 %BaseColor = OpVariable %_ptr_Input_v4float Input
106 %_ptr_Output_v4float = OpTypePointer Output %v4float
107 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
108 )";
109 
110   const std::string before =
111       R"(%main = OpFunction %void None %7
112 %13 = OpLabel
113 %v = OpVariable %_ptr_Function_v4float Function
114 %14 = OpLoad %v4float %BaseColor
115 OpStore %v %14
116 %15 = OpLoad %v4float %v
117 OpStore %gl_FragColor %15
118 OpReturn
119 OpFunctionEnd
120 )";
121 
122   const std::string after =
123       R"(%main = OpFunction %void None %7
124 %13 = OpLabel
125 %v = OpVariable %_ptr_Function_v4float Function
126 %14 = OpLoad %v4float %BaseColor
127 OpStore %v %14
128 OpStore %gl_FragColor %14
129 OpReturn
130 OpFunctionEnd
131 )";
132 
133   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
134       predefs_before + before, predefs_before + after, true, true);
135 }
136 
TEST_F(LocalSingleBlockLoadStoreElimTest,SimpleLoadLoadElim)137 TEST_F(LocalSingleBlockLoadStoreElimTest, SimpleLoadLoadElim) {
138   // #version 140
139   //
140   // in vec4 BaseColor;
141   // in float fi;
142   //
143   // void main()
144   // {
145   //     vec4 v = BaseColor;
146   //     if (fi < 0)
147   //         v = vec4(0.0);
148   //     gl_FragData[0] = v;
149   //     gl_FragData[1] = v;
150   // }
151 
152   const std::string predefs =
153       R"(OpCapability Shader
154 %1 = OpExtInstImport "GLSL.std.450"
155 OpMemoryModel Logical GLSL450
156 OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragData
157 OpExecutionMode %main OriginUpperLeft
158 OpSource GLSL 140
159 OpName %main "main"
160 OpName %v "v"
161 OpName %BaseColor "BaseColor"
162 OpName %fi "fi"
163 OpName %gl_FragData "gl_FragData"
164 %void = OpTypeVoid
165 %8 = OpTypeFunction %void
166 %float = OpTypeFloat 32
167 %v4float = OpTypeVector %float 4
168 %_ptr_Function_v4float = OpTypePointer Function %v4float
169 %_ptr_Input_v4float = OpTypePointer Input %v4float
170 %BaseColor = OpVariable %_ptr_Input_v4float Input
171 %_ptr_Input_float = OpTypePointer Input %float
172 %fi = OpVariable %_ptr_Input_float Input
173 %float_0 = OpConstant %float 0
174 %bool = OpTypeBool
175 %16 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
176 %uint = OpTypeInt 32 0
177 %uint_32 = OpConstant %uint 32
178 %_arr_v4float_uint_32 = OpTypeArray %v4float %uint_32
179 %_ptr_Output__arr_v4float_uint_32 = OpTypePointer Output %_arr_v4float_uint_32
180 %gl_FragData = OpVariable %_ptr_Output__arr_v4float_uint_32 Output
181 %int = OpTypeInt 32 1
182 %int_0 = OpConstant %int 0
183 %_ptr_Output_v4float = OpTypePointer Output %v4float
184 %int_1 = OpConstant %int 1
185 )";
186 
187   const std::string before =
188       R"(%main = OpFunction %void None %8
189 %25 = OpLabel
190 %v = OpVariable %_ptr_Function_v4float Function
191 %26 = OpLoad %v4float %BaseColor
192 OpStore %v %26
193 %27 = OpLoad %float %fi
194 %28 = OpFOrdLessThan %bool %27 %float_0
195 OpSelectionMerge %29 None
196 OpBranchConditional %28 %30 %29
197 %30 = OpLabel
198 OpStore %v %16
199 OpBranch %29
200 %29 = OpLabel
201 %31 = OpLoad %v4float %v
202 %32 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
203 OpStore %32 %31
204 %33 = OpLoad %v4float %v
205 %34 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
206 OpStore %34 %33
207 OpReturn
208 OpFunctionEnd
209 )";
210 
211   const std::string after =
212       R"(%main = OpFunction %void None %8
213 %25 = OpLabel
214 %v = OpVariable %_ptr_Function_v4float Function
215 %26 = OpLoad %v4float %BaseColor
216 OpStore %v %26
217 %27 = OpLoad %float %fi
218 %28 = OpFOrdLessThan %bool %27 %float_0
219 OpSelectionMerge %29 None
220 OpBranchConditional %28 %30 %29
221 %30 = OpLabel
222 OpStore %v %16
223 OpBranch %29
224 %29 = OpLabel
225 %31 = OpLoad %v4float %v
226 %32 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
227 OpStore %32 %31
228 %34 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
229 OpStore %34 %31
230 OpReturn
231 OpFunctionEnd
232 )";
233 
234   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
235       predefs + before, predefs + after, true, true);
236 }
237 
TEST_F(LocalSingleBlockLoadStoreElimTest,StoreStoreElim)238 TEST_F(LocalSingleBlockLoadStoreElimTest, StoreStoreElim) {
239   //
240   // Note first store to v is eliminated
241   //
242   // #version 450
243   //
244   // layout(location = 0) in vec4 BaseColor;
245   // layout(location = 0) out vec4 OutColor;
246   //
247   // void main()
248   // {
249   //     vec4 v = BaseColor;
250   //     v = v * 0.5;
251   //     OutColor = v;
252   // }
253 
254   const std::string predefs_before =
255       R"(OpCapability Shader
256 %1 = OpExtInstImport "GLSL.std.450"
257 OpMemoryModel Logical GLSL450
258 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
259 OpExecutionMode %main OriginUpperLeft
260 OpSource GLSL 450
261 OpName %main "main"
262 OpName %v "v"
263 OpName %BaseColor "BaseColor"
264 OpName %OutColor "OutColor"
265 OpDecorate %BaseColor Location 0
266 OpDecorate %OutColor Location 0
267 %void = OpTypeVoid
268 %7 = OpTypeFunction %void
269 %float = OpTypeFloat 32
270 %v4float = OpTypeVector %float 4
271 %_ptr_Function_v4float = OpTypePointer Function %v4float
272 %_ptr_Input_v4float = OpTypePointer Input %v4float
273 %BaseColor = OpVariable %_ptr_Input_v4float Input
274 %float_0_5 = OpConstant %float 0.5
275 %_ptr_Output_v4float = OpTypePointer Output %v4float
276 %OutColor = OpVariable %_ptr_Output_v4float Output
277 )";
278 
279   const std::string before =
280       R"(%main = OpFunction %void None %7
281 %14 = OpLabel
282 %v = OpVariable %_ptr_Function_v4float Function
283 %15 = OpLoad %v4float %BaseColor
284 OpStore %v %15
285 %16 = OpLoad %v4float %v
286 %17 = OpVectorTimesScalar %v4float %16 %float_0_5
287 OpStore %v %17
288 %18 = OpLoad %v4float %v
289 OpStore %OutColor %18
290 OpReturn
291 OpFunctionEnd
292 )";
293 
294   const std::string after =
295       R"(%main = OpFunction %void None %7
296 %14 = OpLabel
297 %v = OpVariable %_ptr_Function_v4float Function
298 %15 = OpLoad %v4float %BaseColor
299 %17 = OpVectorTimesScalar %v4float %15 %float_0_5
300 OpStore %v %17
301 OpStore %OutColor %17
302 OpReturn
303 OpFunctionEnd
304 )";
305 
306   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
307       predefs_before + before, predefs_before + after, true, true);
308 }
309 
TEST_F(LocalSingleBlockLoadStoreElimTest,NoStoreElimIfInterveningAccessChainLoad)310 TEST_F(LocalSingleBlockLoadStoreElimTest,
311        NoStoreElimIfInterveningAccessChainLoad) {
312   //
313   // Note the first Store to %v is not eliminated due to the following access
314   // chain reference.
315   //
316   // #version 450
317   //
318   // layout(location = 0) in vec4 BaseColor0;
319   // layout(location = 1) in vec4 BaseColor1;
320   // layout(location = 2) flat in int Idx;
321   // layout(location = 0) out vec4 OutColor;
322   //
323   // void main()
324   // {
325   //     vec4 v = BaseColor0;
326   //     float f = v[Idx];
327   //     v = BaseColor1 + vec4(0.1);
328   //     OutColor = v/f;
329   // }
330 
331   const std::string predefs =
332       R"(OpCapability Shader
333 %1 = OpExtInstImport "GLSL.std.450"
334 OpMemoryModel Logical GLSL450
335 OpEntryPoint Fragment %main "main" %BaseColor0 %Idx %BaseColor1 %OutColor
336 OpExecutionMode %main OriginUpperLeft
337 OpSource GLSL 450
338 OpName %main "main"
339 OpName %v "v"
340 OpName %BaseColor0 "BaseColor0"
341 OpName %f "f"
342 OpName %Idx "Idx"
343 OpName %BaseColor1 "BaseColor1"
344 OpName %OutColor "OutColor"
345 OpDecorate %BaseColor0 Location 0
346 OpDecorate %Idx Flat
347 OpDecorate %Idx Location 2
348 OpDecorate %BaseColor1 Location 1
349 OpDecorate %OutColor Location 0
350 %void = OpTypeVoid
351 %10 = OpTypeFunction %void
352 %float = OpTypeFloat 32
353 %v4float = OpTypeVector %float 4
354 %_ptr_Function_v4float = OpTypePointer Function %v4float
355 %_ptr_Input_v4float = OpTypePointer Input %v4float
356 %BaseColor0 = OpVariable %_ptr_Input_v4float Input
357 %_ptr_Function_float = OpTypePointer Function %float
358 %int = OpTypeInt 32 1
359 %_ptr_Input_int = OpTypePointer Input %int
360 %Idx = OpVariable %_ptr_Input_int Input
361 %BaseColor1 = OpVariable %_ptr_Input_v4float Input
362 %float_0_100000001 = OpConstant %float 0.100000001
363 %19 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
364 %_ptr_Output_v4float = OpTypePointer Output %v4float
365 %OutColor = OpVariable %_ptr_Output_v4float Output
366 )";
367 
368   const std::string before =
369       R"(%main = OpFunction %void None %10
370 %21 = OpLabel
371 %v = OpVariable %_ptr_Function_v4float Function
372 %f = OpVariable %_ptr_Function_float Function
373 %22 = OpLoad %v4float %BaseColor0
374 OpStore %v %22
375 %23 = OpLoad %int %Idx
376 %24 = OpAccessChain %_ptr_Function_float %v %23
377 %25 = OpLoad %float %24
378 OpStore %f %25
379 %26 = OpLoad %v4float %BaseColor1
380 %27 = OpFAdd %v4float %26 %19
381 OpStore %v %27
382 %28 = OpLoad %v4float %v
383 %29 = OpLoad %float %f
384 %30 = OpCompositeConstruct %v4float %29 %29 %29 %29
385 %31 = OpFDiv %v4float %28 %30
386 OpStore %OutColor %31
387 OpReturn
388 OpFunctionEnd
389 )";
390 
391   const std::string after =
392       R"(%main = OpFunction %void None %10
393 %21 = OpLabel
394 %v = OpVariable %_ptr_Function_v4float Function
395 %f = OpVariable %_ptr_Function_float Function
396 %22 = OpLoad %v4float %BaseColor0
397 OpStore %v %22
398 %23 = OpLoad %int %Idx
399 %24 = OpAccessChain %_ptr_Function_float %v %23
400 %25 = OpLoad %float %24
401 OpStore %f %25
402 %26 = OpLoad %v4float %BaseColor1
403 %27 = OpFAdd %v4float %26 %19
404 OpStore %v %27
405 %30 = OpCompositeConstruct %v4float %25 %25 %25 %25
406 %31 = OpFDiv %v4float %27 %30
407 OpStore %OutColor %31
408 OpReturn
409 OpFunctionEnd
410 )";
411 
412   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
413       predefs + before, predefs + after, true, true);
414 }
415 
TEST_F(LocalSingleBlockLoadStoreElimTest,NoElimIfInterveningAccessChainStore)416 TEST_F(LocalSingleBlockLoadStoreElimTest, NoElimIfInterveningAccessChainStore) {
417   // #version 140
418   //
419   // in vec4 BaseColor;
420   // flat in int Idx;
421   //
422   // void main()
423   // {
424   //     vec4 v = BaseColor;
425   //     v[Idx] = 0;
426   //     gl_FragColor = v;
427   // }
428 
429   const std::string assembly =
430       R"(OpCapability Shader
431 %1 = OpExtInstImport "GLSL.std.450"
432 OpMemoryModel Logical GLSL450
433 OpEntryPoint Fragment %main "main" %BaseColor %Idx %gl_FragColor
434 OpExecutionMode %main OriginUpperLeft
435 OpSource GLSL 140
436 OpName %main "main"
437 OpName %v "v"
438 OpName %BaseColor "BaseColor"
439 OpName %Idx "Idx"
440 OpName %gl_FragColor "gl_FragColor"
441 OpDecorate %Idx Flat
442 %void = OpTypeVoid
443 %8 = OpTypeFunction %void
444 %float = OpTypeFloat 32
445 %v4float = OpTypeVector %float 4
446 %_ptr_Function_v4float = OpTypePointer Function %v4float
447 %_ptr_Input_v4float = OpTypePointer Input %v4float
448 %BaseColor = OpVariable %_ptr_Input_v4float Input
449 %int = OpTypeInt 32 1
450 %_ptr_Input_int = OpTypePointer Input %int
451 %Idx = OpVariable %_ptr_Input_int Input
452 %float_0 = OpConstant %float 0
453 %_ptr_Function_float = OpTypePointer Function %float
454 %_ptr_Output_v4float = OpTypePointer Output %v4float
455 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
456 %main = OpFunction %void None %8
457 %18 = OpLabel
458 %v = OpVariable %_ptr_Function_v4float Function
459 %19 = OpLoad %v4float %BaseColor
460 OpStore %v %19
461 %20 = OpLoad %int %Idx
462 %21 = OpAccessChain %_ptr_Function_float %v %20
463 OpStore %21 %float_0
464 %22 = OpLoad %v4float %v
465 OpStore %gl_FragColor %22
466 OpReturn
467 OpFunctionEnd
468 )";
469 
470   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(assembly, assembly,
471                                                            false, true);
472 }
473 
TEST_F(LocalSingleBlockLoadStoreElimTest,NoElimIfInterveningFunctionCall)474 TEST_F(LocalSingleBlockLoadStoreElimTest, NoElimIfInterveningFunctionCall) {
475   // #version 140
476   //
477   // in vec4 BaseColor;
478   //
479   // void foo() {
480   // }
481   //
482   // void main()
483   // {
484   //     vec4 v = BaseColor;
485   //     foo();
486   //     gl_FragColor = v;
487   // }
488 
489   const std::string assembly =
490       R"(OpCapability Shader
491 %1 = OpExtInstImport "GLSL.std.450"
492 OpMemoryModel Logical GLSL450
493 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
494 OpExecutionMode %main OriginUpperLeft
495 OpSource GLSL 140
496 OpName %main "main"
497 OpName %foo_ "foo("
498 OpName %v "v"
499 OpName %BaseColor "BaseColor"
500 OpName %gl_FragColor "gl_FragColor"
501 %void = OpTypeVoid
502 %8 = OpTypeFunction %void
503 %float = OpTypeFloat 32
504 %v4float = OpTypeVector %float 4
505 %_ptr_Function_v4float = OpTypePointer Function %v4float
506 %_ptr_Input_v4float = OpTypePointer Input %v4float
507 %BaseColor = OpVariable %_ptr_Input_v4float Input
508 %_ptr_Output_v4float = OpTypePointer Output %v4float
509 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
510 %main = OpFunction %void None %8
511 %14 = OpLabel
512 %v = OpVariable %_ptr_Function_v4float Function
513 %15 = OpLoad %v4float %BaseColor
514 OpStore %v %15
515 %16 = OpFunctionCall %void %foo_
516 %17 = OpLoad %v4float %v
517 OpStore %gl_FragColor %17
518 OpReturn
519 OpFunctionEnd
520 %foo_ = OpFunction %void None %8
521 %18 = OpLabel
522 OpReturn
523 OpFunctionEnd
524 )";
525 
526   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(assembly, assembly,
527                                                            false, true);
528 }
529 
TEST_F(LocalSingleBlockLoadStoreElimTest,ElimIfCopyObjectInFunction)530 TEST_F(LocalSingleBlockLoadStoreElimTest, ElimIfCopyObjectInFunction) {
531   // Note: SPIR-V hand edited to insert CopyObject
532   //
533   // #version 140
534   //
535   // in vec4 BaseColor;
536   //
537   // void main()
538   // {
539   //   vec4 v1 = BaseColor;
540   //   gl_FragData[0] = v1;
541   //   vec4 v2 = BaseColor * 0.5;
542   //   gl_FragData[1] = v2;
543   // }
544 
545   const std::string predefs =
546       R"(OpCapability Shader
547 %1 = OpExtInstImport "GLSL.std.450"
548 OpMemoryModel Logical GLSL450
549 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragData
550 OpExecutionMode %main OriginUpperLeft
551 OpSource GLSL 140
552 OpName %main "main"
553 OpName %v1 "v1"
554 OpName %BaseColor "BaseColor"
555 OpName %gl_FragData "gl_FragData"
556 OpName %v2 "v2"
557 %void = OpTypeVoid
558 %8 = OpTypeFunction %void
559 %float = OpTypeFloat 32
560 %v4float = OpTypeVector %float 4
561 %_ptr_Function_v4float = OpTypePointer Function %v4float
562 %_ptr_Input_v4float = OpTypePointer Input %v4float
563 %BaseColor = OpVariable %_ptr_Input_v4float Input
564 %uint = OpTypeInt 32 0
565 %uint_32 = OpConstant %uint 32
566 %_arr_v4float_uint_32 = OpTypeArray %v4float %uint_32
567 %_ptr_Output__arr_v4float_uint_32 = OpTypePointer Output %_arr_v4float_uint_32
568 %gl_FragData = OpVariable %_ptr_Output__arr_v4float_uint_32 Output
569 %int = OpTypeInt 32 1
570 %int_0 = OpConstant %int 0
571 %_ptr_Output_v4float = OpTypePointer Output %v4float
572 %float_0_5 = OpConstant %float 0.5
573 %int_1 = OpConstant %int 1
574 )";
575 
576   const std::string before =
577       R"(%main = OpFunction %void None %8
578 %22 = OpLabel
579 %v1 = OpVariable %_ptr_Function_v4float Function
580 %v2 = OpVariable %_ptr_Function_v4float Function
581 %23 = OpLoad %v4float %BaseColor
582 OpStore %v1 %23
583 %24 = OpLoad %v4float %v1
584 %25 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
585 OpStore %25 %24
586 %26 = OpLoad %v4float %BaseColor
587 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
588 %28 = OpCopyObject %_ptr_Function_v4float %v2
589 OpStore %28 %27
590 %29 = OpLoad %v4float %28
591 %30 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
592 OpStore %30 %29
593 OpReturn
594 OpFunctionEnd
595 )";
596 
597   const std::string after =
598       R"(%main = OpFunction %void None %8
599 %22 = OpLabel
600 %v1 = OpVariable %_ptr_Function_v4float Function
601 %v2 = OpVariable %_ptr_Function_v4float Function
602 %23 = OpLoad %v4float %BaseColor
603 OpStore %v1 %23
604 %25 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
605 OpStore %25 %23
606 %26 = OpLoad %v4float %BaseColor
607 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
608 %28 = OpCopyObject %_ptr_Function_v4float %v2
609 OpStore %28 %27
610 %30 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
611 OpStore %30 %27
612 OpReturn
613 OpFunctionEnd
614 )";
615 
616   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
617       predefs + before, predefs + after, true, true);
618 }
619 
TEST_F(LocalSingleBlockLoadStoreElimTest,ElimOpaque)620 TEST_F(LocalSingleBlockLoadStoreElimTest, ElimOpaque) {
621   // SPIR-V not representable in GLSL; not generatable from HLSL
622   // at the moment
623 
624   const std::string predefs =
625       R"(OpCapability Shader
626 %1 = OpExtInstImport "GLSL.std.450"
627 OpMemoryModel Logical GLSL450
628 OpEntryPoint Fragment %main "main" %outColor %texCoords
629 OpExecutionMode %main OriginUpperLeft
630 OpSource GLSL 140
631 OpName %main "main"
632 OpName %S_t "S_t"
633 OpMemberName %S_t 0 "v0"
634 OpMemberName %S_t 1 "v1"
635 OpMemberName %S_t 2 "smp"
636 OpName %outColor "outColor"
637 OpName %sampler15 "sampler15"
638 OpName %s0 "s0"
639 OpName %texCoords "texCoords"
640 OpName %param "param"
641 OpDecorate %sampler15 DescriptorSet 0
642 %void = OpTypeVoid
643 %12 = OpTypeFunction %void
644 %float = OpTypeFloat 32
645 %v2float = OpTypeVector %float 2
646 %v4float = OpTypeVector %float 4
647 %_ptr_Output_v4float = OpTypePointer Output %v4float
648 %outColor = OpVariable %_ptr_Output_v4float Output
649 %17 = OpTypeImage %float 2D 0 0 0 1 Unknown
650 %18 = OpTypeSampledImage %17
651 %S_t = OpTypeStruct %v2float %v2float %18
652 %_ptr_Function_S_t = OpTypePointer Function %S_t
653 %20 = OpTypeFunction %void %_ptr_Function_S_t
654 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
655 %_ptr_Function_18 = OpTypePointer Function %18
656 %sampler15 = OpVariable %_ptr_UniformConstant_18 UniformConstant
657 %int = OpTypeInt 32 1
658 %int_0 = OpConstant %int 0
659 %int_2 = OpConstant %int 2
660 %_ptr_Function_v2float = OpTypePointer Function %v2float
661 %_ptr_Input_v2float = OpTypePointer Input %v2float
662 %texCoords = OpVariable %_ptr_Input_v2float Input
663 )";
664 
665   const std::string before =
666       R"(%main = OpFunction %void None %12
667 %28 = OpLabel
668 %s0 = OpVariable %_ptr_Function_S_t Function
669 %param = OpVariable %_ptr_Function_S_t Function
670 %29 = OpLoad %v2float %texCoords
671 %30 = OpLoad %S_t %s0
672 %31 = OpCompositeInsert %S_t %29 %30 0
673 OpStore %s0 %31
674 %32 = OpLoad %18 %sampler15
675 %33 = OpLoad %S_t %s0
676 %34 = OpCompositeInsert %S_t %32 %33 2
677 OpStore %s0 %34
678 %35 = OpLoad %S_t %s0
679 OpStore %param %35
680 %36 = OpLoad %S_t %param
681 %37 = OpCompositeExtract %18 %36 2
682 %38 = OpLoad %S_t %param
683 %39 = OpCompositeExtract %v2float %38 0
684 %40 = OpImageSampleImplicitLod %v4float %37 %39
685 OpStore %outColor %40
686 OpReturn
687 OpFunctionEnd
688 )";
689 
690   const std::string after =
691       R"(%main = OpFunction %void None %12
692 %28 = OpLabel
693 %s0 = OpVariable %_ptr_Function_S_t Function
694 %param = OpVariable %_ptr_Function_S_t Function
695 %29 = OpLoad %v2float %texCoords
696 %30 = OpLoad %S_t %s0
697 %31 = OpCompositeInsert %S_t %29 %30 0
698 %32 = OpLoad %18 %sampler15
699 %34 = OpCompositeInsert %S_t %32 %31 2
700 OpStore %s0 %34
701 OpStore %param %34
702 %37 = OpCompositeExtract %18 %34 2
703 %39 = OpCompositeExtract %v2float %34 0
704 %40 = OpImageSampleImplicitLod %v4float %37 %39
705 OpStore %outColor %40
706 OpReturn
707 OpFunctionEnd
708 )";
709 
710   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
711   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
712       predefs + before, predefs + after, true, true);
713 }
714 
TEST_F(LocalSingleBlockLoadStoreElimTest,PositiveAndNegativeCallTree)715 TEST_F(LocalSingleBlockLoadStoreElimTest, PositiveAndNegativeCallTree) {
716   // Note that the call tree function bar is optimized, but foo is not
717   //
718   // #version 140
719   //
720   // in vec4 BaseColor;
721   //
722   // vec4 foo(vec4 v1)
723   // {
724   //     vec4 t = v1;
725   //     return t;
726   // }
727   //
728   // vec4 bar(vec4 v1)
729   // {
730   //     vec4 t = v1;
731   //     return t;
732   // }
733   //
734   // void main()
735   // {
736   //     gl_FragColor = bar(BaseColor);
737   // }
738 
739   const std::string predefs =
740       R"(OpCapability Shader
741 %1 = OpExtInstImport "GLSL.std.450"
742 OpMemoryModel Logical GLSL450
743 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
744 OpExecutionMode %main OriginUpperLeft
745 OpSource GLSL 140
746 OpName %main "main"
747 OpName %foo_vf4_ "foo(vf4;"
748 OpName %v1 "v1"
749 OpName %bar_vf4_ "bar(vf4;"
750 OpName %v1_0 "v1"
751 OpName %t "t"
752 OpName %t_0 "t"
753 OpName %gl_FragColor "gl_FragColor"
754 OpName %BaseColor "BaseColor"
755 OpName %param "param"
756 %void = OpTypeVoid
757 %13 = OpTypeFunction %void
758 %float = OpTypeFloat 32
759 %v4float = OpTypeVector %float 4
760 %_ptr_Function_v4float = OpTypePointer Function %v4float
761 %17 = OpTypeFunction %v4float %_ptr_Function_v4float
762 %_ptr_Output_v4float = OpTypePointer Output %v4float
763 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
764 %_ptr_Input_v4float = OpTypePointer Input %v4float
765 %BaseColor = OpVariable %_ptr_Input_v4float Input
766 %main = OpFunction %void None %13
767 %20 = OpLabel
768 %param = OpVariable %_ptr_Function_v4float Function
769 %21 = OpLoad %v4float %BaseColor
770 OpStore %param %21
771 %22 = OpFunctionCall %v4float %bar_vf4_ %param
772 OpStore %gl_FragColor %22
773 OpReturn
774 OpFunctionEnd
775 )";
776 
777   const std::string before =
778       R"(%foo_vf4_ = OpFunction %v4float None %17
779 %v1 = OpFunctionParameter %_ptr_Function_v4float
780 %23 = OpLabel
781 %t = OpVariable %_ptr_Function_v4float Function
782 %24 = OpLoad %v4float %v1
783 OpStore %t %24
784 %25 = OpLoad %v4float %t
785 OpReturnValue %25
786 OpFunctionEnd
787 %bar_vf4_ = OpFunction %v4float None %17
788 %v1_0 = OpFunctionParameter %_ptr_Function_v4float
789 %26 = OpLabel
790 %t_0 = OpVariable %_ptr_Function_v4float Function
791 %27 = OpLoad %v4float %v1_0
792 OpStore %t_0 %27
793 %28 = OpLoad %v4float %t_0
794 OpReturnValue %28
795 OpFunctionEnd
796 )";
797 
798   const std::string after =
799       R"(%foo_vf4_ = OpFunction %v4float None %17
800 %v1 = OpFunctionParameter %_ptr_Function_v4float
801 %23 = OpLabel
802 %t = OpVariable %_ptr_Function_v4float Function
803 %24 = OpLoad %v4float %v1
804 OpStore %t %24
805 %25 = OpLoad %v4float %t
806 OpReturnValue %25
807 OpFunctionEnd
808 %bar_vf4_ = OpFunction %v4float None %17
809 %v1_0 = OpFunctionParameter %_ptr_Function_v4float
810 %26 = OpLabel
811 %t_0 = OpVariable %_ptr_Function_v4float Function
812 %27 = OpLoad %v4float %v1_0
813 OpStore %t_0 %27
814 OpReturnValue %27
815 OpFunctionEnd
816 )";
817 
818   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
819       predefs + before, predefs + after, true, true);
820 }
821 
TEST_F(LocalSingleBlockLoadStoreElimTest,PointerVariable)822 TEST_F(LocalSingleBlockLoadStoreElimTest, PointerVariable) {
823   // Test that checks if a pointer variable is removed.
824 
825   const std::string before =
826       R"(OpCapability Shader
827 OpMemoryModel Logical GLSL450
828 OpEntryPoint Fragment %1 "main" %2
829 OpExecutionMode %1 OriginUpperLeft
830 OpMemberDecorate %_struct_3 0 Offset 0
831 OpDecorate %_runtimearr__struct_3 ArrayStride 16
832 OpMemberDecorate %_struct_5 0 Offset 0
833 OpDecorate %_struct_5 BufferBlock
834 OpMemberDecorate %_struct_6 0 Offset 0
835 OpDecorate %_struct_6 BufferBlock
836 OpDecorate %2 Location 0
837 OpDecorate %7 DescriptorSet 0
838 OpDecorate %7 Binding 0
839 %void = OpTypeVoid
840 %10 = OpTypeFunction %void
841 %int = OpTypeInt 32 1
842 %uint = OpTypeInt 32 0
843 %float = OpTypeFloat 32
844 %v4float = OpTypeVector %float 4
845 %_ptr_Output_v4float = OpTypePointer Output %v4float
846 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
847 %_struct_3 = OpTypeStruct %v4float
848 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
849 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
850 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
851 %_struct_6 = OpTypeStruct %int
852 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
853 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
854 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
855 %int_0 = OpConstant %int 0
856 %uint_0 = OpConstant %uint 0
857 %2 = OpVariable %_ptr_Output_v4float Output
858 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
859 %1 = OpFunction %void None %10
860 %23 = OpLabel
861 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
862 OpStore %24 %7
863 %26 = OpLoad %_ptr_Uniform__struct_5 %24
864 %27 = OpAccessChain %_ptr_Uniform_v4float %26 %int_0 %uint_0 %int_0
865 %28 = OpLoad %v4float %27
866 %29 = OpCopyObject %v4float %28
867 OpStore %2 %28
868 OpReturn
869 OpFunctionEnd
870 )";
871 
872   const std::string after =
873       R"(OpCapability Shader
874 OpMemoryModel Logical GLSL450
875 OpEntryPoint Fragment %1 "main" %2
876 OpExecutionMode %1 OriginUpperLeft
877 OpMemberDecorate %_struct_3 0 Offset 0
878 OpDecorate %_runtimearr__struct_3 ArrayStride 16
879 OpMemberDecorate %_struct_5 0 Offset 0
880 OpDecorate %_struct_5 BufferBlock
881 OpMemberDecorate %_struct_6 0 Offset 0
882 OpDecorate %_struct_6 BufferBlock
883 OpDecorate %2 Location 0
884 OpDecorate %7 DescriptorSet 0
885 OpDecorate %7 Binding 0
886 %void = OpTypeVoid
887 %10 = OpTypeFunction %void
888 %int = OpTypeInt 32 1
889 %uint = OpTypeInt 32 0
890 %float = OpTypeFloat 32
891 %v4float = OpTypeVector %float 4
892 %_ptr_Output_v4float = OpTypePointer Output %v4float
893 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
894 %_struct_3 = OpTypeStruct %v4float
895 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
896 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
897 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
898 %_struct_6 = OpTypeStruct %int
899 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
900 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
901 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
902 %int_0 = OpConstant %int 0
903 %uint_0 = OpConstant %uint 0
904 %2 = OpVariable %_ptr_Output_v4float Output
905 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
906 %1 = OpFunction %void None %10
907 %23 = OpLabel
908 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
909 OpStore %24 %7
910 %27 = OpAccessChain %_ptr_Uniform_v4float %7 %int_0 %uint_0 %int_0
911 %28 = OpLoad %v4float %27
912 %29 = OpCopyObject %v4float %28
913 OpStore %2 %28
914 OpReturn
915 OpFunctionEnd
916 )";
917 
918   // Relax logical pointers to allow pointer allocations.
919   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
920   ValidatorOptions()->relax_logical_pointer = true;
921   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(before, after, true,
922                                                            true);
923 }
924 
TEST_F(LocalSingleBlockLoadStoreElimTest,RedundantStore)925 TEST_F(LocalSingleBlockLoadStoreElimTest, RedundantStore) {
926   // Test that checks if a pointer variable is removed.
927   const std::string predefs_before =
928       R"(OpCapability Shader
929 %1 = OpExtInstImport "GLSL.std.450"
930 OpMemoryModel Logical GLSL450
931 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
932 OpExecutionMode %main OriginUpperLeft
933 OpSource GLSL 140
934 OpName %main "main"
935 OpName %v "v"
936 OpName %BaseColor "BaseColor"
937 OpName %gl_FragColor "gl_FragColor"
938 %void = OpTypeVoid
939 %7 = OpTypeFunction %void
940 %float = OpTypeFloat 32
941 %v4float = OpTypeVector %float 4
942 %_ptr_Function_v4float = OpTypePointer Function %v4float
943 %_ptr_Input_v4float = OpTypePointer Input %v4float
944 %BaseColor = OpVariable %_ptr_Input_v4float Input
945 %_ptr_Output_v4float = OpTypePointer Output %v4float
946 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
947 )";
948 
949   const std::string before =
950       R"(%main = OpFunction %void None %7
951 %13 = OpLabel
952 %v = OpVariable %_ptr_Function_v4float Function
953 %14 = OpLoad %v4float %BaseColor
954 OpStore %v %14
955 OpBranch %16
956 %16 = OpLabel
957 %15 = OpLoad %v4float %v
958 OpStore %v %15
959 OpReturn
960 OpFunctionEnd
961 )";
962 
963   const std::string after =
964       R"(%main = OpFunction %void None %7
965 %13 = OpLabel
966 %v = OpVariable %_ptr_Function_v4float Function
967 %14 = OpLoad %v4float %BaseColor
968 OpStore %v %14
969 OpBranch %16
970 %16 = OpLabel
971 %15 = OpLoad %v4float %v
972 OpReturn
973 OpFunctionEnd
974 )";
975 
976   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
977   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
978       predefs_before + before, predefs_before + after, true, true);
979 }
980 
TEST_F(LocalSingleBlockLoadStoreElimTest,RedundantStore2)981 TEST_F(LocalSingleBlockLoadStoreElimTest, RedundantStore2) {
982   // Test that checks if a pointer variable is removed.
983   const std::string predefs_before =
984       R"(OpCapability Shader
985 %1 = OpExtInstImport "GLSL.std.450"
986 OpMemoryModel Logical GLSL450
987 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
988 OpExecutionMode %main OriginUpperLeft
989 OpSource GLSL 140
990 OpName %main "main"
991 OpName %v "v"
992 OpName %BaseColor "BaseColor"
993 OpName %gl_FragColor "gl_FragColor"
994 %void = OpTypeVoid
995 %7 = OpTypeFunction %void
996 %float = OpTypeFloat 32
997 %v4float = OpTypeVector %float 4
998 %_ptr_Function_v4float = OpTypePointer Function %v4float
999 %_ptr_Input_v4float = OpTypePointer Input %v4float
1000 %BaseColor = OpVariable %_ptr_Input_v4float Input
1001 %_ptr_Output_v4float = OpTypePointer Output %v4float
1002 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
1003 )";
1004 
1005   const std::string before =
1006       R"(%main = OpFunction %void None %7
1007 %13 = OpLabel
1008 %v = OpVariable %_ptr_Function_v4float Function
1009 %14 = OpLoad %v4float %BaseColor
1010 OpStore %v %14
1011 OpBranch %16
1012 %16 = OpLabel
1013 %15 = OpLoad %v4float %v
1014 OpStore %v %15
1015 %17 = OpLoad %v4float %v
1016 OpStore %v %17
1017 OpReturn
1018 OpFunctionEnd
1019 )";
1020 
1021   const std::string after =
1022       R"(%main = OpFunction %void None %7
1023 %13 = OpLabel
1024 %v = OpVariable %_ptr_Function_v4float Function
1025 %14 = OpLoad %v4float %BaseColor
1026 OpStore %v %14
1027 OpBranch %16
1028 %16 = OpLabel
1029 %15 = OpLoad %v4float %v
1030 OpReturn
1031 OpFunctionEnd
1032 )";
1033 
1034   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1035   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
1036       predefs_before + before, predefs_before + after, true, true);
1037 }
1038 
1039 // Test that that an unused OpAccessChain between two store does does not
1040 // hinders the removal of the first store.  We need to check this because
1041 // local-access-chain-convert does always remove the OpAccessChain instructions
1042 // that become dead.
1043 
TEST_F(LocalSingleBlockLoadStoreElimTest,StoreElimIfInterveningUnusedAccessChain)1044 TEST_F(LocalSingleBlockLoadStoreElimTest,
1045        StoreElimIfInterveningUnusedAccessChain) {
1046   const std::string predefs =
1047       R"(OpCapability Shader
1048 %1 = OpExtInstImport "GLSL.std.450"
1049 OpMemoryModel Logical GLSL450
1050 OpEntryPoint Fragment %main "main" %BaseColor0 %Idx %BaseColor1 %OutColor
1051 OpExecutionMode %main OriginUpperLeft
1052 OpSource GLSL 450
1053 OpName %main "main"
1054 OpName %v "v"
1055 OpName %BaseColor0 "BaseColor0"
1056 OpName %Idx "Idx"
1057 OpName %BaseColor1 "BaseColor1"
1058 OpName %OutColor "OutColor"
1059 OpDecorate %BaseColor0 Location 0
1060 OpDecorate %Idx Flat
1061 OpDecorate %Idx Location 2
1062 OpDecorate %BaseColor1 Location 1
1063 OpDecorate %OutColor Location 0
1064 %void = OpTypeVoid
1065 %10 = OpTypeFunction %void
1066 %float = OpTypeFloat 32
1067 %v4float = OpTypeVector %float 4
1068 %_ptr_Function_v4float = OpTypePointer Function %v4float
1069 %_ptr_Input_v4float = OpTypePointer Input %v4float
1070 %BaseColor0 = OpVariable %_ptr_Input_v4float Input
1071 %_ptr_Function_float = OpTypePointer Function %float
1072 %int = OpTypeInt 32 1
1073 %_ptr_Input_int = OpTypePointer Input %int
1074 %Idx = OpVariable %_ptr_Input_int Input
1075 %BaseColor1 = OpVariable %_ptr_Input_v4float Input
1076 %float_0_100000001 = OpConstant %float 0.100000001
1077 %19 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
1078 %_ptr_Output_v4float = OpTypePointer Output %v4float
1079 %OutColor = OpVariable %_ptr_Output_v4float Output
1080 )";
1081 
1082   const std::string before =
1083       R"(%main = OpFunction %void None %10
1084 %21 = OpLabel
1085 %v = OpVariable %_ptr_Function_v4float Function
1086 %22 = OpLoad %v4float %BaseColor0
1087 OpStore %v %22
1088 %23 = OpLoad %int %Idx
1089 %24 = OpAccessChain %_ptr_Function_float %v %23
1090 %26 = OpLoad %v4float %BaseColor1
1091 %27 = OpFAdd %v4float %26 %19
1092 OpStore %v %27
1093 OpReturn
1094 OpFunctionEnd
1095 )";
1096 
1097   const std::string after =
1098       R"(%main = OpFunction %void None %10
1099 %21 = OpLabel
1100 %v = OpVariable %_ptr_Function_v4float Function
1101 %22 = OpLoad %v4float %BaseColor0
1102 %23 = OpLoad %int %Idx
1103 %24 = OpAccessChain %_ptr_Function_float %v %23
1104 %26 = OpLoad %v4float %BaseColor1
1105 %27 = OpFAdd %v4float %26 %19
1106 OpStore %v %27
1107 OpReturn
1108 OpFunctionEnd
1109 )";
1110 
1111   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1112   SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
1113       predefs + before, predefs + after, true, true);
1114 }
1115 
TEST_F(LocalSingleBlockLoadStoreElimTest,VariablePointerTest)1116 TEST_F(LocalSingleBlockLoadStoreElimTest, VariablePointerTest) {
1117   // Check that the load of the first variable is still used and that the load
1118   // of the third variable is propagated.  The first load has to remain because
1119   // of the store to the variable pointer.
1120   const std::string text = R"(
1121 ; CHECK: [[v1:%\w+]] = OpVariable
1122 ; CHECK: [[v2:%\w+]] = OpVariable
1123 ; CHECK: [[v3:%\w+]] = OpVariable
1124 ; CHECK: [[phi:%\w+]] = OpPhi
1125 ; CHECK: [[ld1:%\w+]] = OpLoad %int [[v1]]
1126 ; CHECK: OpIAdd %int [[ld1]] %int_0
1127                OpCapability Shader
1128                OpCapability VariablePointers
1129           %1 = OpExtInstImport "GLSL.std.450"
1130                OpMemoryModel Logical GLSL450
1131                OpEntryPoint GLCompute %2 "main"
1132                OpExecutionMode %2 LocalSize 1 1 1
1133                OpSource GLSL 450
1134                OpMemberDecorate %_struct_3 0 Offset 0
1135                OpMemberDecorate %_struct_3 1 Offset 4
1136        %void = OpTypeVoid
1137           %5 = OpTypeFunction %void
1138         %int = OpTypeInt 32 1
1139        %bool = OpTypeBool
1140   %_struct_3 = OpTypeStruct %int %int
1141 %_ptr_Function__struct_3 = OpTypePointer Function %_struct_3
1142 %_ptr_Function_int = OpTypePointer Function %int
1143        %true = OpConstantTrue %bool
1144       %int_0 = OpConstant %int 0
1145       %int_1 = OpConstant %int 1
1146          %13 = OpConstantNull %_struct_3
1147           %2 = OpFunction %void None %5
1148          %14 = OpLabel
1149          %15 = OpVariable %_ptr_Function_int Function
1150          %16 = OpVariable %_ptr_Function_int Function
1151          %17 = OpVariable %_ptr_Function_int Function
1152                OpSelectionMerge %18 None
1153                OpBranchConditional %true %19 %20
1154          %19 = OpLabel
1155                OpBranch %18
1156          %20 = OpLabel
1157                OpBranch %18
1158          %18 = OpLabel
1159          %21 = OpPhi %_ptr_Function_int %15 %19 %16 %20
1160                OpStore %15 %int_1
1161                OpStore %21 %int_0
1162          %22 = OpLoad %int %15
1163                OpStore %17 %int_0
1164          %23 = OpLoad %int %17
1165          %24 = OpIAdd %int %22 %23
1166                OpReturn
1167                OpFunctionEnd
1168   )";
1169   SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
1170 }
1171 
TEST_F(LocalSingleBlockLoadStoreElimTest,DebugDeclareTest)1172 TEST_F(LocalSingleBlockLoadStoreElimTest, DebugDeclareTest) {
1173   // If OpenCL.DebugInfo.100 enabled, check that store/load is still
1174   // optimized, but stores are not deleted for store/store.
1175   //
1176   // struct PS_INPUT {
1177   //   float4 c0 : COLOR0;
1178   //   float4 c1 : COLOR1;
1179   // };
1180   //
1181   // struct PS_OUTPUT {
1182   //   float4 vColor : SV_Target0;
1183   // };
1184   //
1185   // PS_OUTPUT MainPs(PS_INPUT i) {
1186   //   PS_OUTPUT ps_output;
1187   //   float4 c;
1188   //   c = i.c0;
1189   //   c += i.c1;
1190   //   c /= 2.0;
1191   //   ps_output.vColor = c;
1192   //   return ps_output;
1193   // }
1194   const std::string text = R"(
1195                OpCapability Shader
1196           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1197                OpMemoryModel Logical GLSL450
1198                OpEntryPoint Fragment %MainPs "MainPs" %in_var_COLOR0 %in_var_COLOR1 %out_var_SV_Target0
1199                OpExecutionMode %MainPs OriginUpperLeft
1200           %6 = OpString "foo3.frag"
1201           %7 = OpString "PS_OUTPUT"
1202           %8 = OpString "float"
1203           %9 = OpString "vColor"
1204          %10 = OpString "PS_INPUT"
1205          %11 = OpString "c1"
1206          %12 = OpString "c0"
1207          %13 = OpString "src.MainPs"
1208          %14 = OpString "c"
1209          %15 = OpString "ps_output"
1210          %16 = OpString "i"
1211                OpName %in_var_COLOR0 "in.var.COLOR0"
1212                OpName %in_var_COLOR1 "in.var.COLOR1"
1213                OpName %out_var_SV_Target0 "out.var.SV_Target0"
1214                OpName %MainPs "MainPs"
1215                OpName %PS_INPUT "PS_INPUT"
1216                OpMemberName %PS_INPUT 0 "c0"
1217                OpMemberName %PS_INPUT 1 "c1"
1218                OpName %param_var_i "param.var.i"
1219                OpName %PS_OUTPUT "PS_OUTPUT"
1220                OpMemberName %PS_OUTPUT 0 "vColor"
1221                OpName %src_MainPs "src.MainPs"
1222                OpName %i "i"
1223                OpName %bb_entry "bb.entry"
1224                OpName %ps_output "ps_output"
1225                OpName %c "c"
1226                OpDecorate %in_var_COLOR0 Location 0
1227                OpDecorate %in_var_COLOR1 Location 1
1228                OpDecorate %out_var_SV_Target0 Location 0
1229         %int = OpTypeInt 32 1
1230       %int_0 = OpConstant %int 0
1231       %int_1 = OpConstant %int 1
1232       %float = OpTypeFloat 32
1233     %float_2 = OpConstant %float 2
1234     %v4float = OpTypeVector %float 4
1235          %31 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
1236        %uint = OpTypeInt 32 0
1237     %uint_32 = OpConstant %uint 32
1238 %_ptr_Input_v4float = OpTypePointer Input %v4float
1239 %_ptr_Output_v4float = OpTypePointer Output %v4float
1240        %void = OpTypeVoid
1241    %uint_128 = OpConstant %uint 128
1242      %uint_0 = OpConstant %uint 0
1243    %uint_256 = OpConstant %uint 256
1244          %40 = OpTypeFunction %void
1245    %PS_INPUT = OpTypeStruct %v4float %v4float
1246 %_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
1247   %PS_OUTPUT = OpTypeStruct %v4float
1248          %42 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
1249 %_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
1250 %_ptr_Function_v4float = OpTypePointer Function %v4float
1251 %in_var_COLOR0 = OpVariable %_ptr_Input_v4float Input
1252 %in_var_COLOR1 = OpVariable %_ptr_Input_v4float Input
1253 %out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output
1254          %45 = OpExtInst %void %1 DebugSource %6
1255          %46 = OpExtInst %void %1 DebugCompilationUnit 1 4 %45 HLSL
1256          %47 = OpExtInst %void %1 DebugTypeComposite %7 Structure %45 8 1 %46 %7 %uint_128 FlagIsProtected|FlagIsPrivate %48
1257          %49 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 Float
1258          %50 = OpExtInst %void %1 DebugTypeVector %49 4
1259          %48 = OpExtInst %void %1 DebugTypeMember %9 %50 %45 10 5 %47 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
1260          %51 = OpExtInst %void %1 DebugTypeComposite %10 Structure %45 2 1 %46 %10 %uint_256 FlagIsProtected|FlagIsPrivate %52 %53
1261          %53 = OpExtInst %void %1 DebugTypeMember %11 %50 %45 5 5 %51 %uint_128 %uint_128 FlagIsProtected|FlagIsPrivate
1262          %52 = OpExtInst %void %1 DebugTypeMember %12 %50 %45 4 5 %51 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
1263          %54 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %47 %51
1264          %55 = OpExtInst %void %1 DebugFunction %13 %54 %45 13 1 %46 %13 FlagIsProtected|FlagIsPrivate 14 %src_MainPs
1265          %56 = OpExtInst %void %1 DebugLexicalBlock %45 14 1 %55
1266          %57 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %56 FlagIsLocal
1267          %58 = OpExtInst %void %1 DebugLocalVariable %15 %47 %45 15 15 %56 FlagIsLocal
1268          %59 = OpExtInst %void %1 DebugExpression
1269          %60 = OpExtInst %void %1 DebugLocalVariable %16 %51 %45 13 29 %55 FlagIsLocal 1
1270          %61 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %55 FlagIsLocal 1
1271      %MainPs = OpFunction %void None %40
1272          %62 = OpLabel
1273 %param_var_i = OpVariable %_ptr_Function_PS_INPUT Function
1274          %63 = OpLoad %v4float %in_var_COLOR0
1275          %64 = OpLoad %v4float %in_var_COLOR1
1276          %65 = OpCompositeConstruct %PS_INPUT %63 %64
1277                OpStore %param_var_i %65
1278          %66 = OpFunctionCall %PS_OUTPUT %src_MainPs %param_var_i
1279          %67 = OpCompositeExtract %v4float %66 0
1280                OpStore %out_var_SV_Target0 %67
1281                OpReturn
1282                OpFunctionEnd
1283                OpLine %6 13 1
1284  %src_MainPs = OpFunction %PS_OUTPUT None %42
1285          %83 = OpExtInst %void %1 DebugScope %55
1286                OpLine %6 13 29
1287           %i = OpFunctionParameter %_ptr_Function_PS_INPUT
1288          %69 = OpExtInst %void %1 DebugDeclare %60 %i %59
1289          %84 = OpExtInst %void %1 DebugNoScope
1290    %bb_entry = OpLabel
1291          %85 = OpExtInst %void %1 DebugScope %56
1292   %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
1293           %c = OpVariable %_ptr_Function_v4float Function
1294          %71 = OpExtInst %void %1 DebugDeclare %61 %c %59
1295                OpLine %6 18 9
1296          %72 = OpAccessChain %_ptr_Function_v4float %i %int_0
1297                OpLine %6 18 13
1298          %73 = OpLoad %v4float %72
1299                OpLine %6 18 5
1300                OpStore %c %73
1301 ;CHECK:        OpStore %c %73
1302                OpLine %6 19 10
1303          %74 = OpAccessChain %_ptr_Function_v4float %i %int_1
1304                OpLine %6 19 14
1305          %75 = OpLoad %v4float %74
1306                OpLine %6 19 5
1307          %76 = OpLoad %v4float %c
1308 ;CHECK-NOT:       OpLine %6 19 5
1309 ;CHECK-NOT: %76 = OpLoad %v4float %c
1310                OpLine %6 19 7
1311          %77 = OpFAdd %v4float %76 %75
1312 ;CHECK-NOT: %77 = OpFAdd %v4float %76 %75
1313 ;CHECK:     %77 = OpFAdd %v4float %73 %75
1314                OpLine %6 19 5
1315                OpStore %c %77
1316 ;CHECK:        OpStore %c %77
1317                OpLine %6 20 5
1318          %78 = OpLoad %v4float %c
1319 ;CHECK-NOT:       OpLine %6 20 5
1320 ;CHECK-NOT: %78 = OpLoad %v4float %c
1321                OpLine %6 20 7
1322          %79 = OpFDiv %v4float %78 %31
1323 ;CHECK-NOT %79 = OpFDiv %v4float %78 %31
1324 ;CHECK:    %79 = OpFDiv %v4float %77 %31
1325                OpLine %6 20 5
1326                OpStore %c %79
1327 ;CHECK:        OpStore %c %79
1328                OpLine %6 22 26
1329          %80 = OpLoad %v4float %c
1330 ;CHECK-NOT:       OpLine %6 22 26
1331 ;CHECK-NOT: %80 = OpLoad %v4float %c
1332                OpLine %6 22 5
1333          %81 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
1334                OpStore %81 %80
1335 ;CHECK-NOT:    OpStore %81 %80
1336 ;CHECK:        OpStore %81 %79
1337                OpLine %6 23 12
1338          %82 = OpLoad %PS_OUTPUT %ps_output
1339                OpLine %6 23 5
1340                OpReturnValue %82
1341          %86 = OpExtInst %void %1 DebugNoScope
1342                OpFunctionEnd
1343   )";
1344   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1345   SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
1346 }
TEST_F(LocalSingleBlockLoadStoreElimTest,DebugValueTest)1347 TEST_F(LocalSingleBlockLoadStoreElimTest, DebugValueTest) {
1348   // If OpenCL.DebugInfo.100 enabled, check that store/load is still
1349   // optimized, but stores are not deleted for store/store.
1350   // Same source as DebugDeclareTest; DebugDeclare replaced with
1351   // equivalent DebugValue
1352   const std::string text = R"(
1353                OpCapability Shader
1354           %1 = OpExtInstImport "OpenCL.DebugInfo.100"
1355                OpMemoryModel Logical GLSL450
1356                OpEntryPoint Fragment %MainPs "MainPs" %in_var_COLOR0 %in_var_COLOR1 %out_var_SV_Target0
1357                OpExecutionMode %MainPs OriginUpperLeft
1358           %6 = OpString "foo3.frag"
1359           %7 = OpString "PS_OUTPUT"
1360           %8 = OpString "float"
1361           %9 = OpString "vColor"
1362          %10 = OpString "PS_INPUT"
1363          %11 = OpString "c1"
1364          %12 = OpString "c0"
1365          %13 = OpString "src.MainPs"
1366          %14 = OpString "c"
1367          %15 = OpString "ps_output"
1368          %16 = OpString "i"
1369                OpName %in_var_COLOR0 "in.var.COLOR0"
1370                OpName %in_var_COLOR1 "in.var.COLOR1"
1371                OpName %out_var_SV_Target0 "out.var.SV_Target0"
1372                OpName %MainPs "MainPs"
1373                OpName %PS_INPUT "PS_INPUT"
1374                OpMemberName %PS_INPUT 0 "c0"
1375                OpMemberName %PS_INPUT 1 "c1"
1376                OpName %param_var_i "param.var.i"
1377                OpName %PS_OUTPUT "PS_OUTPUT"
1378                OpMemberName %PS_OUTPUT 0 "vColor"
1379                OpName %src_MainPs "src.MainPs"
1380                OpName %i "i"
1381                OpName %bb_entry "bb.entry"
1382                OpName %ps_output "ps_output"
1383                OpName %c "c"
1384                OpDecorate %in_var_COLOR0 Location 0
1385                OpDecorate %in_var_COLOR1 Location 1
1386                OpDecorate %out_var_SV_Target0 Location 0
1387         %int = OpTypeInt 32 1
1388       %int_0 = OpConstant %int 0
1389       %int_1 = OpConstant %int 1
1390       %float = OpTypeFloat 32
1391     %float_2 = OpConstant %float 2
1392     %v4float = OpTypeVector %float 4
1393          %31 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
1394        %uint = OpTypeInt 32 0
1395     %uint_32 = OpConstant %uint 32
1396 %_ptr_Input_v4float = OpTypePointer Input %v4float
1397 %_ptr_Output_v4float = OpTypePointer Output %v4float
1398        %void = OpTypeVoid
1399    %uint_128 = OpConstant %uint 128
1400      %uint_0 = OpConstant %uint 0
1401    %uint_256 = OpConstant %uint 256
1402          %40 = OpTypeFunction %void
1403    %PS_INPUT = OpTypeStruct %v4float %v4float
1404 %_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT
1405   %PS_OUTPUT = OpTypeStruct %v4float
1406          %42 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT
1407 %_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT
1408 %_ptr_Function_v4float = OpTypePointer Function %v4float
1409 %in_var_COLOR0 = OpVariable %_ptr_Input_v4float Input
1410 %in_var_COLOR1 = OpVariable %_ptr_Input_v4float Input
1411 %out_var_SV_Target0 = OpVariable %_ptr_Output_v4float Output
1412          %45 = OpExtInst %void %1 DebugSource %6
1413          %46 = OpExtInst %void %1 DebugCompilationUnit 1 4 %45 HLSL
1414          %47 = OpExtInst %void %1 DebugTypeComposite %7 Structure %45 8 1 %46 %7 %uint_128 FlagIsProtected|FlagIsPrivate %48
1415          %49 = OpExtInst %void %1 DebugTypeBasic %8 %uint_32 Float
1416          %50 = OpExtInst %void %1 DebugTypeVector %49 4
1417          %48 = OpExtInst %void %1 DebugTypeMember %9 %50 %45 10 5 %47 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
1418          %51 = OpExtInst %void %1 DebugTypeComposite %10 Structure %45 2 1 %46 %10 %uint_256 FlagIsProtected|FlagIsPrivate %52 %53
1419          %53 = OpExtInst %void %1 DebugTypeMember %11 %50 %45 5 5 %51 %uint_128 %uint_128 FlagIsProtected|FlagIsPrivate
1420          %52 = OpExtInst %void %1 DebugTypeMember %12 %50 %45 4 5 %51 %uint_0 %uint_128 FlagIsProtected|FlagIsPrivate
1421          %54 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %47 %51
1422          %55 = OpExtInst %void %1 DebugFunction %13 %54 %45 13 1 %46 %13 FlagIsProtected|FlagIsPrivate 14 %src_MainPs
1423          %56 = OpExtInst %void %1 DebugLexicalBlock %45 14 1 %55
1424          %57 = OpExtInst %void %1 DebugLocalVariable %14 %50 %45 16 12 %56 FlagIsLocal
1425          %58 = OpExtInst %void %1 DebugLocalVariable %15 %47 %45 15 15 %56 FlagIsLocal
1426          %59 = OpExtInst %void %1 DebugExpression %60 = OpExtInst %void %1 DebugOperation Deref %61 = OpExtInst
1427 %void %1 DebugExpression %60 %62 = OpExtInst %void %1 DebugLocalVariable %16 %51
1428 %45 13 29 %55 FlagIsLocal 1 %63 = OpExtInst %void %1 DebugLocalVariable %14 %50
1429 %45 16 12 %55 FlagIsLocal 1 %MainPs = OpFunction %void None %40 %64 = OpLabel
1430 %param_var_i = OpVariable %_ptr_Function_PS_INPUT Function
1431          %65 = OpLoad %v4float %in_var_COLOR0
1432          %66 = OpLoad %v4float %in_var_COLOR1
1433          %67 = OpCompositeConstruct %PS_INPUT %65 %66
1434                OpStore %param_var_i %67
1435          %68 = OpFunctionCall %PS_OUTPUT %src_MainPs %param_var_i
1436          %69 = OpCompositeExtract %v4float %68 0
1437                OpStore %out_var_SV_Target0 %69
1438                OpReturn
1439                OpFunctionEnd
1440                OpLine %6 13 1
1441  %src_MainPs = OpFunction %PS_OUTPUT None %42
1442          %70 = OpExtInst %void %1 DebugScope %55
1443                OpLine %6 13 29
1444           %i = OpFunctionParameter %_ptr_Function_PS_INPUT
1445          %71 = OpExtInst %void %1 DebugDeclare %62 %i %59
1446          %72 = OpExtInst %void %1 DebugNoScope
1447    %bb_entry = OpLabel
1448          %73 = OpExtInst %void %1 DebugScope %56
1449   %ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function
1450           %c = OpVariable %_ptr_Function_v4float Function
1451          %74 = OpExtInst %void %1 DebugValue %63 %c %61
1452                OpLine %6 18 9
1453          %75 = OpAccessChain %_ptr_Function_v4float %i %int_0
1454                OpLine %6 18 13
1455          %76 = OpLoad %v4float %75
1456                OpLine %6 18 5
1457                OpStore %c %76
1458 ;CHECK:        OpStore %c %76
1459                OpLine %6 19 10
1460          %77 = OpAccessChain %_ptr_Function_v4float %i %int_1
1461                OpLine %6 19 14
1462          %78 = OpLoad %v4float %77
1463                OpLine %6 19 5
1464          %79 = OpLoad %v4float %c
1465 ;CHECK-NOT:       OpLine %6 19 5
1466 ;CHECK-NOT: %79 = OpLoad %v4float %c
1467                OpLine %6 19 7
1468          %80 = OpFAdd %v4float %79 %78
1469 ;CHECK-NOT: %80 = OpFAdd %v4float %79 %78
1470 ;CHECK:     %80 = OpFAdd %v4float %76 %78
1471                OpLine %6 19 5
1472                OpStore %c %80
1473 ;CHECK:        OpStore %c %80
1474                OpLine %6 20 5
1475          %81 = OpLoad %v4float %c
1476 ;CHECK-NOT:       OpLine %6 20 5
1477 ;CHECK-NOT: %81 = OpLoad %v4float %c
1478                OpLine %6 20 7
1479          %82 = OpFDiv %v4float %81 %31
1480 ;CHECK-NOT: %82 = OpFDiv %v4float %81 %31
1481 ;CHECK:     %82 = OpFDiv %v4float %80 %31
1482                OpLine %6 20 5
1483                OpStore %c %82
1484 ;CHECK:        OpStore %c %82
1485                OpLine %6 22 26
1486          %83 = OpLoad %v4float %c
1487 ;CHECK-NOT:       OpLine %6 22 26
1488 ;CHECK-NOT: %83 = OpLoad %v4float %c
1489                OpLine %6 22 5
1490          %84 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0
1491                OpStore %84 %83
1492 ;CHECK-NOT:    OpStore %84 %83
1493 ;CHECK:        OpStore %84 %82
1494                OpLine %6 23 12
1495          %85 = OpLoad %PS_OUTPUT %ps_output
1496                OpLine %6 23 5
1497                OpReturnValue %85
1498          %86 = OpExtInst %void %1 DebugNoScope
1499                OpFunctionEnd
1500   )";
1501   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1502   SinglePassRunAndMatch<LocalSingleBlockLoadStoreElimPass>(text, false);
1503 }
1504 
1505 // TODO(greg-lunarg): Add tests to verify handling of these cases:
1506 //
1507 //    Other target variable types
1508 //    InBounds Access Chains
1509 //    Check for correctness in the presence of function calls
1510 //    Others?
1511 
1512 }  // namespace
1513 }  // namespace opt
1514 }  // namespace spvtools
1515