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 %39 = 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
1574 } // namespace
1575 } // namespace opt
1576 } // namespace spvtools
1577