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,SimpleLoadLoadElim)87 TEST_F(LocalSingleBlockLoadStoreElimTest, SimpleLoadLoadElim) {
88 // #version 140
89 //
90 // in vec4 BaseColor;
91 // in float fi;
92 //
93 // void main()
94 // {
95 // vec4 v = BaseColor;
96 // if (fi < 0)
97 // v = vec4(0.0);
98 // gl_FragData[0] = v;
99 // gl_FragData[1] = v;
100 // }
101
102 const std::string predefs =
103 R"(OpCapability Shader
104 %1 = OpExtInstImport "GLSL.std.450"
105 OpMemoryModel Logical GLSL450
106 OpEntryPoint Fragment %main "main" %BaseColor %fi %gl_FragData
107 OpExecutionMode %main OriginUpperLeft
108 OpSource GLSL 140
109 OpName %main "main"
110 OpName %v "v"
111 OpName %BaseColor "BaseColor"
112 OpName %fi "fi"
113 OpName %gl_FragData "gl_FragData"
114 %void = OpTypeVoid
115 %8 = OpTypeFunction %void
116 %float = OpTypeFloat 32
117 %v4float = OpTypeVector %float 4
118 %_ptr_Function_v4float = OpTypePointer Function %v4float
119 %_ptr_Input_v4float = OpTypePointer Input %v4float
120 %BaseColor = OpVariable %_ptr_Input_v4float Input
121 %_ptr_Input_float = OpTypePointer Input %float
122 %fi = OpVariable %_ptr_Input_float Input
123 %float_0 = OpConstant %float 0
124 %bool = OpTypeBool
125 %16 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
126 %uint = OpTypeInt 32 0
127 %uint_32 = OpConstant %uint 32
128 %_arr_v4float_uint_32 = OpTypeArray %v4float %uint_32
129 %_ptr_Output__arr_v4float_uint_32 = OpTypePointer Output %_arr_v4float_uint_32
130 %gl_FragData = OpVariable %_ptr_Output__arr_v4float_uint_32 Output
131 %int = OpTypeInt 32 1
132 %int_0 = OpConstant %int 0
133 %_ptr_Output_v4float = OpTypePointer Output %v4float
134 %int_1 = OpConstant %int 1
135 )";
136
137 const std::string before =
138 R"(%main = OpFunction %void None %8
139 %25 = OpLabel
140 %v = OpVariable %_ptr_Function_v4float Function
141 %26 = OpLoad %v4float %BaseColor
142 OpStore %v %26
143 %27 = OpLoad %float %fi
144 %28 = OpFOrdLessThan %bool %27 %float_0
145 OpSelectionMerge %29 None
146 OpBranchConditional %28 %30 %29
147 %30 = OpLabel
148 OpStore %v %16
149 OpBranch %29
150 %29 = OpLabel
151 %31 = OpLoad %v4float %v
152 %32 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
153 OpStore %32 %31
154 %33 = OpLoad %v4float %v
155 %34 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
156 OpStore %34 %33
157 OpReturn
158 OpFunctionEnd
159 )";
160
161 const std::string after =
162 R"(%main = OpFunction %void None %8
163 %25 = OpLabel
164 %v = OpVariable %_ptr_Function_v4float Function
165 %26 = OpLoad %v4float %BaseColor
166 OpStore %v %26
167 %27 = OpLoad %float %fi
168 %28 = OpFOrdLessThan %bool %27 %float_0
169 OpSelectionMerge %29 None
170 OpBranchConditional %28 %30 %29
171 %30 = OpLabel
172 OpStore %v %16
173 OpBranch %29
174 %29 = OpLabel
175 %31 = OpLoad %v4float %v
176 %32 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
177 OpStore %32 %31
178 %34 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
179 OpStore %34 %31
180 OpReturn
181 OpFunctionEnd
182 )";
183
184 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
185 predefs + before, predefs + after, true, true);
186 }
187
TEST_F(LocalSingleBlockLoadStoreElimTest,StoreStoreElim)188 TEST_F(LocalSingleBlockLoadStoreElimTest, StoreStoreElim) {
189 //
190 // Note first store to v is eliminated
191 //
192 // #version 450
193 //
194 // layout(location = 0) in vec4 BaseColor;
195 // layout(location = 0) out vec4 OutColor;
196 //
197 // void main()
198 // {
199 // vec4 v = BaseColor;
200 // v = v * 0.5;
201 // OutColor = v;
202 // }
203
204 const std::string predefs_before =
205 R"(OpCapability Shader
206 %1 = OpExtInstImport "GLSL.std.450"
207 OpMemoryModel Logical GLSL450
208 OpEntryPoint Fragment %main "main" %BaseColor %OutColor
209 OpExecutionMode %main OriginUpperLeft
210 OpSource GLSL 450
211 OpName %main "main"
212 OpName %v "v"
213 OpName %BaseColor "BaseColor"
214 OpName %OutColor "OutColor"
215 OpDecorate %BaseColor Location 0
216 OpDecorate %OutColor Location 0
217 %void = OpTypeVoid
218 %7 = OpTypeFunction %void
219 %float = OpTypeFloat 32
220 %v4float = OpTypeVector %float 4
221 %_ptr_Function_v4float = OpTypePointer Function %v4float
222 %_ptr_Input_v4float = OpTypePointer Input %v4float
223 %BaseColor = OpVariable %_ptr_Input_v4float Input
224 %float_0_5 = OpConstant %float 0.5
225 %_ptr_Output_v4float = OpTypePointer Output %v4float
226 %OutColor = OpVariable %_ptr_Output_v4float Output
227 )";
228
229 const std::string before =
230 R"(%main = OpFunction %void None %7
231 %14 = OpLabel
232 %v = OpVariable %_ptr_Function_v4float Function
233 %15 = OpLoad %v4float %BaseColor
234 OpStore %v %15
235 %16 = OpLoad %v4float %v
236 %17 = OpVectorTimesScalar %v4float %16 %float_0_5
237 OpStore %v %17
238 %18 = OpLoad %v4float %v
239 OpStore %OutColor %18
240 OpReturn
241 OpFunctionEnd
242 )";
243
244 const std::string after =
245 R"(%main = OpFunction %void None %7
246 %14 = OpLabel
247 %v = OpVariable %_ptr_Function_v4float Function
248 %15 = OpLoad %v4float %BaseColor
249 %17 = OpVectorTimesScalar %v4float %15 %float_0_5
250 OpStore %v %17
251 OpStore %OutColor %17
252 OpReturn
253 OpFunctionEnd
254 )";
255
256 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
257 predefs_before + before, predefs_before + after, true, true);
258 }
259
TEST_F(LocalSingleBlockLoadStoreElimTest,NoStoreElimIfInterveningAccessChainLoad)260 TEST_F(LocalSingleBlockLoadStoreElimTest,
261 NoStoreElimIfInterveningAccessChainLoad) {
262 //
263 // Note the first Store to %v is not eliminated due to the following access
264 // chain reference.
265 //
266 // #version 450
267 //
268 // layout(location = 0) in vec4 BaseColor0;
269 // layout(location = 1) in vec4 BaseColor1;
270 // layout(location = 2) flat in int Idx;
271 // layout(location = 0) out vec4 OutColor;
272 //
273 // void main()
274 // {
275 // vec4 v = BaseColor0;
276 // float f = v[Idx];
277 // v = BaseColor1 + vec4(0.1);
278 // OutColor = v/f;
279 // }
280
281 const std::string predefs =
282 R"(OpCapability Shader
283 %1 = OpExtInstImport "GLSL.std.450"
284 OpMemoryModel Logical GLSL450
285 OpEntryPoint Fragment %main "main" %BaseColor0 %Idx %BaseColor1 %OutColor
286 OpExecutionMode %main OriginUpperLeft
287 OpSource GLSL 450
288 OpName %main "main"
289 OpName %v "v"
290 OpName %BaseColor0 "BaseColor0"
291 OpName %f "f"
292 OpName %Idx "Idx"
293 OpName %BaseColor1 "BaseColor1"
294 OpName %OutColor "OutColor"
295 OpDecorate %BaseColor0 Location 0
296 OpDecorate %Idx Flat
297 OpDecorate %Idx Location 2
298 OpDecorate %BaseColor1 Location 1
299 OpDecorate %OutColor Location 0
300 %void = OpTypeVoid
301 %10 = OpTypeFunction %void
302 %float = OpTypeFloat 32
303 %v4float = OpTypeVector %float 4
304 %_ptr_Function_v4float = OpTypePointer Function %v4float
305 %_ptr_Input_v4float = OpTypePointer Input %v4float
306 %BaseColor0 = OpVariable %_ptr_Input_v4float Input
307 %_ptr_Function_float = OpTypePointer Function %float
308 %int = OpTypeInt 32 1
309 %_ptr_Input_int = OpTypePointer Input %int
310 %Idx = OpVariable %_ptr_Input_int Input
311 %BaseColor1 = OpVariable %_ptr_Input_v4float Input
312 %float_0_100000001 = OpConstant %float 0.100000001
313 %19 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
314 %_ptr_Output_v4float = OpTypePointer Output %v4float
315 %OutColor = OpVariable %_ptr_Output_v4float Output
316 )";
317
318 const std::string before =
319 R"(%main = OpFunction %void None %10
320 %21 = OpLabel
321 %v = OpVariable %_ptr_Function_v4float Function
322 %f = OpVariable %_ptr_Function_float Function
323 %22 = OpLoad %v4float %BaseColor0
324 OpStore %v %22
325 %23 = OpLoad %int %Idx
326 %24 = OpAccessChain %_ptr_Function_float %v %23
327 %25 = OpLoad %float %24
328 OpStore %f %25
329 %26 = OpLoad %v4float %BaseColor1
330 %27 = OpFAdd %v4float %26 %19
331 OpStore %v %27
332 %28 = OpLoad %v4float %v
333 %29 = OpLoad %float %f
334 %30 = OpCompositeConstruct %v4float %29 %29 %29 %29
335 %31 = OpFDiv %v4float %28 %30
336 OpStore %OutColor %31
337 OpReturn
338 OpFunctionEnd
339 )";
340
341 const std::string after =
342 R"(%main = OpFunction %void None %10
343 %21 = OpLabel
344 %v = OpVariable %_ptr_Function_v4float Function
345 %f = OpVariable %_ptr_Function_float Function
346 %22 = OpLoad %v4float %BaseColor0
347 OpStore %v %22
348 %23 = OpLoad %int %Idx
349 %24 = OpAccessChain %_ptr_Function_float %v %23
350 %25 = OpLoad %float %24
351 OpStore %f %25
352 %26 = OpLoad %v4float %BaseColor1
353 %27 = OpFAdd %v4float %26 %19
354 OpStore %v %27
355 %30 = OpCompositeConstruct %v4float %25 %25 %25 %25
356 %31 = OpFDiv %v4float %27 %30
357 OpStore %OutColor %31
358 OpReturn
359 OpFunctionEnd
360 )";
361
362 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
363 predefs + before, predefs + after, true, true);
364 }
365
TEST_F(LocalSingleBlockLoadStoreElimTest,NoElimIfInterveningAccessChainStore)366 TEST_F(LocalSingleBlockLoadStoreElimTest, NoElimIfInterveningAccessChainStore) {
367 // #version 140
368 //
369 // in vec4 BaseColor;
370 // flat in int Idx;
371 //
372 // void main()
373 // {
374 // vec4 v = BaseColor;
375 // v[Idx] = 0;
376 // gl_FragColor = v;
377 // }
378
379 const std::string assembly =
380 R"(OpCapability Shader
381 %1 = OpExtInstImport "GLSL.std.450"
382 OpMemoryModel Logical GLSL450
383 OpEntryPoint Fragment %main "main" %BaseColor %Idx %gl_FragColor
384 OpExecutionMode %main OriginUpperLeft
385 OpSource GLSL 140
386 OpName %main "main"
387 OpName %v "v"
388 OpName %BaseColor "BaseColor"
389 OpName %Idx "Idx"
390 OpName %gl_FragColor "gl_FragColor"
391 OpDecorate %Idx Flat
392 %void = OpTypeVoid
393 %8 = OpTypeFunction %void
394 %float = OpTypeFloat 32
395 %v4float = OpTypeVector %float 4
396 %_ptr_Function_v4float = OpTypePointer Function %v4float
397 %_ptr_Input_v4float = OpTypePointer Input %v4float
398 %BaseColor = OpVariable %_ptr_Input_v4float Input
399 %int = OpTypeInt 32 1
400 %_ptr_Input_int = OpTypePointer Input %int
401 %Idx = OpVariable %_ptr_Input_int Input
402 %float_0 = OpConstant %float 0
403 %_ptr_Function_float = OpTypePointer Function %float
404 %_ptr_Output_v4float = OpTypePointer Output %v4float
405 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
406 %main = OpFunction %void None %8
407 %18 = OpLabel
408 %v = OpVariable %_ptr_Function_v4float Function
409 %19 = OpLoad %v4float %BaseColor
410 OpStore %v %19
411 %20 = OpLoad %int %Idx
412 %21 = OpAccessChain %_ptr_Function_float %v %20
413 OpStore %21 %float_0
414 %22 = OpLoad %v4float %v
415 OpStore %gl_FragColor %22
416 OpReturn
417 OpFunctionEnd
418 )";
419
420 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(assembly, assembly,
421 false, true);
422 }
423
TEST_F(LocalSingleBlockLoadStoreElimTest,NoElimIfInterveningFunctionCall)424 TEST_F(LocalSingleBlockLoadStoreElimTest, NoElimIfInterveningFunctionCall) {
425 // #version 140
426 //
427 // in vec4 BaseColor;
428 //
429 // void foo() {
430 // }
431 //
432 // void main()
433 // {
434 // vec4 v = BaseColor;
435 // foo();
436 // gl_FragColor = v;
437 // }
438
439 const std::string assembly =
440 R"(OpCapability Shader
441 %1 = OpExtInstImport "GLSL.std.450"
442 OpMemoryModel Logical GLSL450
443 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
444 OpExecutionMode %main OriginUpperLeft
445 OpSource GLSL 140
446 OpName %main "main"
447 OpName %foo_ "foo("
448 OpName %v "v"
449 OpName %BaseColor "BaseColor"
450 OpName %gl_FragColor "gl_FragColor"
451 %void = OpTypeVoid
452 %8 = OpTypeFunction %void
453 %float = OpTypeFloat 32
454 %v4float = OpTypeVector %float 4
455 %_ptr_Function_v4float = OpTypePointer Function %v4float
456 %_ptr_Input_v4float = OpTypePointer Input %v4float
457 %BaseColor = OpVariable %_ptr_Input_v4float Input
458 %_ptr_Output_v4float = OpTypePointer Output %v4float
459 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
460 %main = OpFunction %void None %8
461 %14 = OpLabel
462 %v = OpVariable %_ptr_Function_v4float Function
463 %15 = OpLoad %v4float %BaseColor
464 OpStore %v %15
465 %16 = OpFunctionCall %void %foo_
466 %17 = OpLoad %v4float %v
467 OpStore %gl_FragColor %17
468 OpReturn
469 OpFunctionEnd
470 %foo_ = OpFunction %void None %8
471 %18 = OpLabel
472 OpReturn
473 OpFunctionEnd
474 )";
475
476 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(assembly, assembly,
477 false, true);
478 }
479
TEST_F(LocalSingleBlockLoadStoreElimTest,ElimIfCopyObjectInFunction)480 TEST_F(LocalSingleBlockLoadStoreElimTest, ElimIfCopyObjectInFunction) {
481 // Note: SPIR-V hand edited to insert CopyObject
482 //
483 // #version 140
484 //
485 // in vec4 BaseColor;
486 //
487 // void main()
488 // {
489 // vec4 v1 = BaseColor;
490 // gl_FragData[0] = v1;
491 // vec4 v2 = BaseColor * 0.5;
492 // gl_FragData[1] = v2;
493 // }
494
495 const std::string predefs =
496 R"(OpCapability Shader
497 %1 = OpExtInstImport "GLSL.std.450"
498 OpMemoryModel Logical GLSL450
499 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragData
500 OpExecutionMode %main OriginUpperLeft
501 OpSource GLSL 140
502 OpName %main "main"
503 OpName %v1 "v1"
504 OpName %BaseColor "BaseColor"
505 OpName %gl_FragData "gl_FragData"
506 OpName %v2 "v2"
507 %void = OpTypeVoid
508 %8 = OpTypeFunction %void
509 %float = OpTypeFloat 32
510 %v4float = OpTypeVector %float 4
511 %_ptr_Function_v4float = OpTypePointer Function %v4float
512 %_ptr_Input_v4float = OpTypePointer Input %v4float
513 %BaseColor = OpVariable %_ptr_Input_v4float Input
514 %uint = OpTypeInt 32 0
515 %uint_32 = OpConstant %uint 32
516 %_arr_v4float_uint_32 = OpTypeArray %v4float %uint_32
517 %_ptr_Output__arr_v4float_uint_32 = OpTypePointer Output %_arr_v4float_uint_32
518 %gl_FragData = OpVariable %_ptr_Output__arr_v4float_uint_32 Output
519 %int = OpTypeInt 32 1
520 %int_0 = OpConstant %int 0
521 %_ptr_Output_v4float = OpTypePointer Output %v4float
522 %float_0_5 = OpConstant %float 0.5
523 %int_1 = OpConstant %int 1
524 )";
525
526 const std::string before =
527 R"(%main = OpFunction %void None %8
528 %22 = OpLabel
529 %v1 = OpVariable %_ptr_Function_v4float Function
530 %v2 = OpVariable %_ptr_Function_v4float Function
531 %23 = OpLoad %v4float %BaseColor
532 OpStore %v1 %23
533 %24 = OpLoad %v4float %v1
534 %25 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
535 OpStore %25 %24
536 %26 = OpLoad %v4float %BaseColor
537 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
538 %28 = OpCopyObject %_ptr_Function_v4float %v2
539 OpStore %28 %27
540 %29 = OpLoad %v4float %28
541 %30 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
542 OpStore %30 %29
543 OpReturn
544 OpFunctionEnd
545 )";
546
547 const std::string after =
548 R"(%main = OpFunction %void None %8
549 %22 = OpLabel
550 %v1 = OpVariable %_ptr_Function_v4float Function
551 %v2 = OpVariable %_ptr_Function_v4float Function
552 %23 = OpLoad %v4float %BaseColor
553 OpStore %v1 %23
554 %25 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_0
555 OpStore %25 %23
556 %26 = OpLoad %v4float %BaseColor
557 %27 = OpVectorTimesScalar %v4float %26 %float_0_5
558 %28 = OpCopyObject %_ptr_Function_v4float %v2
559 OpStore %28 %27
560 %30 = OpAccessChain %_ptr_Output_v4float %gl_FragData %int_1
561 OpStore %30 %27
562 OpReturn
563 OpFunctionEnd
564 )";
565
566 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
567 predefs + before, predefs + after, true, true);
568 }
569
TEST_F(LocalSingleBlockLoadStoreElimTest,ElimOpaque)570 TEST_F(LocalSingleBlockLoadStoreElimTest, ElimOpaque) {
571 // SPIR-V not representable in GLSL; not generatable from HLSL
572 // at the moment
573
574 const std::string predefs =
575 R"(OpCapability Shader
576 %1 = OpExtInstImport "GLSL.std.450"
577 OpMemoryModel Logical GLSL450
578 OpEntryPoint Fragment %main "main" %outColor %texCoords
579 OpExecutionMode %main OriginUpperLeft
580 OpSource GLSL 140
581 OpName %main "main"
582 OpName %S_t "S_t"
583 OpMemberName %S_t 0 "v0"
584 OpMemberName %S_t 1 "v1"
585 OpMemberName %S_t 2 "smp"
586 OpName %outColor "outColor"
587 OpName %sampler15 "sampler15"
588 OpName %s0 "s0"
589 OpName %texCoords "texCoords"
590 OpName %param "param"
591 OpDecorate %sampler15 DescriptorSet 0
592 %void = OpTypeVoid
593 %12 = OpTypeFunction %void
594 %float = OpTypeFloat 32
595 %v2float = OpTypeVector %float 2
596 %v4float = OpTypeVector %float 4
597 %_ptr_Output_v4float = OpTypePointer Output %v4float
598 %outColor = OpVariable %_ptr_Output_v4float Output
599 %17 = OpTypeImage %float 2D 0 0 0 1 Unknown
600 %18 = OpTypeSampledImage %17
601 %S_t = OpTypeStruct %v2float %v2float %18
602 %_ptr_Function_S_t = OpTypePointer Function %S_t
603 %20 = OpTypeFunction %void %_ptr_Function_S_t
604 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
605 %_ptr_Function_18 = OpTypePointer Function %18
606 %sampler15 = OpVariable %_ptr_UniformConstant_18 UniformConstant
607 %int = OpTypeInt 32 1
608 %int_0 = OpConstant %int 0
609 %int_2 = OpConstant %int 2
610 %_ptr_Function_v2float = OpTypePointer Function %v2float
611 %_ptr_Input_v2float = OpTypePointer Input %v2float
612 %texCoords = OpVariable %_ptr_Input_v2float Input
613 )";
614
615 const std::string before =
616 R"(%main = OpFunction %void None %12
617 %28 = OpLabel
618 %s0 = OpVariable %_ptr_Function_S_t Function
619 %param = OpVariable %_ptr_Function_S_t Function
620 %29 = OpLoad %v2float %texCoords
621 %30 = OpLoad %S_t %s0
622 %31 = OpCompositeInsert %S_t %29 %30 0
623 OpStore %s0 %31
624 %32 = OpLoad %18 %sampler15
625 %33 = OpLoad %S_t %s0
626 %34 = OpCompositeInsert %S_t %32 %33 2
627 OpStore %s0 %34
628 %35 = OpLoad %S_t %s0
629 OpStore %param %35
630 %36 = OpLoad %S_t %param
631 %37 = OpCompositeExtract %18 %36 2
632 %38 = OpLoad %S_t %param
633 %39 = OpCompositeExtract %v2float %38 0
634 %40 = OpImageSampleImplicitLod %v4float %37 %39
635 OpStore %outColor %40
636 OpReturn
637 OpFunctionEnd
638 )";
639
640 const std::string after =
641 R"(%main = OpFunction %void None %12
642 %28 = OpLabel
643 %s0 = OpVariable %_ptr_Function_S_t Function
644 %param = OpVariable %_ptr_Function_S_t Function
645 %29 = OpLoad %v2float %texCoords
646 %30 = OpLoad %S_t %s0
647 %31 = OpCompositeInsert %S_t %29 %30 0
648 %32 = OpLoad %18 %sampler15
649 %34 = OpCompositeInsert %S_t %32 %31 2
650 OpStore %s0 %34
651 OpStore %param %34
652 %37 = OpCompositeExtract %18 %34 2
653 %39 = OpCompositeExtract %v2float %34 0
654 %40 = OpImageSampleImplicitLod %v4float %37 %39
655 OpStore %outColor %40
656 OpReturn
657 OpFunctionEnd
658 )";
659
660 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
661 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
662 predefs + before, predefs + after, true, true);
663 }
664
TEST_F(LocalSingleBlockLoadStoreElimTest,PositiveAndNegativeCallTree)665 TEST_F(LocalSingleBlockLoadStoreElimTest, PositiveAndNegativeCallTree) {
666 // Note that the call tree function bar is optimized, but foo is not
667 //
668 // #version 140
669 //
670 // in vec4 BaseColor;
671 //
672 // vec4 foo(vec4 v1)
673 // {
674 // vec4 t = v1;
675 // return t;
676 // }
677 //
678 // vec4 bar(vec4 v1)
679 // {
680 // vec4 t = v1;
681 // return t;
682 // }
683 //
684 // void main()
685 // {
686 // gl_FragColor = bar(BaseColor);
687 // }
688
689 const std::string predefs =
690 R"(OpCapability Shader
691 %1 = OpExtInstImport "GLSL.std.450"
692 OpMemoryModel Logical GLSL450
693 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor
694 OpExecutionMode %main OriginUpperLeft
695 OpSource GLSL 140
696 OpName %main "main"
697 OpName %foo_vf4_ "foo(vf4;"
698 OpName %v1 "v1"
699 OpName %bar_vf4_ "bar(vf4;"
700 OpName %v1_0 "v1"
701 OpName %t "t"
702 OpName %t_0 "t"
703 OpName %gl_FragColor "gl_FragColor"
704 OpName %BaseColor "BaseColor"
705 OpName %param "param"
706 %void = OpTypeVoid
707 %13 = OpTypeFunction %void
708 %float = OpTypeFloat 32
709 %v4float = OpTypeVector %float 4
710 %_ptr_Function_v4float = OpTypePointer Function %v4float
711 %17 = OpTypeFunction %v4float %_ptr_Function_v4float
712 %_ptr_Output_v4float = OpTypePointer Output %v4float
713 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
714 %_ptr_Input_v4float = OpTypePointer Input %v4float
715 %BaseColor = OpVariable %_ptr_Input_v4float Input
716 %main = OpFunction %void None %13
717 %20 = OpLabel
718 %param = OpVariable %_ptr_Function_v4float Function
719 %21 = OpLoad %v4float %BaseColor
720 OpStore %param %21
721 %22 = OpFunctionCall %v4float %bar_vf4_ %param
722 OpStore %gl_FragColor %22
723 OpReturn
724 OpFunctionEnd
725 )";
726
727 const std::string before =
728 R"(%foo_vf4_ = OpFunction %v4float None %17
729 %v1 = OpFunctionParameter %_ptr_Function_v4float
730 %23 = OpLabel
731 %t = OpVariable %_ptr_Function_v4float Function
732 %24 = OpLoad %v4float %v1
733 OpStore %t %24
734 %25 = OpLoad %v4float %t
735 OpReturnValue %25
736 OpFunctionEnd
737 %bar_vf4_ = OpFunction %v4float None %17
738 %v1_0 = OpFunctionParameter %_ptr_Function_v4float
739 %26 = OpLabel
740 %t_0 = OpVariable %_ptr_Function_v4float Function
741 %27 = OpLoad %v4float %v1_0
742 OpStore %t_0 %27
743 %28 = OpLoad %v4float %t_0
744 OpReturnValue %28
745 OpFunctionEnd
746 )";
747
748 const std::string after =
749 R"(%foo_vf4_ = OpFunction %v4float None %17
750 %v1 = OpFunctionParameter %_ptr_Function_v4float
751 %23 = OpLabel
752 %t = OpVariable %_ptr_Function_v4float Function
753 %24 = OpLoad %v4float %v1
754 OpStore %t %24
755 %25 = OpLoad %v4float %t
756 OpReturnValue %25
757 OpFunctionEnd
758 %bar_vf4_ = OpFunction %v4float None %17
759 %v1_0 = OpFunctionParameter %_ptr_Function_v4float
760 %26 = OpLabel
761 %t_0 = OpVariable %_ptr_Function_v4float Function
762 %27 = OpLoad %v4float %v1_0
763 OpStore %t_0 %27
764 OpReturnValue %27
765 OpFunctionEnd
766 )";
767
768 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
769 predefs + before, predefs + after, true, true);
770 }
771
TEST_F(LocalSingleBlockLoadStoreElimTest,PointerVariable)772 TEST_F(LocalSingleBlockLoadStoreElimTest, PointerVariable) {
773 // Test that checks if a pointer variable is removed.
774
775 const std::string before =
776 R"(OpCapability Shader
777 OpMemoryModel Logical GLSL450
778 OpEntryPoint Fragment %1 "main" %2
779 OpExecutionMode %1 OriginUpperLeft
780 OpMemberDecorate %_struct_3 0 Offset 0
781 OpDecorate %_runtimearr__struct_3 ArrayStride 16
782 OpMemberDecorate %_struct_5 0 Offset 0
783 OpDecorate %_struct_5 BufferBlock
784 OpMemberDecorate %_struct_6 0 Offset 0
785 OpDecorate %_struct_6 BufferBlock
786 OpDecorate %2 Location 0
787 OpDecorate %7 DescriptorSet 0
788 OpDecorate %7 Binding 0
789 %void = OpTypeVoid
790 %10 = OpTypeFunction %void
791 %int = OpTypeInt 32 1
792 %uint = OpTypeInt 32 0
793 %float = OpTypeFloat 32
794 %v4float = OpTypeVector %float 4
795 %_ptr_Output_v4float = OpTypePointer Output %v4float
796 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
797 %_struct_3 = OpTypeStruct %v4float
798 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
799 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
800 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
801 %_struct_6 = OpTypeStruct %int
802 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
803 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
804 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
805 %int_0 = OpConstant %int 0
806 %uint_0 = OpConstant %uint 0
807 %2 = OpVariable %_ptr_Output_v4float Output
808 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
809 %1 = OpFunction %void None %10
810 %23 = OpLabel
811 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
812 OpStore %24 %7
813 %26 = OpLoad %_ptr_Uniform__struct_5 %24
814 %27 = OpAccessChain %_ptr_Uniform_v4float %26 %int_0 %uint_0 %int_0
815 %28 = OpLoad %v4float %27
816 %29 = OpCopyObject %v4float %28
817 OpStore %2 %28
818 OpReturn
819 OpFunctionEnd
820 )";
821
822 const std::string after =
823 R"(OpCapability Shader
824 OpMemoryModel Logical GLSL450
825 OpEntryPoint Fragment %1 "main" %2
826 OpExecutionMode %1 OriginUpperLeft
827 OpMemberDecorate %_struct_3 0 Offset 0
828 OpDecorate %_runtimearr__struct_3 ArrayStride 16
829 OpMemberDecorate %_struct_5 0 Offset 0
830 OpDecorate %_struct_5 BufferBlock
831 OpMemberDecorate %_struct_6 0 Offset 0
832 OpDecorate %_struct_6 BufferBlock
833 OpDecorate %2 Location 0
834 OpDecorate %7 DescriptorSet 0
835 OpDecorate %7 Binding 0
836 %void = OpTypeVoid
837 %10 = OpTypeFunction %void
838 %int = OpTypeInt 32 1
839 %uint = OpTypeInt 32 0
840 %float = OpTypeFloat 32
841 %v4float = OpTypeVector %float 4
842 %_ptr_Output_v4float = OpTypePointer Output %v4float
843 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
844 %_struct_3 = OpTypeStruct %v4float
845 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3
846 %_struct_5 = OpTypeStruct %_runtimearr__struct_3
847 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5
848 %_struct_6 = OpTypeStruct %int
849 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6
850 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5
851 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6
852 %int_0 = OpConstant %int 0
853 %uint_0 = OpConstant %uint 0
854 %2 = OpVariable %_ptr_Output_v4float Output
855 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform
856 %1 = OpFunction %void None %10
857 %23 = OpLabel
858 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function
859 OpStore %24 %7
860 %27 = OpAccessChain %_ptr_Uniform_v4float %7 %int_0 %uint_0 %int_0
861 %28 = OpLoad %v4float %27
862 %29 = OpCopyObject %v4float %28
863 OpStore %2 %28
864 OpReturn
865 OpFunctionEnd
866 )";
867
868 // Relax logical pointers to allow pointer allocations.
869 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
870 ValidatorOptions()->relax_logical_pointer = true;
871 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(before, after, true,
872 true);
873 }
874
TEST_F(LocalSingleBlockLoadStoreElimTest,RedundantStore)875 TEST_F(LocalSingleBlockLoadStoreElimTest, RedundantStore) {
876 // Test that checks if a pointer variable is removed.
877 const std::string predefs_before =
878 R"(OpCapability Shader
879 %1 = OpExtInstImport "GLSL.std.450"
880 OpMemoryModel Logical GLSL450
881 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
882 OpExecutionMode %main OriginUpperLeft
883 OpSource GLSL 140
884 OpName %main "main"
885 OpName %v "v"
886 OpName %BaseColor "BaseColor"
887 OpName %gl_FragColor "gl_FragColor"
888 %void = OpTypeVoid
889 %7 = OpTypeFunction %void
890 %float = OpTypeFloat 32
891 %v4float = OpTypeVector %float 4
892 %_ptr_Function_v4float = OpTypePointer Function %v4float
893 %_ptr_Input_v4float = OpTypePointer Input %v4float
894 %BaseColor = OpVariable %_ptr_Input_v4float Input
895 %_ptr_Output_v4float = OpTypePointer Output %v4float
896 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
897 )";
898
899 const std::string before =
900 R"(%main = OpFunction %void None %7
901 %13 = OpLabel
902 %v = OpVariable %_ptr_Function_v4float Function
903 %14 = OpLoad %v4float %BaseColor
904 OpStore %v %14
905 OpBranch %16
906 %16 = OpLabel
907 %15 = OpLoad %v4float %v
908 OpStore %v %15
909 OpReturn
910 OpFunctionEnd
911 )";
912
913 const std::string after =
914 R"(%main = OpFunction %void None %7
915 %13 = OpLabel
916 %v = OpVariable %_ptr_Function_v4float Function
917 %14 = OpLoad %v4float %BaseColor
918 OpStore %v %14
919 OpBranch %16
920 %16 = OpLabel
921 %15 = OpLoad %v4float %v
922 OpReturn
923 OpFunctionEnd
924 )";
925
926 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
927 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
928 predefs_before + before, predefs_before + after, true, true);
929 }
930
TEST_F(LocalSingleBlockLoadStoreElimTest,RedundantStore2)931 TEST_F(LocalSingleBlockLoadStoreElimTest, RedundantStore2) {
932 // Test that checks if a pointer variable is removed.
933 const std::string predefs_before =
934 R"(OpCapability Shader
935 %1 = OpExtInstImport "GLSL.std.450"
936 OpMemoryModel Logical GLSL450
937 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
938 OpExecutionMode %main OriginUpperLeft
939 OpSource GLSL 140
940 OpName %main "main"
941 OpName %v "v"
942 OpName %BaseColor "BaseColor"
943 OpName %gl_FragColor "gl_FragColor"
944 %void = OpTypeVoid
945 %7 = OpTypeFunction %void
946 %float = OpTypeFloat 32
947 %v4float = OpTypeVector %float 4
948 %_ptr_Function_v4float = OpTypePointer Function %v4float
949 %_ptr_Input_v4float = OpTypePointer Input %v4float
950 %BaseColor = OpVariable %_ptr_Input_v4float Input
951 %_ptr_Output_v4float = OpTypePointer Output %v4float
952 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
953 )";
954
955 const std::string before =
956 R"(%main = OpFunction %void None %7
957 %13 = OpLabel
958 %v = OpVariable %_ptr_Function_v4float Function
959 %14 = OpLoad %v4float %BaseColor
960 OpStore %v %14
961 OpBranch %16
962 %16 = OpLabel
963 %15 = OpLoad %v4float %v
964 OpStore %v %15
965 %17 = OpLoad %v4float %v
966 OpStore %v %17
967 OpReturn
968 OpFunctionEnd
969 )";
970
971 const std::string after =
972 R"(%main = OpFunction %void None %7
973 %13 = OpLabel
974 %v = OpVariable %_ptr_Function_v4float Function
975 %14 = OpLoad %v4float %BaseColor
976 OpStore %v %14
977 OpBranch %16
978 %16 = OpLabel
979 %15 = OpLoad %v4float %v
980 OpReturn
981 OpFunctionEnd
982 )";
983
984 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
985 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
986 predefs_before + before, predefs_before + after, true, true);
987 }
988
989 // Test that that an unused OpAccessChain between two store does does not
990 // hinders the removal of the first store. We need to check this because
991 // local-access-chain-convert does always remove the OpAccessChain instructions
992 // that become dead.
993
TEST_F(LocalSingleBlockLoadStoreElimTest,StoreElimIfInterveningUnusedAccessChain)994 TEST_F(LocalSingleBlockLoadStoreElimTest,
995 StoreElimIfInterveningUnusedAccessChain) {
996 const std::string predefs =
997 R"(OpCapability Shader
998 %1 = OpExtInstImport "GLSL.std.450"
999 OpMemoryModel Logical GLSL450
1000 OpEntryPoint Fragment %main "main" %BaseColor0 %Idx %BaseColor1 %OutColor
1001 OpExecutionMode %main OriginUpperLeft
1002 OpSource GLSL 450
1003 OpName %main "main"
1004 OpName %v "v"
1005 OpName %BaseColor0 "BaseColor0"
1006 OpName %Idx "Idx"
1007 OpName %BaseColor1 "BaseColor1"
1008 OpName %OutColor "OutColor"
1009 OpDecorate %BaseColor0 Location 0
1010 OpDecorate %Idx Flat
1011 OpDecorate %Idx Location 2
1012 OpDecorate %BaseColor1 Location 1
1013 OpDecorate %OutColor Location 0
1014 %void = OpTypeVoid
1015 %10 = OpTypeFunction %void
1016 %float = OpTypeFloat 32
1017 %v4float = OpTypeVector %float 4
1018 %_ptr_Function_v4float = OpTypePointer Function %v4float
1019 %_ptr_Input_v4float = OpTypePointer Input %v4float
1020 %BaseColor0 = OpVariable %_ptr_Input_v4float Input
1021 %_ptr_Function_float = OpTypePointer Function %float
1022 %int = OpTypeInt 32 1
1023 %_ptr_Input_int = OpTypePointer Input %int
1024 %Idx = OpVariable %_ptr_Input_int Input
1025 %BaseColor1 = OpVariable %_ptr_Input_v4float Input
1026 %float_0_100000001 = OpConstant %float 0.100000001
1027 %19 = OpConstantComposite %v4float %float_0_100000001 %float_0_100000001 %float_0_100000001 %float_0_100000001
1028 %_ptr_Output_v4float = OpTypePointer Output %v4float
1029 %OutColor = OpVariable %_ptr_Output_v4float Output
1030 )";
1031
1032 const std::string before =
1033 R"(%main = OpFunction %void None %10
1034 %21 = OpLabel
1035 %v = OpVariable %_ptr_Function_v4float Function
1036 %22 = OpLoad %v4float %BaseColor0
1037 OpStore %v %22
1038 %23 = OpLoad %int %Idx
1039 %24 = OpAccessChain %_ptr_Function_float %v %23
1040 %26 = OpLoad %v4float %BaseColor1
1041 %27 = OpFAdd %v4float %26 %19
1042 OpStore %v %27
1043 OpReturn
1044 OpFunctionEnd
1045 )";
1046
1047 const std::string after =
1048 R"(%main = OpFunction %void None %10
1049 %21 = OpLabel
1050 %v = OpVariable %_ptr_Function_v4float Function
1051 %22 = OpLoad %v4float %BaseColor0
1052 %23 = OpLoad %int %Idx
1053 %24 = OpAccessChain %_ptr_Function_float %v %23
1054 %26 = OpLoad %v4float %BaseColor1
1055 %27 = OpFAdd %v4float %26 %19
1056 OpStore %v %27
1057 OpReturn
1058 OpFunctionEnd
1059 )";
1060
1061 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1062 SinglePassRunAndCheck<LocalSingleBlockLoadStoreElimPass>(
1063 predefs + before, predefs + after, true, true);
1064 }
1065 // TODO(greg-lunarg): Add tests to verify handling of these cases:
1066 //
1067 // Other target variable types
1068 // InBounds Access Chains
1069 // Check for correctness in the presence of function calls
1070 // Others?
1071
1072 } // namespace
1073 } // namespace opt
1074 } // namespace spvtools
1075