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 LocalAccessChainConvertTest = PassTest<::testing::Test>;
26
TEST_F(LocalAccessChainConvertTest,StructOfVecsOfFloatConverted)27 TEST_F(LocalAccessChainConvertTest, StructOfVecsOfFloatConverted) {
28 // #version 140
29 //
30 // in vec4 BaseColor;
31 //
32 // struct S_t {
33 // vec4 v0;
34 // vec4 v1;
35 // };
36 //
37 // void main()
38 // {
39 // S_t s0;
40 // s0.v1 = BaseColor;
41 // gl_FragColor = s0.v1;
42 // }
43
44 const std::string predefs_before =
45 R"(OpCapability Shader
46 %1 = OpExtInstImport "GLSL.std.450"
47 OpMemoryModel Logical GLSL450
48 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
49 OpExecutionMode %main OriginUpperLeft
50 OpSource GLSL 140
51 OpName %main "main"
52 OpName %S_t "S_t"
53 OpMemberName %S_t 0 "v0"
54 OpMemberName %S_t 1 "v1"
55 OpName %s0 "s0"
56 OpName %BaseColor "BaseColor"
57 OpName %gl_FragColor "gl_FragColor"
58 %void = OpTypeVoid
59 %8 = OpTypeFunction %void
60 %float = OpTypeFloat 32
61 %v4float = OpTypeVector %float 4
62 %S_t = OpTypeStruct %v4float %v4float
63 %_ptr_Function_S_t = OpTypePointer Function %S_t
64 %int = OpTypeInt 32 1
65 %int_1 = OpConstant %int 1
66 %_ptr_Input_v4float = OpTypePointer Input %v4float
67 %BaseColor = OpVariable %_ptr_Input_v4float Input
68 %_ptr_Function_v4float = OpTypePointer Function %v4float
69 %_ptr_Output_v4float = OpTypePointer Output %v4float
70 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
71 )";
72
73 const std::string before =
74 R"(
75 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
76 ; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0
77 ; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
78 ; CHECK: OpStore %s0 [[ex1]]
79 ; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0
80 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
81 ; CHECK: OpStore %gl_FragColor [[ex2]]
82 %main = OpFunction %void None %8
83 %17 = OpLabel
84 %s0 = OpVariable %_ptr_Function_S_t Function
85 %18 = OpLoad %v4float %BaseColor
86 %19 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
87 OpStore %19 %18
88 %20 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
89 %21 = OpLoad %v4float %20
90 OpStore %gl_FragColor %21
91 OpReturn
92 OpFunctionEnd
93 )";
94
95 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
96 true);
97 }
98
TEST_F(LocalAccessChainConvertTest,InBoundsAccessChainsConverted)99 TEST_F(LocalAccessChainConvertTest, InBoundsAccessChainsConverted) {
100 // #version 140
101 //
102 // in vec4 BaseColor;
103 //
104 // struct S_t {
105 // vec4 v0;
106 // vec4 v1;
107 // };
108 //
109 // void main()
110 // {
111 // S_t s0;
112 // s0.v1 = BaseColor;
113 // gl_FragColor = s0.v1;
114 // }
115
116 const std::string predefs_before =
117 R"(OpCapability Shader
118 %1 = OpExtInstImport "GLSL.std.450"
119 OpMemoryModel Logical GLSL450
120 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
121 OpExecutionMode %main OriginUpperLeft
122 OpSource GLSL 140
123 OpName %main "main"
124 OpName %S_t "S_t"
125 OpMemberName %S_t 0 "v0"
126 OpMemberName %S_t 1 "v1"
127 OpName %s0 "s0"
128 OpName %BaseColor "BaseColor"
129 OpName %gl_FragColor "gl_FragColor"
130 %void = OpTypeVoid
131 %8 = OpTypeFunction %void
132 %float = OpTypeFloat 32
133 %v4float = OpTypeVector %float 4
134 %S_t = OpTypeStruct %v4float %v4float
135 %_ptr_Function_S_t = OpTypePointer Function %S_t
136 %int = OpTypeInt 32 1
137 %int_1 = OpConstant %int 1
138 %_ptr_Input_v4float = OpTypePointer Input %v4float
139 %BaseColor = OpVariable %_ptr_Input_v4float Input
140 %_ptr_Function_v4float = OpTypePointer Function %v4float
141 %_ptr_Output_v4float = OpTypePointer Output %v4float
142 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
143 )";
144
145 const std::string before =
146 R"(
147 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
148 ; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0
149 ; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
150 ; CHECK: OpStore %s0 [[ex1]]
151 ; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0
152 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
153 ; CHECK: OpStore %gl_FragColor [[ex2]]
154 %main = OpFunction %void None %8
155 %17 = OpLabel
156 %s0 = OpVariable %_ptr_Function_S_t Function
157 %18 = OpLoad %v4float %BaseColor
158 %19 = OpInBoundsAccessChain %_ptr_Function_v4float %s0 %int_1
159 OpStore %19 %18
160 %20 = OpInBoundsAccessChain %_ptr_Function_v4float %s0 %int_1
161 %21 = OpLoad %v4float %20
162 OpStore %gl_FragColor %21
163 OpReturn
164 OpFunctionEnd
165 )";
166
167 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
168 true);
169 }
170
TEST_F(LocalAccessChainConvertTest,TwoUsesofSingleChainConverted)171 TEST_F(LocalAccessChainConvertTest, TwoUsesofSingleChainConverted) {
172 // #version 140
173 //
174 // in vec4 BaseColor;
175 //
176 // struct S_t {
177 // vec4 v0;
178 // vec4 v1;
179 // };
180 //
181 // void main()
182 // {
183 // S_t s0;
184 // s0.v1 = BaseColor;
185 // gl_FragColor = s0.v1;
186 // }
187
188 const std::string predefs_before =
189 R"(OpCapability Shader
190 %1 = OpExtInstImport "GLSL.std.450"
191 OpMemoryModel Logical GLSL450
192 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
193 OpExecutionMode %main OriginUpperLeft
194 OpSource GLSL 140
195 OpName %main "main"
196 OpName %S_t "S_t"
197 OpMemberName %S_t 0 "v0"
198 OpMemberName %S_t 1 "v1"
199 OpName %s0 "s0"
200 OpName %BaseColor "BaseColor"
201 OpName %gl_FragColor "gl_FragColor"
202 %void = OpTypeVoid
203 %8 = OpTypeFunction %void
204 %float = OpTypeFloat 32
205 %v4float = OpTypeVector %float 4
206 %S_t = OpTypeStruct %v4float %v4float
207 %_ptr_Function_S_t = OpTypePointer Function %S_t
208 %int = OpTypeInt 32 1
209 %int_1 = OpConstant %int 1
210 %_ptr_Input_v4float = OpTypePointer Input %v4float
211 %BaseColor = OpVariable %_ptr_Input_v4float Input
212 %_ptr_Function_v4float = OpTypePointer Function %v4float
213 %_ptr_Output_v4float = OpTypePointer Output %v4float
214 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
215 )";
216
217 const std::string before =
218 R"(
219 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
220 ; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0
221 ; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
222 ; CHECK: OpStore %s0 [[ex1]]
223 ; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0
224 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
225 ; CHECK: OpStore %gl_FragColor [[ex2]]
226 %main = OpFunction %void None %8
227 %17 = OpLabel
228 %s0 = OpVariable %_ptr_Function_S_t Function
229 %18 = OpLoad %v4float %BaseColor
230 %19 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
231 OpStore %19 %18
232 %20 = OpLoad %v4float %19
233 OpStore %gl_FragColor %20
234 OpReturn
235 OpFunctionEnd
236 )";
237
238 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
239 true);
240 }
241
TEST_F(LocalAccessChainConvertTest,OpaqueConverted)242 TEST_F(LocalAccessChainConvertTest, OpaqueConverted) {
243 // SPIR-V not representable in GLSL; not generatable from HLSL
244 // at the moment
245
246 const std::string predefs =
247 R"(
248 OpCapability Shader
249 %1 = OpExtInstImport "GLSL.std.450"
250 OpMemoryModel Logical GLSL450
251 OpEntryPoint Fragment %main "main" %outColor %texCoords
252 OpExecutionMode %main OriginUpperLeft
253 OpSource GLSL 140
254 OpName %main "main"
255 OpName %S_t "S_t"
256 OpMemberName %S_t 0 "v0"
257 OpMemberName %S_t 1 "v1"
258 OpMemberName %S_t 2 "smp"
259 OpName %foo_struct_S_t_vf2_vf21_ "foo(struct-S_t-vf2-vf21;"
260 OpName %s "s"
261 OpName %outColor "outColor"
262 OpName %sampler15 "sampler15"
263 OpName %s0 "s0"
264 OpName %texCoords "texCoords"
265 OpName %param "param"
266 OpDecorate %sampler15 DescriptorSet 0
267 %void = OpTypeVoid
268 %12 = OpTypeFunction %void
269 %float = OpTypeFloat 32
270 %v2float = OpTypeVector %float 2
271 %v4float = OpTypeVector %float 4
272 %_ptr_Output_v4float = OpTypePointer Output %v4float
273 %outColor = OpVariable %_ptr_Output_v4float Output
274 %17 = OpTypeImage %float 2D 0 0 0 1 Unknown
275 %18 = OpTypeSampledImage %17
276 %S_t = OpTypeStruct %v2float %v2float %18
277 %_ptr_Function_S_t = OpTypePointer Function %S_t
278 %20 = OpTypeFunction %void %_ptr_Function_S_t
279 %_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
280 %_ptr_Function_18 = OpTypePointer Function %18
281 %sampler15 = OpVariable %_ptr_UniformConstant_18 UniformConstant
282 %int = OpTypeInt 32 1
283 %int_0 = OpConstant %int 0
284 %int_2 = OpConstant %int 2
285 %_ptr_Function_v2float = OpTypePointer Function %v2float
286 %_ptr_Input_v2float = OpTypePointer Input %v2float
287 %texCoords = OpVariable %_ptr_Input_v2float Input
288 )";
289
290 const std::string before =
291 R"(
292 ; CHECK: [[l1:%\w+]] = OpLoad %S_t %param
293 ; CHECK: [[e1:%\w+]] = OpCompositeExtract {{%\w+}} [[l1]] 2
294 ; CHECK: [[l2:%\w+]] = OpLoad %S_t %param
295 ; CHECK: [[e2:%\w+]] = OpCompositeExtract {{%\w+}} [[l2]] 0
296 ; CHECK: OpImageSampleImplicitLod {{%\w+}} [[e1]] [[e2]]
297 %main = OpFunction %void None %12
298 %28 = OpLabel
299 %s0 = OpVariable %_ptr_Function_S_t Function
300 %param = OpVariable %_ptr_Function_S_t Function
301 %29 = OpLoad %v2float %texCoords
302 %30 = OpAccessChain %_ptr_Function_v2float %s0 %int_0
303 OpStore %30 %29
304 %31 = OpLoad %18 %sampler15
305 %32 = OpAccessChain %_ptr_Function_18 %s0 %int_2
306 OpStore %32 %31
307 %33 = OpLoad %S_t %s0
308 OpStore %param %33
309 %34 = OpAccessChain %_ptr_Function_18 %param %int_2
310 %35 = OpLoad %18 %34
311 %36 = OpAccessChain %_ptr_Function_v2float %param %int_0
312 %37 = OpLoad %v2float %36
313 %38 = OpImageSampleImplicitLod %v4float %35 %37
314 OpStore %outColor %38
315 OpReturn
316 OpFunctionEnd
317 )";
318
319 const std::string remain =
320 R"(%foo_struct_S_t_vf2_vf21_ = OpFunction %void None %20
321 %s = OpFunctionParameter %_ptr_Function_S_t
322 %39 = OpLabel
323 %40 = OpAccessChain %_ptr_Function_18 %s %int_2
324 %41 = OpLoad %18 %40
325 %42 = OpAccessChain %_ptr_Function_v2float %s %int_0
326 %43 = OpLoad %v2float %42
327 %44 = OpImageSampleImplicitLod %v4float %41 %43
328 OpStore %outColor %44
329 OpReturn
330 OpFunctionEnd
331 )";
332
333 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs + before + remain,
334 true);
335 }
336
TEST_F(LocalAccessChainConvertTest,NestedStructsConverted)337 TEST_F(LocalAccessChainConvertTest, NestedStructsConverted) {
338 // #version 140
339 //
340 // in vec4 BaseColor;
341 //
342 // struct S1_t {
343 // vec4 v1;
344 // };
345 //
346 // struct S2_t {
347 // vec4 v2;
348 // S1_t s1;
349 // };
350 //
351 // void main()
352 // {
353 // S2_t s2;
354 // s2.s1.v1 = BaseColor;
355 // gl_FragColor = s2.s1.v1;
356 // }
357
358 const std::string predefs_before =
359 R"(OpCapability Shader
360 %1 = OpExtInstImport "GLSL.std.450"
361 OpMemoryModel Logical GLSL450
362 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
363 OpExecutionMode %main OriginUpperLeft
364 OpSource GLSL 140
365 OpName %main "main"
366 OpName %S1_t "S1_t"
367 OpMemberName %S1_t 0 "v1"
368 OpName %S2_t "S2_t"
369 OpMemberName %S2_t 0 "v2"
370 OpMemberName %S2_t 1 "s1"
371 OpName %s2 "s2"
372 OpName %BaseColor "BaseColor"
373 OpName %gl_FragColor "gl_FragColor"
374 %void = OpTypeVoid
375 %9 = OpTypeFunction %void
376 %float = OpTypeFloat 32
377 %v4float = OpTypeVector %float 4
378 %S1_t = OpTypeStruct %v4float
379 %S2_t = OpTypeStruct %v4float %S1_t
380 %_ptr_Function_S2_t = OpTypePointer Function %S2_t
381 %int = OpTypeInt 32 1
382 %int_1 = OpConstant %int 1
383 %int_0 = OpConstant %int 0
384 %_ptr_Input_v4float = OpTypePointer Input %v4float
385 %BaseColor = OpVariable %_ptr_Input_v4float Input
386 %_ptr_Function_v4float = OpTypePointer Function %v4float
387 %_ptr_Output_v4float = OpTypePointer Output %v4float
388 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
389 )";
390
391 const std::string before =
392 R"(
393 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
394 ; CHECK: [[ld1:%\w+]] = OpLoad %S2_t %s2
395 ; CHECK: [[ex1:%\w+]] = OpCompositeInsert %S2_t [[st_id]] [[ld1]] 1 0
396 ; CHECK: OpStore %s2 [[ex1]]
397 ; CHECK: [[ld2:%\w+]] = OpLoad %S2_t %s2
398 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1 0
399 ; CHECK: OpStore %gl_FragColor [[ex2]]
400 %main = OpFunction %void None %9
401 %19 = OpLabel
402 %s2 = OpVariable %_ptr_Function_S2_t Function
403 %20 = OpLoad %v4float %BaseColor
404 %21 = OpAccessChain %_ptr_Function_v4float %s2 %int_1 %int_0
405 OpStore %21 %20
406 %22 = OpAccessChain %_ptr_Function_v4float %s2 %int_1 %int_0
407 %23 = OpLoad %v4float %22
408 OpStore %gl_FragColor %23
409 OpReturn
410 OpFunctionEnd
411 )";
412
413 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
414 true);
415 }
416
TEST_F(LocalAccessChainConvertTest,SomeAccessChainsHaveNoUse)417 TEST_F(LocalAccessChainConvertTest, SomeAccessChainsHaveNoUse) {
418 // Based on HLSL source code:
419 // struct S {
420 // float f;
421 // };
422
423 // float main(float input : A) : B {
424 // S local = { input };
425 // return local.f;
426 // }
427
428 const std::string predefs = R"(OpCapability Shader
429 OpMemoryModel Logical GLSL450
430 OpEntryPoint Vertex %main "main" %in_var_A %out_var_B
431 OpName %main "main"
432 OpName %in_var_A "in.var.A"
433 OpName %out_var_B "out.var.B"
434 OpName %S "S"
435 OpName %local "local"
436 %int = OpTypeInt 32 1
437 %void = OpTypeVoid
438 %8 = OpTypeFunction %void
439 %float = OpTypeFloat 32
440 %_ptr_Function_float = OpTypePointer Function %float
441 %_ptr_Input_float = OpTypePointer Input %float
442 %_ptr_Output_float = OpTypePointer Output %float
443 %S = OpTypeStruct %float
444 %_ptr_Function_S = OpTypePointer Function %S
445 %int_0 = OpConstant %int 0
446 %in_var_A = OpVariable %_ptr_Input_float Input
447 %out_var_B = OpVariable %_ptr_Output_float Output
448 %main = OpFunction %void None %8
449 %15 = OpLabel
450 %local = OpVariable %_ptr_Function_S Function
451 %16 = OpLoad %float %in_var_A
452 %17 = OpCompositeConstruct %S %16
453 OpStore %local %17
454 )";
455
456 const std::string before =
457 R"(
458 ; CHECK: [[ld:%\w+]] = OpLoad %S %local
459 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0
460 ; CHECK: OpStore %out_var_B [[ex]]
461 %18 = OpAccessChain %_ptr_Function_float %local %int_0
462 %19 = OpAccessChain %_ptr_Function_float %local %int_0
463 %20 = OpLoad %float %18
464 OpStore %out_var_B %20
465 OpReturn
466 OpFunctionEnd
467 )";
468
469 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs + before, true);
470 }
471
TEST_F(LocalAccessChainConvertTest,StructOfVecsOfFloatConvertedWithDecorationOnLoad)472 TEST_F(LocalAccessChainConvertTest,
473 StructOfVecsOfFloatConvertedWithDecorationOnLoad) {
474 // #version 140
475 //
476 // in vec4 BaseColor;
477 //
478 // struct S_t {
479 // vec4 v0;
480 // vec4 v1;
481 // };
482 //
483 // void main()
484 // {
485 // S_t s0;
486 // s0.v1 = BaseColor;
487 // gl_FragColor = s0.v1;
488 // }
489
490 const std::string predefs_before =
491 R"(OpCapability Shader
492 %1 = OpExtInstImport "GLSL.std.450"
493 OpMemoryModel Logical GLSL450
494 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
495 OpExecutionMode %main OriginUpperLeft
496 OpSource GLSL 140
497 OpName %main "main"
498 OpName %S_t "S_t"
499 OpMemberName %S_t 0 "v0"
500 OpMemberName %S_t 1 "v1"
501 OpName %s0 "s0"
502 OpName %BaseColor "BaseColor"
503 OpName %gl_FragColor "gl_FragColor"
504 OpDecorate %21 RelaxedPrecision
505 %void = OpTypeVoid
506 %8 = OpTypeFunction %void
507 %float = OpTypeFloat 32
508 %v4float = OpTypeVector %float 4
509 %S_t = OpTypeStruct %v4float %v4float
510 %_ptr_Function_S_t = OpTypePointer Function %S_t
511 %int = OpTypeInt 32 1
512 %int_1 = OpConstant %int 1
513 %_ptr_Input_v4float = OpTypePointer Input %v4float
514 %BaseColor = OpVariable %_ptr_Input_v4float Input
515 %_ptr_Function_v4float = OpTypePointer Function %v4float
516 %_ptr_Output_v4float = OpTypePointer Output %v4float
517 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
518 )";
519
520 const std::string before =
521 R"(
522 ; CHECK: OpDecorate
523 ; CHECK: OpDecorate [[ld2:%\w+]] RelaxedPrecision
524 ; CHECK-NOT: OpDecorate
525 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
526 ; CHECK: [[ld1:%\w+]] = OpLoad %S_t %s0
527 ; CHECK: [[ins:%\w+]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
528 ; CHECK: OpStore %s0 [[ins]]
529 ; CHECK: [[ld2]] = OpLoad %S_t %s0
530 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
531 ; CHECK: OpStore %gl_FragColor [[ex2]]
532 %main = OpFunction %void None %8
533 %17 = OpLabel
534 %s0 = OpVariable %_ptr_Function_S_t Function
535 %18 = OpLoad %v4float %BaseColor
536 %19 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
537 OpStore %19 %18
538 %20 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
539 %21 = OpLoad %v4float %20
540 OpStore %gl_FragColor %21
541 OpReturn
542 OpFunctionEnd
543 )";
544
545 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
546 true);
547 }
548
TEST_F(LocalAccessChainConvertTest,StructOfVecsOfFloatConvertedWithDecorationOnStore)549 TEST_F(LocalAccessChainConvertTest,
550 StructOfVecsOfFloatConvertedWithDecorationOnStore) {
551 // #version 140
552 //
553 // in vec4 BaseColor;
554 //
555 // struct S_t {
556 // vec4 v0;
557 // vec4 v1;
558 // };
559 //
560 // void main()
561 // {
562 // S_t s0;
563 // s0.v1 = BaseColor;
564 // gl_FragColor = s0.v1;
565 // }
566
567 const std::string predefs_before =
568 R"(OpCapability Shader
569 %1 = OpExtInstImport "GLSL.std.450"
570 OpMemoryModel Logical GLSL450
571 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor
572 OpExecutionMode %main OriginUpperLeft
573 OpSource GLSL 140
574 OpName %main "main"
575 OpName %S_t "S_t"
576 OpMemberName %S_t 0 "v0"
577 OpMemberName %S_t 1 "v1"
578 OpName %s0 "s0"
579 OpName %BaseColor "BaseColor"
580 OpName %gl_FragColor "gl_FragColor"
581 OpDecorate %s0 RelaxedPrecision
582 %void = OpTypeVoid
583 %8 = OpTypeFunction %void
584 %float = OpTypeFloat 32
585 %v4float = OpTypeVector %float 4
586 %S_t = OpTypeStruct %v4float %v4float
587 %_ptr_Function_S_t = OpTypePointer Function %S_t
588 %int = OpTypeInt 32 1
589 %int_1 = OpConstant %int 1
590 %_ptr_Input_v4float = OpTypePointer Input %v4float
591 %BaseColor = OpVariable %_ptr_Input_v4float Input
592 %_ptr_Function_v4float = OpTypePointer Function %v4float
593 %_ptr_Output_v4float = OpTypePointer Output %v4float
594 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
595 )";
596
597 const std::string before =
598 R"(
599 ; CHECK: OpDecorate
600 ; CHECK: OpDecorate [[ld1:%\w+]] RelaxedPrecision
601 ; CHECK: OpDecorate [[ins:%\w+]] RelaxedPrecision
602 ; CHECK-NOT: OpDecorate
603 ; CHECK: [[st_id:%\w+]] = OpLoad %v4float %BaseColor
604 ; CHECK: [[ld1]] = OpLoad %S_t %s0
605 ; CHECK: [[ins]] = OpCompositeInsert %S_t [[st_id]] [[ld1]] 1
606 ; CHECK: OpStore %s0 [[ins]]
607 ; CHECK: [[ld2:%\w+]] = OpLoad %S_t %s0
608 ; CHECK: [[ex2:%\w+]] = OpCompositeExtract %v4float [[ld2]] 1
609 ; CHECK: OpStore %gl_FragColor [[ex2]]
610 %main = OpFunction %void None %8
611 %17 = OpLabel
612 %s0 = OpVariable %_ptr_Function_S_t Function
613 %18 = OpLoad %v4float %BaseColor
614 %19 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
615 OpStore %19 %18
616 %20 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
617 %21 = OpLoad %v4float %20
618 OpStore %gl_FragColor %21
619 OpReturn
620 OpFunctionEnd
621 )";
622
623 SinglePassRunAndMatch<LocalAccessChainConvertPass>(predefs_before + before,
624 true);
625 }
626
TEST_F(LocalAccessChainConvertTest,DynamicallyIndexedVarNotConverted)627 TEST_F(LocalAccessChainConvertTest, DynamicallyIndexedVarNotConverted) {
628 // #version 140
629 //
630 // in vec4 BaseColor;
631 // flat in int Idx;
632 // in float Bi;
633 //
634 // struct S_t {
635 // vec4 v0;
636 // vec4 v1;
637 // };
638 //
639 // void main()
640 // {
641 // S_t s0;
642 // s0.v1 = BaseColor;
643 // s0.v1[Idx] = Bi;
644 // gl_FragColor = s0.v1;
645 // }
646
647 const std::string assembly =
648 R"(OpCapability Shader
649 %1 = OpExtInstImport "GLSL.std.450"
650 OpMemoryModel Logical GLSL450
651 OpEntryPoint Fragment %main "main" %BaseColor %Idx %Bi %gl_FragColor
652 OpExecutionMode %main OriginUpperLeft
653 OpSource GLSL 140
654 OpName %main "main"
655 OpName %S_t "S_t"
656 OpMemberName %S_t 0 "v0"
657 OpMemberName %S_t 1 "v1"
658 OpName %s0 "s0"
659 OpName %BaseColor "BaseColor"
660 OpName %Idx "Idx"
661 OpName %Bi "Bi"
662 OpName %gl_FragColor "gl_FragColor"
663 OpDecorate %Idx Flat
664 %void = OpTypeVoid
665 %10 = OpTypeFunction %void
666 %float = OpTypeFloat 32
667 %v4float = OpTypeVector %float 4
668 %S_t = OpTypeStruct %v4float %v4float
669 %_ptr_Function_S_t = OpTypePointer Function %S_t
670 %int = OpTypeInt 32 1
671 %int_1 = OpConstant %int 1
672 %_ptr_Input_v4float = OpTypePointer Input %v4float
673 %BaseColor = OpVariable %_ptr_Input_v4float Input
674 %_ptr_Function_v4float = OpTypePointer Function %v4float
675 %_ptr_Input_int = OpTypePointer Input %int
676 %Idx = OpVariable %_ptr_Input_int Input
677 %_ptr_Input_float = OpTypePointer Input %float
678 %Bi = OpVariable %_ptr_Input_float Input
679 %_ptr_Function_float = OpTypePointer Function %float
680 %_ptr_Output_v4float = OpTypePointer Output %v4float
681 %gl_FragColor = OpVariable %_ptr_Output_v4float Output
682 %main = OpFunction %void None %10
683 %22 = OpLabel
684 %s0 = OpVariable %_ptr_Function_S_t Function
685 %23 = OpLoad %v4float %BaseColor
686 %24 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
687 OpStore %24 %23
688 %25 = OpLoad %int %Idx
689 %26 = OpLoad %float %Bi
690 %27 = OpAccessChain %_ptr_Function_float %s0 %int_1 %25
691 OpStore %27 %26
692 %28 = OpAccessChain %_ptr_Function_v4float %s0 %int_1
693 %29 = OpLoad %v4float %28
694 OpStore %gl_FragColor %29
695 OpReturn
696 OpFunctionEnd
697 )";
698
699 SinglePassRunAndCheck<LocalAccessChainConvertPass>(assembly, assembly, false,
700 true);
701 }
702
TEST_F(LocalAccessChainConvertTest,VariablePointersStorageBuffer)703 TEST_F(LocalAccessChainConvertTest, VariablePointersStorageBuffer) {
704 // A case with a storage buffer variable pointer. We should still convert
705 // the access chain on the function scope symbol.
706 const std::string test =
707 R"(
708 ; CHECK: OpFunction
709 ; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Function
710 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[var]]
711 ; CHECK: OpCompositeExtract {{%\w+}} [[ld]] 0 0
712 OpCapability Shader
713 OpCapability VariablePointersStorageBuffer
714 %1 = OpExtInstImport "GLSL.std.450"
715 OpMemoryModel Logical GLSL450
716 OpEntryPoint GLCompute %2 "main"
717 OpExecutionMode %2 LocalSize 1 1 1
718 OpSource GLSL 450
719 OpMemberDecorate %_struct_3 0 Offset 0
720 OpDecorate %_struct_3 Block
721 OpDecorate %4 DescriptorSet 0
722 OpDecorate %4 Binding 0
723 OpDecorate %_ptr_StorageBuffer_int ArrayStride 4
724 OpDecorate %_arr_int_int_128 ArrayStride 4
725 %void = OpTypeVoid
726 %8 = OpTypeFunction %void
727 %int = OpTypeInt 32 1
728 %int_128 = OpConstant %int 128
729 %_arr_int_int_128 = OpTypeArray %int %int_128
730 %_struct_3 = OpTypeStruct %_arr_int_int_128
731 %_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
732 %_ptr_Function__struct_3 = OpTypePointer Function %_struct_3
733 %4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer
734 %bool = OpTypeBool
735 %true = OpConstantTrue %bool
736 %int_0 = OpConstant %int 0
737 %int_1 = OpConstant %int 1
738 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
739 %_ptr_Function_int = OpTypePointer Function %int
740 %2 = OpFunction %void None %8
741 %18 = OpLabel
742 %19 = OpVariable %_ptr_Function__struct_3 Function
743 %20 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0
744 OpBranch %21
745 %21 = OpLabel
746 %22 = OpPhi %_ptr_StorageBuffer_int %20 %18 %23 %24
747 OpLoopMerge %25 %24 None
748 OpBranchConditional %true %26 %25
749 %26 = OpLabel
750 OpStore %22 %int_0
751 OpBranch %24
752 %24 = OpLabel
753 %23 = OpPtrAccessChain %_ptr_StorageBuffer_int %22 %int_1
754 OpBranch %21
755 %25 = OpLabel
756 %27 = OpAccessChain %_ptr_Function_int %19 %int_0 %int_0
757 %28 = OpLoad %int %27
758 OpReturn
759 OpFunctionEnd
760 )";
761
762 SinglePassRunAndMatch<LocalAccessChainConvertPass>(test, true);
763 }
764
TEST_F(LocalAccessChainConvertTest,VariablePointers)765 TEST_F(LocalAccessChainConvertTest, VariablePointers) {
766 // A case with variable pointer capability. We should not convert
767 // the access chain on the function scope symbol because the variable pointer
768 // could the analysis to miss references to function scope symbols.
769 const std::string test =
770 R"(OpCapability Shader
771 OpCapability VariablePointers
772 %1 = OpExtInstImport "GLSL.std.450"
773 OpMemoryModel Logical GLSL450
774 OpEntryPoint GLCompute %2 "main"
775 OpExecutionMode %2 LocalSize 1 1 1
776 OpSource GLSL 450
777 OpMemberDecorate %_struct_3 0 Offset 0
778 OpDecorate %_struct_3 Block
779 OpDecorate %4 DescriptorSet 0
780 OpDecorate %4 Binding 0
781 OpDecorate %_ptr_StorageBuffer_int ArrayStride 4
782 OpDecorate %_arr_int_int_128 ArrayStride 4
783 %void = OpTypeVoid
784 %8 = OpTypeFunction %void
785 %int = OpTypeInt 32 1
786 %int_128 = OpConstant %int 128
787 %_arr_int_int_128 = OpTypeArray %int %int_128
788 %_struct_3 = OpTypeStruct %_arr_int_int_128
789 %_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
790 %_ptr_Function__struct_3 = OpTypePointer Function %_struct_3
791 %4 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer
792 %bool = OpTypeBool
793 %true = OpConstantTrue %bool
794 %int_0 = OpConstant %int 0
795 %int_1 = OpConstant %int 1
796 %_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int
797 %_ptr_Function_int = OpTypePointer Function %int
798 %2 = OpFunction %void None %8
799 %18 = OpLabel
800 %19 = OpVariable %_ptr_Function__struct_3 Function
801 %20 = OpAccessChain %_ptr_StorageBuffer_int %4 %int_0 %int_0
802 OpBranch %21
803 %21 = OpLabel
804 %22 = OpPhi %_ptr_StorageBuffer_int %20 %18 %23 %24
805 OpLoopMerge %25 %24 None
806 OpBranchConditional %true %26 %25
807 %26 = OpLabel
808 OpStore %22 %int_0
809 OpBranch %24
810 %24 = OpLabel
811 %23 = OpPtrAccessChain %_ptr_StorageBuffer_int %22 %int_1
812 OpBranch %21
813 %25 = OpLabel
814 %27 = OpAccessChain %_ptr_Function_int %19 %int_0 %int_0
815 %28 = OpLoad %int %27
816 OpReturn
817 OpFunctionEnd
818 )";
819
820 SinglePassRunAndCheck<LocalAccessChainConvertPass>(test, test, false, true);
821 }
822
TEST_F(LocalAccessChainConvertTest,IdOverflowReplacingLoad)823 TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingLoad) {
824 const std::string text =
825 R"(
826 OpCapability Shader
827 OpMemoryModel Logical GLSL450
828 OpEntryPoint Fragment %4 "PSMain"
829 OpExecutionMode %4 OriginUpperLeft
830 OpDecorate %10 Location 47360
831 %void = OpTypeVoid
832 %3 = OpTypeFunction %void
833 %float = OpTypeFloat 32
834 %v4float = OpTypeVector %float 4
835 %_struct_8 = OpTypeStruct %v4float
836 %_ptr_Function__struct_8 = OpTypePointer Function %_struct_8
837 %int = OpTypeInt 32 1
838 %int_0 = OpConstant %int 0
839 %_ptr_Function_v4float = OpTypePointer Function %v4float
840 %4 = OpFunction %void None %3
841 %5 = OpLabel
842 %10 = OpVariable %_ptr_Function__struct_8 Function
843 %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0
844 %4194302 = OpLoad %v4float %4194301
845 OpReturn
846 OpFunctionEnd
847 )";
848
849 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
850
851 std::vector<Message> messages = {
852 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
853 SetMessageConsumer(GetTestMessageConsumer(messages));
854 auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
855 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
856 }
857
TEST_F(LocalAccessChainConvertTest,IdOverflowReplacingStore1)858 TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore1) {
859 const std::string text =
860 R"(
861 OpCapability Shader
862 OpMemoryModel Logical GLSL450
863 OpEntryPoint Fragment %4 "PSMain"
864 OpExecutionMode %4 OriginUpperLeft
865 OpDecorate %10 Location 47360
866 %void = OpTypeVoid
867 %3 = OpTypeFunction %void
868 %float = OpTypeFloat 32
869 %v4float = OpTypeVector %float 4
870 %_struct_7 = OpTypeStruct %v4float
871 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
872 %int = OpTypeInt 32 1
873 %int_0 = OpConstant %int 0
874 %_ptr_Function_v4float = OpTypePointer Function %v4float
875 %13 = OpConstantNull %v4float
876 %4 = OpFunction %void None %3
877 %5 = OpLabel
878 %10 = OpVariable %_ptr_Function__struct_7 Function
879 %4194302 = OpAccessChain %_ptr_Function_v4float %10 %int_0
880 OpStore %4194302 %13
881 OpReturn
882 OpFunctionEnd
883 )";
884
885 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
886
887 std::vector<Message> messages = {
888 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
889 SetMessageConsumer(GetTestMessageConsumer(messages));
890 auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
891 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
892 }
893
TEST_F(LocalAccessChainConvertTest,IdOverflowReplacingStore2)894 TEST_F(LocalAccessChainConvertTest, IdOverflowReplacingStore2) {
895 const std::string text =
896 R"(
897 OpCapability Shader
898 OpMemoryModel Logical GLSL450
899 OpEntryPoint Fragment %4 "PSMain"
900 OpExecutionMode %4 OriginUpperLeft
901 OpDecorate %10 Location 47360
902 %void = OpTypeVoid
903 %3 = OpTypeFunction %void
904 %float = OpTypeFloat 32
905 %v4float = OpTypeVector %float 4
906 %_struct_7 = OpTypeStruct %v4float
907 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
908 %int = OpTypeInt 32 1
909 %int_0 = OpConstant %int 0
910 %_ptr_Function_v4float = OpTypePointer Function %v4float
911 %13 = OpConstantNull %v4float
912 %4 = OpFunction %void None %3
913 %5 = OpLabel
914 %10 = OpVariable %_ptr_Function__struct_7 Function
915 %4194301 = OpAccessChain %_ptr_Function_v4float %10 %int_0
916 OpStore %4194301 %13
917 OpReturn
918 OpFunctionEnd
919 )";
920
921 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
922
923 std::vector<Message> messages = {
924 {SPV_MSG_ERROR, "", 0, 0, "ID overflow. Try running compact-ids."}};
925 SetMessageConsumer(GetTestMessageConsumer(messages));
926 auto result = SinglePassRunToBinary<LocalAccessChainConvertPass>(text, true);
927 EXPECT_EQ(Pass::Status::Failure, std::get<1>(result));
928 }
929
930 // TODO(greg-lunarg): Add tests to verify handling of these cases:
931 //
932 // Assorted vector and matrix types
933 // Assorted struct array types
934 // Assorted scalar types
935 // Assorted non-target types
936 // OpInBoundsAccessChain
937 // Others?
938
939 } // namespace
940 } // namespace opt
941 } // namespace spvtools
942