1 // Copyright (c) 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <iostream>
16 #include <string>
17 
18 #include "gmock/gmock.h"
19 #include "test/opt/assembly_builder.h"
20 #include "test/opt/pass_fixture.h"
21 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 using CopyPropArrayPassTest = PassTest<::testing::Test>;
27 
TEST_F(CopyPropArrayPassTest,BasicPropagateArray)28 TEST_F(CopyPropArrayPassTest, BasicPropagateArray) {
29   const std::string before =
30       R"(
31 OpCapability Shader
32 OpMemoryModel Logical GLSL450
33 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
34 OpExecutionMode %main OriginUpperLeft
35 OpSource HLSL 600
36 OpName %type_MyCBuffer "type.MyCBuffer"
37 OpMemberName %type_MyCBuffer 0 "Data"
38 OpName %MyCBuffer "MyCBuffer"
39 OpName %main "main"
40 OpName %in_var_INDEX "in.var.INDEX"
41 OpName %out_var_SV_Target "out.var.SV_Target"
42 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
43 OpMemberDecorate %type_MyCBuffer 0 Offset 0
44 OpDecorate %type_MyCBuffer Block
45 OpDecorate %in_var_INDEX Flat
46 OpDecorate %in_var_INDEX Location 0
47 OpDecorate %out_var_SV_Target Location 0
48 OpDecorate %MyCBuffer DescriptorSet 0
49 OpDecorate %MyCBuffer Binding 0
50 %float = OpTypeFloat 32
51 %v4float = OpTypeVector %float 4
52 %uint = OpTypeInt 32 0
53 %uint_8 = OpConstant %uint 8
54 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
55 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
56 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
57 %void = OpTypeVoid
58 %13 = OpTypeFunction %void
59 %int = OpTypeInt 32 1
60 %_ptr_Input_int = OpTypePointer Input %int
61 %_ptr_Output_v4float = OpTypePointer Output %v4float
62 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
63 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
64 %int_0 = OpConstant %int 0
65 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
66 %_ptr_Function_v4float = OpTypePointer Function %v4float
67 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
68 %in_var_INDEX = OpVariable %_ptr_Input_int Input
69 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
70 ; CHECK: OpFunction
71 ; CHECK: OpLabel
72 ; CHECK: OpVariable
73 ; CHECK: OpAccessChain
74 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
75 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
76 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
77 ; CHECK: OpStore %out_var_SV_Target [[load]]
78 %main = OpFunction %void None %13
79 %22 = OpLabel
80 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
81 %24 = OpLoad %int %in_var_INDEX
82 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
83 %26 = OpLoad %_arr_v4float_uint_8 %25
84 %27 = OpCompositeExtract %v4float %26 0
85 %28 = OpCompositeExtract %v4float %26 1
86 %29 = OpCompositeExtract %v4float %26 2
87 %30 = OpCompositeExtract %v4float %26 3
88 %31 = OpCompositeExtract %v4float %26 4
89 %32 = OpCompositeExtract %v4float %26 5
90 %33 = OpCompositeExtract %v4float %26 6
91 %34 = OpCompositeExtract %v4float %26 7
92 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
93 OpStore %23 %35
94 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
95 %37 = OpLoad %v4float %36
96 OpStore %out_var_SV_Target %37
97 OpReturn
98 OpFunctionEnd
99 )";
100 
101   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
102   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
103                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
104   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
105 }
106 
TEST_F(CopyPropArrayPassTest,BasicPropagateArrayWithName)107 TEST_F(CopyPropArrayPassTest, BasicPropagateArrayWithName) {
108   const std::string before =
109       R"(
110 OpCapability Shader
111 OpMemoryModel Logical GLSL450
112 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
113 OpExecutionMode %main OriginUpperLeft
114 OpSource HLSL 600
115 OpName %type_MyCBuffer "type.MyCBuffer"
116 OpMemberName %type_MyCBuffer 0 "Data"
117 OpName %MyCBuffer "MyCBuffer"
118 OpName %main "main"
119 OpName %local "local"
120 OpName %in_var_INDEX "in.var.INDEX"
121 OpName %out_var_SV_Target "out.var.SV_Target"
122 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
123 OpMemberDecorate %type_MyCBuffer 0 Offset 0
124 OpDecorate %type_MyCBuffer Block
125 OpDecorate %in_var_INDEX Flat
126 OpDecorate %in_var_INDEX Location 0
127 OpDecorate %out_var_SV_Target Location 0
128 OpDecorate %MyCBuffer DescriptorSet 0
129 OpDecorate %MyCBuffer Binding 0
130 %float = OpTypeFloat 32
131 %v4float = OpTypeVector %float 4
132 %uint = OpTypeInt 32 0
133 %uint_8 = OpConstant %uint 8
134 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
135 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
136 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
137 %void = OpTypeVoid
138 %13 = OpTypeFunction %void
139 %int = OpTypeInt 32 1
140 %_ptr_Input_int = OpTypePointer Input %int
141 %_ptr_Output_v4float = OpTypePointer Output %v4float
142 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
143 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
144 %int_0 = OpConstant %int 0
145 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
146 %_ptr_Function_v4float = OpTypePointer Function %v4float
147 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
148 %in_var_INDEX = OpVariable %_ptr_Input_int Input
149 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
150 ; CHECK: OpFunction
151 ; CHECK: OpLabel
152 ; CHECK: OpVariable
153 ; CHECK: OpAccessChain
154 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
155 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
156 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
157 ; CHECK: OpStore %out_var_SV_Target [[load]]
158 %main = OpFunction %void None %13
159 %22 = OpLabel
160 %local = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
161 %24 = OpLoad %int %in_var_INDEX
162 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
163 %26 = OpLoad %_arr_v4float_uint_8 %25
164 %27 = OpCompositeExtract %v4float %26 0
165 %28 = OpCompositeExtract %v4float %26 1
166 %29 = OpCompositeExtract %v4float %26 2
167 %30 = OpCompositeExtract %v4float %26 3
168 %31 = OpCompositeExtract %v4float %26 4
169 %32 = OpCompositeExtract %v4float %26 5
170 %33 = OpCompositeExtract %v4float %26 6
171 %34 = OpCompositeExtract %v4float %26 7
172 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
173 OpStore %local %35
174 %36 = OpAccessChain %_ptr_Function_v4float %local %24
175 %37 = OpLoad %v4float %36
176 OpStore %out_var_SV_Target %37
177 OpReturn
178 OpFunctionEnd
179 )";
180 
181   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
182   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
183                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
184   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
185 }
186 
187 // Propagate 2d array.  This test identifying a copy through multiple levels.
188 // Also has to traverse multiple OpAccessChains.
TEST_F(CopyPropArrayPassTest,Propagate2DArray)189 TEST_F(CopyPropArrayPassTest, Propagate2DArray) {
190   const std::string text =
191       R"(OpCapability Shader
192 OpMemoryModel Logical GLSL450
193 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
194 OpExecutionMode %main OriginUpperLeft
195 OpSource HLSL 600
196 OpName %type_MyCBuffer "type.MyCBuffer"
197 OpMemberName %type_MyCBuffer 0 "Data"
198 OpName %MyCBuffer "MyCBuffer"
199 OpName %main "main"
200 OpName %in_var_INDEX "in.var.INDEX"
201 OpName %out_var_SV_Target "out.var.SV_Target"
202 OpDecorate %_arr_v4float_uint_2 ArrayStride 16
203 OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
204 OpMemberDecorate %type_MyCBuffer 0 Offset 0
205 OpDecorate %type_MyCBuffer Block
206 OpDecorate %in_var_INDEX Flat
207 OpDecorate %in_var_INDEX Location 0
208 OpDecorate %out_var_SV_Target Location 0
209 OpDecorate %MyCBuffer DescriptorSet 0
210 OpDecorate %MyCBuffer Binding 0
211 %float = OpTypeFloat 32
212 %v4float = OpTypeVector %float 4
213 %uint = OpTypeInt 32 0
214 %uint_2 = OpConstant %uint 2
215 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
216 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
217 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
218 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
219 %void = OpTypeVoid
220 %14 = OpTypeFunction %void
221 %int = OpTypeInt 32 1
222 %_ptr_Input_int = OpTypePointer Input %int
223 %_ptr_Output_v4float = OpTypePointer Output %v4float
224 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
225 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
226 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
227 %int_0 = OpConstant %int 0
228 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
229 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
230 %_ptr_Function_v4float = OpTypePointer Function %v4float
231 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
232 %in_var_INDEX = OpVariable %_ptr_Input_int Input
233 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
234 ; CHECK: OpFunction
235 ; CHECK: OpLabel
236 ; CHECK: OpVariable
237 ; CHECK: OpVariable
238 ; CHECK: OpAccessChain
239 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
240 %main = OpFunction %void None %14
241 %25 = OpLabel
242 %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
243 %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
244 %28 = OpLoad %int %in_var_INDEX
245 %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
246 %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
247 %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
248 %32 = OpCompositeExtract %v4float %31 0
249 %33 = OpCompositeExtract %v4float %31 1
250 %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
251 %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
252 %36 = OpCompositeExtract %v4float %35 0
253 %37 = OpCompositeExtract %v4float %35 1
254 %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
255 %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
256 ; CHECK: OpStore
257 OpStore %27 %39
258 %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
259 %42 = OpAccessChain %_ptr_Function_v4float %40 %28
260 %43 = OpLoad %v4float %42
261 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
262 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
263 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
264 ; CHECK: OpStore %out_var_SV_Target [[load]]
265 OpStore %out_var_SV_Target %43
266 OpReturn
267 OpFunctionEnd
268 )";
269 
270   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
271   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
272                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
273   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
274 }
275 
276 // Propagate 2d array.  This test identifying a copy through multiple levels.
277 // Also has to traverse multiple OpAccessChains.
TEST_F(CopyPropArrayPassTest,Propagate2DArrayWithMultiLevelExtract)278 TEST_F(CopyPropArrayPassTest, Propagate2DArrayWithMultiLevelExtract) {
279   const std::string text =
280       R"(OpCapability Shader
281 OpMemoryModel Logical GLSL450
282 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
283 OpExecutionMode %main OriginUpperLeft
284 OpSource HLSL 600
285 OpName %type_MyCBuffer "type.MyCBuffer"
286 OpMemberName %type_MyCBuffer 0 "Data"
287 OpName %MyCBuffer "MyCBuffer"
288 OpName %main "main"
289 OpName %in_var_INDEX "in.var.INDEX"
290 OpName %out_var_SV_Target "out.var.SV_Target"
291 OpDecorate %_arr_v4float_uint_2 ArrayStride 16
292 OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
293 OpMemberDecorate %type_MyCBuffer 0 Offset 0
294 OpDecorate %type_MyCBuffer Block
295 OpDecorate %in_var_INDEX Flat
296 OpDecorate %in_var_INDEX Location 0
297 OpDecorate %out_var_SV_Target Location 0
298 OpDecorate %MyCBuffer DescriptorSet 0
299 OpDecorate %MyCBuffer Binding 0
300 %float = OpTypeFloat 32
301 %v4float = OpTypeVector %float 4
302 %uint = OpTypeInt 32 0
303 %uint_2 = OpConstant %uint 2
304 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
305 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
306 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
307 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
308 %void = OpTypeVoid
309 %14 = OpTypeFunction %void
310 %int = OpTypeInt 32 1
311 %_ptr_Input_int = OpTypePointer Input %int
312 %_ptr_Output_v4float = OpTypePointer Output %v4float
313 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
314 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
315 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
316 %int_0 = OpConstant %int 0
317 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
318 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
319 %_ptr_Function_v4float = OpTypePointer Function %v4float
320 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
321 %in_var_INDEX = OpVariable %_ptr_Input_int Input
322 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
323 ; CHECK: OpFunction
324 ; CHECK: OpLabel
325 ; CHECK: OpVariable
326 ; CHECK: OpVariable
327 ; CHECK: OpAccessChain
328 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
329 %main = OpFunction %void None %14
330 %25 = OpLabel
331 %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
332 %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
333 %28 = OpLoad %int %in_var_INDEX
334 %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
335 %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
336 %32 = OpCompositeExtract %v4float %30 0 0
337 %33 = OpCompositeExtract %v4float %30 0 1
338 %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
339 %36 = OpCompositeExtract %v4float %30 1 0
340 %37 = OpCompositeExtract %v4float %30 1 1
341 %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
342 %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
343 ; CHECK: OpStore
344 OpStore %27 %39
345 %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
346 %42 = OpAccessChain %_ptr_Function_v4float %40 %28
347 %43 = OpLoad %v4float %42
348 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
349 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
350 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
351 ; CHECK: OpStore %out_var_SV_Target [[load]]
352 OpStore %out_var_SV_Target %43
353 OpReturn
354 OpFunctionEnd
355 )";
356 
357   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
358   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
359                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
360   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
361 }
362 
363 // Test decomposing an object when we need to "rewrite" a store.
TEST_F(CopyPropArrayPassTest,DecomposeObjectForArrayStore)364 TEST_F(CopyPropArrayPassTest, DecomposeObjectForArrayStore) {
365   const std::string text =
366       R"(               OpCapability Shader
367                OpMemoryModel Logical GLSL450
368                OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
369                OpExecutionMode %main OriginUpperLeft
370                OpSource HLSL 600
371                OpName %type_MyCBuffer "type.MyCBuffer"
372                OpMemberName %type_MyCBuffer 0 "Data"
373                OpName %MyCBuffer "MyCBuffer"
374                OpName %main "main"
375                OpName %in_var_INDEX "in.var.INDEX"
376                OpName %out_var_SV_Target "out.var.SV_Target"
377                OpDecorate %_arr_v4float_uint_2 ArrayStride 16
378                OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
379                OpMemberDecorate %type_MyCBuffer 0 Offset 0
380                OpDecorate %type_MyCBuffer Block
381                OpDecorate %in_var_INDEX Flat
382                OpDecorate %in_var_INDEX Location 0
383                OpDecorate %out_var_SV_Target Location 0
384                OpDecorate %MyCBuffer DescriptorSet 0
385                OpDecorate %MyCBuffer Binding 0
386       %float = OpTypeFloat 32
387     %v4float = OpTypeVector %float 4
388        %uint = OpTypeInt 32 0
389      %uint_2 = OpConstant %uint 2
390 %_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
391 %_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
392 %type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
393 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
394        %void = OpTypeVoid
395          %14 = OpTypeFunction %void
396         %int = OpTypeInt 32 1
397 %_ptr_Input_int = OpTypePointer Input %int
398 %_ptr_Output_v4float = OpTypePointer Output %v4float
399 %_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
400 %_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
401 %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
402       %int_0 = OpConstant %int 0
403 %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
404 %_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
405 %_ptr_Function_v4float = OpTypePointer Function %v4float
406   %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
407 %in_var_INDEX = OpVariable %_ptr_Input_int Input
408 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
409        %main = OpFunction %void None %14
410          %25 = OpLabel
411          %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
412          %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
413          %28 = OpLoad %int %in_var_INDEX
414          %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
415          %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
416          %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
417          %32 = OpCompositeExtract %v4float %31 0
418          %33 = OpCompositeExtract %v4float %31 1
419          %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
420          %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
421          %36 = OpCompositeExtract %v4float %35 0
422          %37 = OpCompositeExtract %v4float %35 1
423          %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
424          %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
425                OpStore %27 %39
426 ; CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2
427          %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
428 ; CHECK: [[load:%\w+]] = OpLoad %_arr_v4float_uint_2 [[access_chain]]
429          %41 = OpLoad %_arr_v4float_uint_2_0 %40
430 ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %v4float [[load]] 0
431 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %v4float [[load]] 1
432 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct %_arr_v4float_uint_2_0 [[extract1]] [[extract2]]
433 ; CHECK: OpStore %26 [[construct]]
434                OpStore %26 %41
435          %42 = OpAccessChain %_ptr_Function_v4float %26 %28
436          %43 = OpLoad %v4float %42
437                OpStore %out_var_SV_Target %43
438                OpReturn
439                OpFunctionEnd
440 )";
441 
442   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
443   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
444                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
445   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
446 }
447 
448 // Test decomposing an object when we need to "rewrite" a store.
TEST_F(CopyPropArrayPassTest,DecomposeObjectForStructStore)449 TEST_F(CopyPropArrayPassTest, DecomposeObjectForStructStore) {
450   const std::string text =
451       R"(               OpCapability Shader
452                OpMemoryModel Logical GLSL450
453                OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
454                OpExecutionMode %main OriginUpperLeft
455                OpSource HLSL 600
456                OpName %type_MyCBuffer "type.MyCBuffer"
457                OpMemberName %type_MyCBuffer 0 "Data"
458                OpName %MyCBuffer "MyCBuffer"
459                OpName %main "main"
460                OpName %in_var_INDEX "in.var.INDEX"
461                OpName %out_var_SV_Target "out.var.SV_Target"
462                OpMemberDecorate %type_MyCBuffer 0 Offset 0
463                OpDecorate %type_MyCBuffer Block
464                OpDecorate %in_var_INDEX Flat
465                OpDecorate %in_var_INDEX Location 0
466                OpDecorate %out_var_SV_Target Location 0
467                OpDecorate %MyCBuffer DescriptorSet 0
468                OpDecorate %MyCBuffer Binding 0
469 ; CHECK: OpDecorate [[decorated_type:%\w+]] GLSLPacked
470                OpDecorate %struct GLSLPacked
471       %float = OpTypeFloat 32
472     %v4float = OpTypeVector %float 4
473        %uint = OpTypeInt 32 0
474      %uint_2 = OpConstant %uint 2
475 ; CHECK: [[decorated_type]] = OpTypeStruct
476 %struct = OpTypeStruct %float %uint
477 %_arr_struct_uint_2 = OpTypeArray %struct %uint_2
478 %type_MyCBuffer = OpTypeStruct %_arr_struct_uint_2
479 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
480        %void = OpTypeVoid
481          %14 = OpTypeFunction %void
482         %int = OpTypeInt 32 1
483 %_ptr_Input_int = OpTypePointer Input %int
484 %_ptr_Output_v4float = OpTypePointer Output %v4float
485 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float %uint
486 %struct_0 = OpTypeStruct %float %uint
487 %_arr_struct_0_uint_2 = OpTypeArray %struct_0 %uint_2
488 %_ptr_Function__arr_struct_0_uint_2 = OpTypePointer Function %_arr_struct_0_uint_2
489       %int_0 = OpConstant %int 0
490 %_ptr_Uniform__arr_struct_uint_2 = OpTypePointer Uniform %_arr_struct_uint_2
491 ; CHECK: [[decorated_ptr:%\w+]] = OpTypePointer Uniform [[decorated_type]]
492 %_ptr_Function_struct_0 = OpTypePointer Function %struct_0
493 %_ptr_Function_v4float = OpTypePointer Function %v4float
494   %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
495 %in_var_INDEX = OpVariable %_ptr_Input_int Input
496 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
497        %main = OpFunction %void None %14
498          %25 = OpLabel
499          %26 = OpVariable %_ptr_Function_struct_0 Function
500          %27 = OpVariable %_ptr_Function__arr_struct_0_uint_2 Function
501          %28 = OpLoad %int %in_var_INDEX
502          %29 = OpAccessChain %_ptr_Uniform__arr_struct_uint_2 %MyCBuffer %int_0
503          %30 = OpLoad %_arr_struct_uint_2 %29
504          %31 = OpCompositeExtract %struct %30 0
505          %32 = OpCompositeExtract %v4float %31 0
506          %33 = OpCompositeExtract %v4float %31 1
507          %34 = OpCompositeConstruct %struct_0 %32 %33
508          %35 = OpCompositeExtract %struct %30 1
509          %36 = OpCompositeExtract %float %35 0
510          %37 = OpCompositeExtract %uint %35 1
511          %38 = OpCompositeConstruct %struct_0 %36 %37
512          %39 = OpCompositeConstruct %_arr_struct_0_uint_2 %34 %38
513                OpStore %27 %39
514 ; CHECK: [[access_chain:%\w+]] = OpAccessChain [[decorated_ptr]]
515          %40 = OpAccessChain %_ptr_Function_struct_0 %27 %28
516 ; CHECK: [[load:%\w+]] = OpLoad [[decorated_type]] [[access_chain]]
517          %41 = OpLoad %struct_0 %40
518 ; CHECK: [[extract1:%\w+]] = OpCompositeExtract %float [[load]] 0
519 ; CHECK: [[extract2:%\w+]] = OpCompositeExtract %uint [[load]] 1
520 ; CHECK: [[construct:%\w+]] = OpCompositeConstruct [[struct]] [[extract1]] [[extract2]]
521 ; CHECK: OpStore %26 [[construct]]
522                OpStore %26 %41
523          %42 = OpAccessChain %_ptr_Function_v4float %26 %28
524          %43 = OpLoad %v4float %42
525                OpStore %out_var_SV_Target %43
526                OpReturn
527                OpFunctionEnd
528 )";
529 
530   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
531   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
532                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
533   SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
534 }
535 
TEST_F(CopyPropArrayPassTest,CopyViaInserts)536 TEST_F(CopyPropArrayPassTest, CopyViaInserts) {
537   const std::string before =
538       R"(
539 OpCapability Shader
540 OpMemoryModel Logical GLSL450
541 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
542 OpExecutionMode %main OriginUpperLeft
543 OpSource HLSL 600
544 OpName %type_MyCBuffer "type.MyCBuffer"
545 OpMemberName %type_MyCBuffer 0 "Data"
546 OpName %MyCBuffer "MyCBuffer"
547 OpName %main "main"
548 OpName %in_var_INDEX "in.var.INDEX"
549 OpName %out_var_SV_Target "out.var.SV_Target"
550 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
551 OpMemberDecorate %type_MyCBuffer 0 Offset 0
552 OpDecorate %type_MyCBuffer Block
553 OpDecorate %in_var_INDEX Flat
554 OpDecorate %in_var_INDEX Location 0
555 OpDecorate %out_var_SV_Target Location 0
556 OpDecorate %MyCBuffer DescriptorSet 0
557 OpDecorate %MyCBuffer Binding 0
558 %float = OpTypeFloat 32
559 %v4float = OpTypeVector %float 4
560 %uint = OpTypeInt 32 0
561 %uint_8 = OpConstant %uint 8
562 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
563 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
564 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
565 %void = OpTypeVoid
566 %13 = OpTypeFunction %void
567 %int = OpTypeInt 32 1
568 %_ptr_Input_int = OpTypePointer Input %int
569 %_ptr_Output_v4float = OpTypePointer Output %v4float
570 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
571 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
572 %int_0 = OpConstant %int 0
573 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
574 %_ptr_Function_v4float = OpTypePointer Function %v4float
575 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
576 %in_var_INDEX = OpVariable %_ptr_Input_int Input
577 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
578 ; CHECK: OpFunction
579 ; CHECK: OpLabel
580 ; CHECK: OpVariable
581 ; CHECK: OpAccessChain
582 ; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
583 ; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
584 ; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
585 ; CHECK: OpStore %out_var_SV_Target [[load]]
586 %main = OpFunction %void None %13
587 %22 = OpLabel
588 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
589 %undef = OpUndef %_arr_v4float_uint_8_0
590 %24 = OpLoad %int %in_var_INDEX
591 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
592 %26 = OpLoad %_arr_v4float_uint_8 %25
593 %27 = OpCompositeExtract %v4float %26 0
594 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
595 %28 = OpCompositeExtract %v4float %26 1
596 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
597 %29 = OpCompositeExtract %v4float %26 2
598 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
599 %30 = OpCompositeExtract %v4float %26 3
600 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
601 %31 = OpCompositeExtract %v4float %26 4
602 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
603 %32 = OpCompositeExtract %v4float %26 5
604 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
605 %33 = OpCompositeExtract %v4float %26 6
606 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
607 %34 = OpCompositeExtract %v4float %26 7
608 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
609 OpStore %23 %i7
610 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
611 %37 = OpLoad %v4float %36
612 OpStore %out_var_SV_Target %37
613 OpReturn
614 OpFunctionEnd
615 )";
616 
617   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
618   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
619                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
620   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
621 }
622 
TEST_F(CopyPropArrayPassTest,IsomorphicTypes1)623 TEST_F(CopyPropArrayPassTest, IsomorphicTypes1) {
624   const std::string before =
625       R"(
626 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
627 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
628 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
629 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
630 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
631 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
632 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
633 ; CHECK: [[p_a1:%\w+]] = OpTypePointer Uniform [[a1]]
634 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
635 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_a1]] [[global_var]] %uint_0
636 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s2]] [[ac1]] %uint_0
637 ; CHECK: [[ld:%\w+]] = OpLoad [[s2]] [[ac2]]
638 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[s1]] [[ld]]
639                OpCapability Shader
640           %1 = OpExtInstImport "GLSL.std.450"
641                OpMemoryModel Logical GLSL450
642                OpEntryPoint Fragment %2 "PS_main"
643                OpExecutionMode %2 OriginUpperLeft
644                OpSource HLSL 600
645                OpDecorate %3 DescriptorSet 0
646                OpDecorate %3 Binding 101
647        %uint = OpTypeInt 32 0
648      %uint_1 = OpConstant %uint 1
649   %s1 = OpTypeStruct %uint
650   %s2 = OpTypeStruct %s1
651 %a1 = OpTypeArray %s2 %uint_1
652   %s3 = OpTypeStruct %a1
653  %s1_1 = OpTypeStruct %uint
654 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
655        %void = OpTypeVoid
656          %13 = OpTypeFunction %void
657      %uint_0 = OpConstant %uint 0
658  %s1_0 = OpTypeStruct %uint
659  %s2_0 = OpTypeStruct %s1_0
660 %a1_0 = OpTypeArray %s2_0 %uint_1
661  %s3_0 = OpTypeStruct %a1_0
662 %p_s3 = OpTypePointer Uniform %s3
663 %p_s3_0 = OpTypePointer Function %s3_0
664           %3 = OpVariable %p_s3 Uniform
665 %p_a1_0 = OpTypePointer Function %a1_0
666 %p_s2_0 = OpTypePointer Function %s2_0
667           %2 = OpFunction %void None %13
668          %20 = OpLabel
669          %21 = OpVariable %p_a1_0 Function
670          %22 = OpLoad %s3 %3
671          %23 = OpCompositeExtract %a1 %22 0
672          %24 = OpCompositeExtract %s2 %23 0
673          %25 = OpCompositeExtract %s1 %24 0
674          %26 = OpCompositeExtract %uint %25 0
675          %27 = OpCompositeConstruct %s1_0 %26
676          %32 = OpCompositeConstruct %s2_0 %27
677          %28 = OpCompositeConstruct %a1_0 %32
678                OpStore %21 %28
679          %29 = OpAccessChain %p_s2_0 %21 %uint_0
680          %30 = OpLoad %s2 %29
681          %31 = OpCompositeExtract %s1 %30 0
682                OpReturn
683                OpFunctionEnd
684 )";
685 
686   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
687   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
688                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
689   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
690 }
691 
TEST_F(CopyPropArrayPassTest,IsomorphicTypes2)692 TEST_F(CopyPropArrayPassTest, IsomorphicTypes2) {
693   const std::string before =
694       R"(
695 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
696 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
697 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
698 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
699 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
700 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
701 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
702 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
703 ; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
704 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
705 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
706 ; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
707 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
708                OpCapability Shader
709           %1 = OpExtInstImport "GLSL.std.450"
710                OpMemoryModel Logical GLSL450
711                OpEntryPoint Fragment %2 "PS_main"
712                OpExecutionMode %2 OriginUpperLeft
713                OpSource HLSL 600
714                OpDecorate %3 DescriptorSet 0
715                OpDecorate %3 Binding 101
716        %uint = OpTypeInt 32 0
717      %uint_1 = OpConstant %uint 1
718   %_struct_6 = OpTypeStruct %uint
719   %_struct_7 = OpTypeStruct %_struct_6
720 %_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
721   %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
722  %_struct_10 = OpTypeStruct %uint
723 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
724        %void = OpTypeVoid
725          %13 = OpTypeFunction %void
726      %uint_0 = OpConstant %uint 0
727  %_struct_15 = OpTypeStruct %uint
728 %_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
729 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
730 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
731           %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
732 %_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
733           %2 = OpFunction %void None %13
734          %20 = OpLabel
735          %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
736          %22 = OpLoad %_struct_9 %3
737          %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
738          %24 = OpCompositeExtract %_struct_7 %23 0
739          %25 = OpCompositeExtract %_struct_6 %24 0
740          %26 = OpCompositeExtract %uint %25 0
741          %27 = OpCompositeConstruct %_struct_15 %26
742          %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
743                OpStore %21 %28
744          %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
745          %30 = OpLoad %_struct_15 %29
746          %31 = OpCompositeExtract %uint %30 0
747                OpReturn
748                OpFunctionEnd
749 )";
750 
751   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
752   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
753                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
754   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
755 }
756 
TEST_F(CopyPropArrayPassTest,IsomorphicTypes3)757 TEST_F(CopyPropArrayPassTest, IsomorphicTypes3) {
758   const std::string before =
759       R"(
760 ; CHECK: [[int:%\w+]] = OpTypeInt 32 0
761 ; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
762 ; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
763 ; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
764 ; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
765 ; CHECK: [[s1_1:%\w+]] = OpTypeStruct [[int]]
766 ; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
767 ; CHECK: [[p_s1_1:%\w+]] = OpTypePointer Function [[s1_1]]
768 ; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
769 ; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
770 ; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
771 ; CHECK: [[var:%\w+]] = OpVariable [[p_s1_1]] Function
772 ; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
773 ; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
774 ; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
775 ; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
776 ; CHECK: [[copy:%\w+]] = OpCompositeConstruct [[s1_1]] [[ex]]
777 ; CHECK: OpStore [[var]] [[copy]]
778                OpCapability Shader
779           %1 = OpExtInstImport "GLSL.std.450"
780                OpMemoryModel Logical GLSL450
781                OpEntryPoint Fragment %2 "PS_main"
782                OpExecutionMode %2 OriginUpperLeft
783                OpSource HLSL 600
784                OpDecorate %3 DescriptorSet 0
785                OpDecorate %3 Binding 101
786        %uint = OpTypeInt 32 0
787      %uint_1 = OpConstant %uint 1
788   %_struct_6 = OpTypeStruct %uint
789   %_struct_7 = OpTypeStruct %_struct_6
790 %_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
791   %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
792 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
793        %void = OpTypeVoid
794          %13 = OpTypeFunction %void
795      %uint_0 = OpConstant %uint 0
796  %_struct_15 = OpTypeStruct %uint
797  %_struct_10 = OpTypeStruct %uint
798 %_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
799 %_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
800 %_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
801           %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
802 %_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
803           %2 = OpFunction %void None %13
804          %20 = OpLabel
805          %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
806         %var = OpVariable %_ptr_Function__struct_15 Function
807          %22 = OpLoad %_struct_9 %3
808          %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
809          %24 = OpCompositeExtract %_struct_7 %23 0
810          %25 = OpCompositeExtract %_struct_6 %24 0
811          %26 = OpCompositeExtract %uint %25 0
812          %27 = OpCompositeConstruct %_struct_15 %26
813          %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
814                OpStore %21 %28
815          %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
816          %30 = OpLoad %_struct_15 %29
817                OpStore %var %30
818                OpReturn
819                OpFunctionEnd
820 )";
821 
822   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
823   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
824                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
825   SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
826 }
827 
TEST_F(CopyPropArrayPassTest,BadMergingTwoObjects)828 TEST_F(CopyPropArrayPassTest, BadMergingTwoObjects) {
829   // The second element in the |OpCompositeConstruct| is from a different
830   // object.
831   const std::string text =
832       R"(OpCapability Shader
833 OpMemoryModel Logical GLSL450
834 OpEntryPoint Fragment %main "main"
835 OpExecutionMode %main OriginUpperLeft
836 OpName %type_ConstBuf "type.ConstBuf"
837 OpMemberName %type_ConstBuf 0 "TexSizeU"
838 OpMemberName %type_ConstBuf 1 "TexSizeV"
839 OpName %ConstBuf "ConstBuf"
840 OpName %main "main"
841 OpMemberDecorate %type_ConstBuf 0 Offset 0
842 OpMemberDecorate %type_ConstBuf 1 Offset 8
843 OpDecorate %type_ConstBuf Block
844 OpDecorate %ConstBuf DescriptorSet 0
845 OpDecorate %ConstBuf Binding 2
846 %float = OpTypeFloat 32
847 %v2float = OpTypeVector %float 2
848 %type_ConstBuf = OpTypeStruct %v2float %v2float
849 %_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
850 %void = OpTypeVoid
851 %9 = OpTypeFunction %void
852 %uint = OpTypeInt 32 0
853 %int_0 = OpConstant %uint 0
854 %uint_2 = OpConstant %uint 2
855 %_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
856 %_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
857 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
858 %ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
859 %main = OpFunction %void None %9
860 %24 = OpLabel
861 %25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
862 %27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
863 %28 = OpLoad %v2float %27
864 %29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
865 %30 = OpLoad %v2float %29
866 %31 = OpFNegate %v2float %30
867 %37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %31
868 OpStore %25 %37
869 OpReturn
870 OpFunctionEnd
871 )";
872 
873   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
874       text, /* skip_nop = */ true, /* do_validation = */ false);
875   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
876 }
877 
TEST_F(CopyPropArrayPassTest,SecondElementNotContained)878 TEST_F(CopyPropArrayPassTest, SecondElementNotContained) {
879   // The second element in the |OpCompositeConstruct| is not a memory object.
880   // Make sure no change happends.
881   const std::string text =
882       R"(OpCapability Shader
883 OpMemoryModel Logical GLSL450
884 OpEntryPoint Fragment %main "main"
885 OpExecutionMode %main OriginUpperLeft
886 OpName %type_ConstBuf "type.ConstBuf"
887 OpMemberName %type_ConstBuf 0 "TexSizeU"
888 OpMemberName %type_ConstBuf 1 "TexSizeV"
889 OpName %ConstBuf "ConstBuf"
890 OpName %main "main"
891 OpMemberDecorate %type_ConstBuf 0 Offset 0
892 OpMemberDecorate %type_ConstBuf 1 Offset 8
893 OpDecorate %type_ConstBuf Block
894 OpDecorate %ConstBuf DescriptorSet 0
895 OpDecorate %ConstBuf Binding 2
896 OpDecorate %ConstBuf2 DescriptorSet 1
897 OpDecorate %ConstBuf2 Binding 2
898 %float = OpTypeFloat 32
899 %v2float = OpTypeVector %float 2
900 %type_ConstBuf = OpTypeStruct %v2float %v2float
901 %_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
902 %void = OpTypeVoid
903 %9 = OpTypeFunction %void
904 %uint = OpTypeInt 32 0
905 %int_0 = OpConstant %uint 0
906 %int_1 = OpConstant %uint 1
907 %uint_2 = OpConstant %uint 2
908 %_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
909 %_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
910 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
911 %ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
912 %ConstBuf2 = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
913 %main = OpFunction %void None %9
914 %24 = OpLabel
915 %25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
916 %27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
917 %28 = OpLoad %v2float %27
918 %29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf2 %int_1
919 %30 = OpLoad %v2float %29
920 %37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %30
921 OpStore %25 %37
922 OpReturn
923 OpFunctionEnd
924 )";
925 
926   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
927       text, /* skip_nop = */ true, /* do_validation = */ false);
928   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
929 }
930 // This test will place a load before the store.  We cannot propagate in this
931 // case.
TEST_F(CopyPropArrayPassTest,LoadBeforeStore)932 TEST_F(CopyPropArrayPassTest, LoadBeforeStore) {
933   const std::string text =
934       R"(
935 OpCapability Shader
936 OpMemoryModel Logical GLSL450
937 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
938 OpExecutionMode %main OriginUpperLeft
939 OpSource HLSL 600
940 OpName %type_MyCBuffer "type.MyCBuffer"
941 OpMemberName %type_MyCBuffer 0 "Data"
942 OpName %MyCBuffer "MyCBuffer"
943 OpName %main "main"
944 OpName %in_var_INDEX "in.var.INDEX"
945 OpName %out_var_SV_Target "out.var.SV_Target"
946 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
947 OpMemberDecorate %type_MyCBuffer 0 Offset 0
948 OpDecorate %type_MyCBuffer Block
949 OpDecorate %in_var_INDEX Flat
950 OpDecorate %in_var_INDEX Location 0
951 OpDecorate %out_var_SV_Target Location 0
952 OpDecorate %MyCBuffer DescriptorSet 0
953 OpDecorate %MyCBuffer Binding 0
954 %float = OpTypeFloat 32
955 %v4float = OpTypeVector %float 4
956 %uint = OpTypeInt 32 0
957 %uint_8 = OpConstant %uint 8
958 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
959 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
960 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
961 %void = OpTypeVoid
962 %13 = OpTypeFunction %void
963 %int = OpTypeInt 32 1
964 %_ptr_Input_int = OpTypePointer Input %int
965 %_ptr_Output_v4float = OpTypePointer Output %v4float
966 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
967 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
968 %int_0 = OpConstant %int 0
969 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
970 %_ptr_Function_v4float = OpTypePointer Function %v4float
971 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
972 %in_var_INDEX = OpVariable %_ptr_Input_int Input
973 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
974 %main = OpFunction %void None %13
975 %22 = OpLabel
976 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
977 %38 = OpAccessChain %_ptr_Function_v4float %23 %24
978 %39 = OpLoad %v4float %36
979 %24 = OpLoad %int %in_var_INDEX
980 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
981 %26 = OpLoad %_arr_v4float_uint_8 %25
982 %27 = OpCompositeExtract %v4float %26 0
983 %28 = OpCompositeExtract %v4float %26 1
984 %29 = OpCompositeExtract %v4float %26 2
985 %30 = OpCompositeExtract %v4float %26 3
986 %31 = OpCompositeExtract %v4float %26 4
987 %32 = OpCompositeExtract %v4float %26 5
988 %33 = OpCompositeExtract %v4float %26 6
989 %34 = OpCompositeExtract %v4float %26 7
990 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
991 OpStore %23 %35
992 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
993 %37 = OpLoad %v4float %36
994 OpStore %out_var_SV_Target %37
995 OpReturn
996 OpFunctionEnd
997 )";
998 
999   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1000   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1001                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1002   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1003       text, /* skip_nop = */ true, /* do_validation = */ false);
1004 
1005   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1006 }
1007 
1008 // This test will place a load where it is not dominated by the store.  We
1009 // cannot propagate in this case.
TEST_F(CopyPropArrayPassTest,LoadNotDominated)1010 TEST_F(CopyPropArrayPassTest, LoadNotDominated) {
1011   const std::string text =
1012       R"(
1013 OpCapability Shader
1014 OpMemoryModel Logical GLSL450
1015 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1016 OpExecutionMode %main OriginUpperLeft
1017 OpSource HLSL 600
1018 OpName %type_MyCBuffer "type.MyCBuffer"
1019 OpMemberName %type_MyCBuffer 0 "Data"
1020 OpName %MyCBuffer "MyCBuffer"
1021 OpName %main "main"
1022 OpName %in_var_INDEX "in.var.INDEX"
1023 OpName %out_var_SV_Target "out.var.SV_Target"
1024 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1025 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1026 OpDecorate %type_MyCBuffer Block
1027 OpDecorate %in_var_INDEX Flat
1028 OpDecorate %in_var_INDEX Location 0
1029 OpDecorate %out_var_SV_Target Location 0
1030 OpDecorate %MyCBuffer DescriptorSet 0
1031 OpDecorate %MyCBuffer Binding 0
1032 %bool = OpTypeBool
1033 %true = OpConstantTrue %bool
1034 %float = OpTypeFloat 32
1035 %v4float = OpTypeVector %float 4
1036 %uint = OpTypeInt 32 0
1037 %uint_8 = OpConstant %uint 8
1038 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1039 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1040 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1041 %void = OpTypeVoid
1042 %13 = OpTypeFunction %void
1043 %int = OpTypeInt 32 1
1044 %_ptr_Input_int = OpTypePointer Input %int
1045 %_ptr_Output_v4float = OpTypePointer Output %v4float
1046 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1047 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1048 %int_0 = OpConstant %int 0
1049 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1050 %_ptr_Function_v4float = OpTypePointer Function %v4float
1051 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1052 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1053 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1054 %main = OpFunction %void None %13
1055 %22 = OpLabel
1056 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1057 OpSelectionMerge %merge None
1058 OpBranchConditional %true %if %else
1059 %if = OpLabel
1060 %24 = OpLoad %int %in_var_INDEX
1061 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1062 %26 = OpLoad %_arr_v4float_uint_8 %25
1063 %27 = OpCompositeExtract %v4float %26 0
1064 %28 = OpCompositeExtract %v4float %26 1
1065 %29 = OpCompositeExtract %v4float %26 2
1066 %30 = OpCompositeExtract %v4float %26 3
1067 %31 = OpCompositeExtract %v4float %26 4
1068 %32 = OpCompositeExtract %v4float %26 5
1069 %33 = OpCompositeExtract %v4float %26 6
1070 %34 = OpCompositeExtract %v4float %26 7
1071 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1072 OpStore %23 %35
1073 %38 = OpAccessChain %_ptr_Function_v4float %23 %24
1074 %39 = OpLoad %v4float %36
1075 OpBranch %merge
1076 %else = OpLabel
1077 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1078 %37 = OpLoad %v4float %36
1079 OpBranch %merge
1080 %merge = OpLabel
1081 %phi = OpPhi %out_var_SV_Target %39 %if %37 %else
1082 OpStore %out_var_SV_Target %phi
1083 OpReturn
1084 OpFunctionEnd
1085 )";
1086 
1087   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1088   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1089                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1090   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1091       text, /* skip_nop = */ true, /* do_validation = */ false);
1092 
1093   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1094 }
1095 
1096 // This test has a partial store to the variable.  We cannot propagate in this
1097 // case.
TEST_F(CopyPropArrayPassTest,PartialStore)1098 TEST_F(CopyPropArrayPassTest, PartialStore) {
1099   const std::string text =
1100       R"(
1101 OpCapability Shader
1102 OpMemoryModel Logical GLSL450
1103 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1104 OpExecutionMode %main OriginUpperLeft
1105 OpSource HLSL 600
1106 OpName %type_MyCBuffer "type.MyCBuffer"
1107 OpMemberName %type_MyCBuffer 0 "Data"
1108 OpName %MyCBuffer "MyCBuffer"
1109 OpName %main "main"
1110 OpName %in_var_INDEX "in.var.INDEX"
1111 OpName %out_var_SV_Target "out.var.SV_Target"
1112 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1113 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1114 OpDecorate %type_MyCBuffer Block
1115 OpDecorate %in_var_INDEX Flat
1116 OpDecorate %in_var_INDEX Location 0
1117 OpDecorate %out_var_SV_Target Location 0
1118 OpDecorate %MyCBuffer DescriptorSet 0
1119 OpDecorate %MyCBuffer Binding 0
1120 %float = OpTypeFloat 32
1121 %v4float = OpTypeVector %float 4
1122 %uint = OpTypeInt 32 0
1123 %uint_8 = OpConstant %uint 8
1124 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1125 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1126 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1127 %void = OpTypeVoid
1128 %13 = OpTypeFunction %void
1129 %int = OpTypeInt 32 1
1130 %_ptr_Input_int = OpTypePointer Input %int
1131 %_ptr_Output_v4float = OpTypePointer Output %v4float
1132 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1133 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1134 %int_0 = OpConstant %int 0
1135 %f0 = OpConstant %float 0
1136 %v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
1137 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1138 %_ptr_Function_v4float = OpTypePointer Function %v4float
1139 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1140 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1141 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1142 %main = OpFunction %void None %13
1143 %22 = OpLabel
1144 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1145 %24 = OpLoad %int %in_var_INDEX
1146 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1147 %26 = OpLoad %_arr_v4float_uint_8 %25
1148 %27 = OpCompositeExtract %v4float %26 0
1149 %28 = OpCompositeExtract %v4float %26 1
1150 %29 = OpCompositeExtract %v4float %26 2
1151 %30 = OpCompositeExtract %v4float %26 3
1152 %31 = OpCompositeExtract %v4float %26 4
1153 %32 = OpCompositeExtract %v4float %26 5
1154 %33 = OpCompositeExtract %v4float %26 6
1155 %34 = OpCompositeExtract %v4float %26 7
1156 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1157 OpStore %23 %35
1158 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1159 %37 = OpLoad %v4float %36
1160       OpStore %36 %v4const
1161 OpStore %out_var_SV_Target %37
1162 OpReturn
1163 OpFunctionEnd
1164 )";
1165 
1166   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1167   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1168                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1169   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1170       text, /* skip_nop = */ true, /* do_validation = */ false);
1171 
1172   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1173 }
1174 
1175 // This test does not have a proper copy of an object.  We cannot propagate in
1176 // this case.
TEST_F(CopyPropArrayPassTest,NotACopy)1177 TEST_F(CopyPropArrayPassTest, NotACopy) {
1178   const std::string text =
1179       R"(
1180 OpCapability Shader
1181 OpMemoryModel Logical GLSL450
1182 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1183 OpExecutionMode %main OriginUpperLeft
1184 OpSource HLSL 600
1185 OpName %type_MyCBuffer "type.MyCBuffer"
1186 OpMemberName %type_MyCBuffer 0 "Data"
1187 OpName %MyCBuffer "MyCBuffer"
1188 OpName %main "main"
1189 OpName %in_var_INDEX "in.var.INDEX"
1190 OpName %out_var_SV_Target "out.var.SV_Target"
1191 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1192 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1193 OpDecorate %type_MyCBuffer Block
1194 OpDecorate %in_var_INDEX Flat
1195 OpDecorate %in_var_INDEX Location 0
1196 OpDecorate %out_var_SV_Target Location 0
1197 OpDecorate %MyCBuffer DescriptorSet 0
1198 OpDecorate %MyCBuffer Binding 0
1199 %float = OpTypeFloat 32
1200 %v4float = OpTypeVector %float 4
1201 %uint = OpTypeInt 32 0
1202 %uint_8 = OpConstant %uint 8
1203 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1204 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1205 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1206 %void = OpTypeVoid
1207 %13 = OpTypeFunction %void
1208 %int = OpTypeInt 32 1
1209 %_ptr_Input_int = OpTypePointer Input %int
1210 %_ptr_Output_v4float = OpTypePointer Output %v4float
1211 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1212 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1213 %int_0 = OpConstant %int 0
1214 %f0 = OpConstant %float 0
1215 %v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
1216 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1217 %_ptr_Function_v4float = OpTypePointer Function %v4float
1218 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1219 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1220 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1221 %main = OpFunction %void None %13
1222 %22 = OpLabel
1223 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1224 %24 = OpLoad %int %in_var_INDEX
1225 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1226 %26 = OpLoad %_arr_v4float_uint_8 %25
1227 %27 = OpCompositeExtract %v4float %26 0
1228 %28 = OpCompositeExtract %v4float %26 0
1229 %29 = OpCompositeExtract %v4float %26 2
1230 %30 = OpCompositeExtract %v4float %26 3
1231 %31 = OpCompositeExtract %v4float %26 4
1232 %32 = OpCompositeExtract %v4float %26 5
1233 %33 = OpCompositeExtract %v4float %26 6
1234 %34 = OpCompositeExtract %v4float %26 7
1235 %35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1236 OpStore %23 %35
1237 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1238 %37 = OpLoad %v4float %36
1239 OpStore %out_var_SV_Target %37
1240 OpReturn
1241 OpFunctionEnd
1242 )";
1243 
1244   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1245   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1246                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1247   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1248       text, /* skip_nop = */ true, /* do_validation = */ false);
1249 
1250   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1251 }
1252 
TEST_F(CopyPropArrayPassTest,BadCopyViaInserts1)1253 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts1) {
1254   const std::string text =
1255       R"(
1256 OpCapability Shader
1257 OpMemoryModel Logical GLSL450
1258 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1259 OpExecutionMode %main OriginUpperLeft
1260 OpSource HLSL 600
1261 OpName %type_MyCBuffer "type.MyCBuffer"
1262 OpMemberName %type_MyCBuffer 0 "Data"
1263 OpName %MyCBuffer "MyCBuffer"
1264 OpName %main "main"
1265 OpName %in_var_INDEX "in.var.INDEX"
1266 OpName %out_var_SV_Target "out.var.SV_Target"
1267 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1268 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1269 OpDecorate %type_MyCBuffer Block
1270 OpDecorate %in_var_INDEX Flat
1271 OpDecorate %in_var_INDEX Location 0
1272 OpDecorate %out_var_SV_Target Location 0
1273 OpDecorate %MyCBuffer DescriptorSet 0
1274 OpDecorate %MyCBuffer Binding 0
1275 %float = OpTypeFloat 32
1276 %v4float = OpTypeVector %float 4
1277 %uint = OpTypeInt 32 0
1278 %uint_8 = OpConstant %uint 8
1279 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1280 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1281 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1282 %void = OpTypeVoid
1283 %13 = OpTypeFunction %void
1284 %int = OpTypeInt 32 1
1285 %_ptr_Input_int = OpTypePointer Input %int
1286 %_ptr_Output_v4float = OpTypePointer Output %v4float
1287 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1288 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1289 %int_0 = OpConstant %int 0
1290 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1291 %_ptr_Function_v4float = OpTypePointer Function %v4float
1292 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1293 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1294 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1295 %main = OpFunction %void None %13
1296 %22 = OpLabel
1297 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1298 %undef = OpUndef %_arr_v4float_uint_8_0
1299 %24 = OpLoad %int %in_var_INDEX
1300 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1301 %26 = OpLoad %_arr_v4float_uint_8 %25
1302 %27 = OpCompositeExtract %v4float %26 0
1303 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
1304 %28 = OpCompositeExtract %v4float %26 1
1305 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
1306 %29 = OpCompositeExtract %v4float %26 2
1307 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 3
1308 %30 = OpCompositeExtract %v4float %26 3
1309 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1310 %31 = OpCompositeExtract %v4float %26 4
1311 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1312 %32 = OpCompositeExtract %v4float %26 5
1313 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1314 %33 = OpCompositeExtract %v4float %26 6
1315 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1316 %34 = OpCompositeExtract %v4float %26 7
1317 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1318 OpStore %23 %i7
1319 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1320 %37 = OpLoad %v4float %36
1321 OpStore %out_var_SV_Target %37
1322 OpReturn
1323 OpFunctionEnd
1324 )";
1325 
1326   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1327   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1328                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1329   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1330       text, /* skip_nop = */ true, /* do_validation = */ false);
1331 
1332   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1333 }
1334 
TEST_F(CopyPropArrayPassTest,BadCopyViaInserts2)1335 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts2) {
1336   const std::string text =
1337       R"(
1338 OpCapability Shader
1339 OpMemoryModel Logical GLSL450
1340 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1341 OpExecutionMode %main OriginUpperLeft
1342 OpSource HLSL 600
1343 OpName %type_MyCBuffer "type.MyCBuffer"
1344 OpMemberName %type_MyCBuffer 0 "Data"
1345 OpName %MyCBuffer "MyCBuffer"
1346 OpName %main "main"
1347 OpName %in_var_INDEX "in.var.INDEX"
1348 OpName %out_var_SV_Target "out.var.SV_Target"
1349 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1350 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1351 OpDecorate %type_MyCBuffer Block
1352 OpDecorate %in_var_INDEX Flat
1353 OpDecorate %in_var_INDEX Location 0
1354 OpDecorate %out_var_SV_Target Location 0
1355 OpDecorate %MyCBuffer DescriptorSet 0
1356 OpDecorate %MyCBuffer Binding 0
1357 %float = OpTypeFloat 32
1358 %v4float = OpTypeVector %float 4
1359 %uint = OpTypeInt 32 0
1360 %uint_8 = OpConstant %uint 8
1361 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1362 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1363 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1364 %void = OpTypeVoid
1365 %13 = OpTypeFunction %void
1366 %int = OpTypeInt 32 1
1367 %_ptr_Input_int = OpTypePointer Input %int
1368 %_ptr_Output_v4float = OpTypePointer Output %v4float
1369 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1370 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1371 %int_0 = OpConstant %int 0
1372 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1373 %_ptr_Function_v4float = OpTypePointer Function %v4float
1374 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1375 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1376 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1377 %main = OpFunction %void None %13
1378 %22 = OpLabel
1379 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1380 %undef = OpUndef %_arr_v4float_uint_8_0
1381 %24 = OpLoad %int %in_var_INDEX
1382 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1383 %26 = OpLoad %_arr_v4float_uint_8 %25
1384 %27 = OpCompositeExtract %v4float %26 0
1385 %i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
1386 %28 = OpCompositeExtract %v4float %26 1
1387 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
1388 %29 = OpCompositeExtract %v4float %26 3
1389 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
1390 %30 = OpCompositeExtract %v4float %26 3
1391 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1392 %31 = OpCompositeExtract %v4float %26 4
1393 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1394 %32 = OpCompositeExtract %v4float %26 5
1395 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1396 %33 = OpCompositeExtract %v4float %26 6
1397 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1398 %34 = OpCompositeExtract %v4float %26 7
1399 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1400 OpStore %23 %i7
1401 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1402 %37 = OpLoad %v4float %36
1403 OpStore %out_var_SV_Target %37
1404 OpReturn
1405 OpFunctionEnd
1406 )";
1407 
1408   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1409   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1410                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1411   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1412       text, /* skip_nop = */ true, /* do_validation = */ false);
1413 
1414   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1415 }
1416 
TEST_F(CopyPropArrayPassTest,BadCopyViaInserts3)1417 TEST_F(CopyPropArrayPassTest, BadCopyViaInserts3) {
1418   const std::string text =
1419       R"(
1420 OpCapability Shader
1421 OpMemoryModel Logical GLSL450
1422 OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1423 OpExecutionMode %main OriginUpperLeft
1424 OpSource HLSL 600
1425 OpName %type_MyCBuffer "type.MyCBuffer"
1426 OpMemberName %type_MyCBuffer 0 "Data"
1427 OpName %MyCBuffer "MyCBuffer"
1428 OpName %main "main"
1429 OpName %in_var_INDEX "in.var.INDEX"
1430 OpName %out_var_SV_Target "out.var.SV_Target"
1431 OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1432 OpMemberDecorate %type_MyCBuffer 0 Offset 0
1433 OpDecorate %type_MyCBuffer Block
1434 OpDecorate %in_var_INDEX Flat
1435 OpDecorate %in_var_INDEX Location 0
1436 OpDecorate %out_var_SV_Target Location 0
1437 OpDecorate %MyCBuffer DescriptorSet 0
1438 OpDecorate %MyCBuffer Binding 0
1439 %float = OpTypeFloat 32
1440 %v4float = OpTypeVector %float 4
1441 %uint = OpTypeInt 32 0
1442 %uint_8 = OpConstant %uint 8
1443 %_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1444 %type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1445 %_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1446 %void = OpTypeVoid
1447 %13 = OpTypeFunction %void
1448 %int = OpTypeInt 32 1
1449 %_ptr_Input_int = OpTypePointer Input %int
1450 %_ptr_Output_v4float = OpTypePointer Output %v4float
1451 %_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1452 %_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1453 %int_0 = OpConstant %int 0
1454 %_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1455 %_ptr_Function_v4float = OpTypePointer Function %v4float
1456 %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1457 %in_var_INDEX = OpVariable %_ptr_Input_int Input
1458 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1459 %main = OpFunction %void None %13
1460 %22 = OpLabel
1461 %23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1462 %undef = OpUndef %_arr_v4float_uint_8_0
1463 %24 = OpLoad %int %in_var_INDEX
1464 %25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1465 %26 = OpLoad %_arr_v4float_uint_8 %25
1466 %28 = OpCompositeExtract %v4float %26 1
1467 %i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %undef 1
1468 %29 = OpCompositeExtract %v4float %26 2
1469 %i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
1470 %30 = OpCompositeExtract %v4float %26 3
1471 %i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1472 %31 = OpCompositeExtract %v4float %26 4
1473 %i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1474 %32 = OpCompositeExtract %v4float %26 5
1475 %i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1476 %33 = OpCompositeExtract %v4float %26 6
1477 %i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1478 %34 = OpCompositeExtract %v4float %26 7
1479 %i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1480 OpStore %23 %i7
1481 %36 = OpAccessChain %_ptr_Function_v4float %23 %24
1482 %37 = OpLoad %v4float %36
1483 OpStore %out_var_SV_Target %37
1484 OpReturn
1485 OpFunctionEnd
1486 )";
1487 
1488   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1489   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1490                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1491   auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1492       text, /* skip_nop = */ true, /* do_validation = */ false);
1493 
1494   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1495 }
1496 
TEST_F(CopyPropArrayPassTest,AtomicAdd)1497 TEST_F(CopyPropArrayPassTest, AtomicAdd) {
1498   const std::string before = R"(OpCapability SampledBuffer
1499 OpCapability StorageImageExtendedFormats
1500 OpCapability ImageBuffer
1501 OpCapability Shader
1502 %1 = OpExtInstImport "GLSL.std.450"
1503 OpMemoryModel Logical GLSL450
1504 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
1505 OpExecutionMode %2 LocalSize 64 1 1
1506 OpSource HLSL 600
1507 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
1508 OpDecorate %4 DescriptorSet 4
1509 OpDecorate %4 Binding 70
1510 %uint = OpTypeInt 32 0
1511 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
1512 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
1513 %_ptr_Function_6 = OpTypePointer Function %6
1514 %void = OpTypeVoid
1515 %10 = OpTypeFunction %void
1516 %uint_0 = OpConstant %uint 0
1517 %uint_1 = OpConstant %uint 1
1518 %v3uint = OpTypeVector %uint 3
1519 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
1520 %_ptr_Image_uint = OpTypePointer Image %uint
1521 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
1522 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
1523 %2 = OpFunction %void None %10
1524 %17 = OpLabel
1525 %16 = OpVariable %_ptr_Function_6 Function
1526 %18 = OpLoad %6 %4
1527 OpStore %16 %18
1528 %19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0
1529 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
1530 OpReturn
1531 OpFunctionEnd
1532 )";
1533 
1534   const std::string after = R"(OpCapability SampledBuffer
1535 OpCapability StorageImageExtendedFormats
1536 OpCapability ImageBuffer
1537 OpCapability Shader
1538 %1 = OpExtInstImport "GLSL.std.450"
1539 OpMemoryModel Logical GLSL450
1540 OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
1541 OpExecutionMode %2 LocalSize 64 1 1
1542 OpSource HLSL 600
1543 OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
1544 OpDecorate %4 DescriptorSet 4
1545 OpDecorate %4 Binding 70
1546 %uint = OpTypeInt 32 0
1547 %6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
1548 %_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
1549 %_ptr_Function_6 = OpTypePointer Function %6
1550 %void = OpTypeVoid
1551 %10 = OpTypeFunction %void
1552 %uint_0 = OpConstant %uint 0
1553 %uint_1 = OpConstant %uint 1
1554 %v3uint = OpTypeVector %uint 3
1555 %_ptr_Input_v3uint = OpTypePointer Input %v3uint
1556 %_ptr_Image_uint = OpTypePointer Image %uint
1557 %4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
1558 %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
1559 %2 = OpFunction %void None %10
1560 %17 = OpLabel
1561 %16 = OpVariable %_ptr_Function_6 Function
1562 %18 = OpLoad %6 %4
1563 OpStore %16 %18
1564 %19 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0
1565 %20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
1566 OpReturn
1567 OpFunctionEnd
1568 )";
1569 
1570   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1571   SinglePassRunAndCheck<CopyPropagateArrays>(before, after, true, true);
1572 }
1573 
TEST_F(CopyPropArrayPassTest,IndexIsNullConstnat)1574 TEST_F(CopyPropArrayPassTest, IndexIsNullConstnat) {
1575   const std::string text = R"(
1576 ; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform
1577 ; CHECK: [[null:%\w+]] = OpConstantNull %uint
1578 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_uint_uint_1 [[var]] %uint_0 %uint_0
1579 ; CHECK: OpAccessChain %_ptr_Uniform_uint [[ac1]] [[null]]
1580 ; CHECK-NEXT: OpReturn
1581                OpCapability Shader
1582                OpMemoryModel Logical GLSL450
1583                OpEntryPoint Fragment %main "main"
1584                OpExecutionMode %main OriginUpperLeft
1585                OpSource HLSL 600
1586                OpDecorate %myCBuffer DescriptorSet 0
1587                OpDecorate %myCBuffer Binding 0
1588                OpDecorate %_arr_v4float_uint_1 ArrayStride 16
1589                OpMemberDecorate %MyConstantBuffer 0 Offset 0
1590                OpMemberDecorate %type_myCBuffer 0 Offset 0
1591                OpDecorate %type_myCBuffer Block
1592        %uint = OpTypeInt 32 0
1593       %int_0 = OpConstant %uint 0
1594      %uint_1 = OpConstant %uint 1
1595 %_arr_v4float_uint_1 = OpTypeArray %uint %uint_1
1596 %MyConstantBuffer = OpTypeStruct %_arr_v4float_uint_1
1597 %type_myCBuffer = OpTypeStruct %MyConstantBuffer
1598 %_ptr_Uniform_type_myCBuffer = OpTypePointer Uniform %type_myCBuffer
1599 %_arr_v4float_uint_1_0 = OpTypeArray %uint %uint_1
1600        %void = OpTypeVoid
1601          %19 = OpTypeFunction %void
1602 %_ptr_Function_v4float = OpTypePointer Function %uint
1603 %_ptr_Uniform_MyConstantBuffer = OpTypePointer Uniform %MyConstantBuffer
1604   %myCBuffer = OpVariable %_ptr_Uniform_type_myCBuffer Uniform
1605 %_ptr_Function__arr_v4float_uint_1_0 = OpTypePointer Function %_arr_v4float_uint_1_0
1606          %23 = OpConstantNull %uint
1607        %main = OpFunction %void None %19
1608          %24 = OpLabel
1609          %25 = OpVariable %_ptr_Function__arr_v4float_uint_1_0 Function
1610          %26 = OpAccessChain %_ptr_Uniform_MyConstantBuffer %myCBuffer %int_0
1611          %27 = OpLoad %MyConstantBuffer %26
1612          %28 = OpCompositeExtract %_arr_v4float_uint_1 %27 0
1613          %29 = OpCompositeExtract %uint %28 0
1614          %30 = OpCompositeConstruct %_arr_v4float_uint_1_0 %29
1615                OpStore %25 %30
1616          %31 = OpAccessChain %_ptr_Function_v4float %25 %23
1617                OpReturn
1618                OpFunctionEnd
1619 )";
1620 
1621   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1622   SinglePassRunAndMatch<CopyPropagateArrays>(text, true);
1623 }
1624 
1625 }  // namespace
1626 }  // namespace opt
1627 }  // namespace spvtools
1628