• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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