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 <string>
16
17#include "gmock/gmock.h"
18#include "test/opt/assembly_builder.h"
19#include "test/opt/pass_fixture.h"
20
21namespace spvtools {
22namespace opt {
23namespace {
24
25using CopyPropArrayPassTest = PassTest<::testing::Test>;
26
27TEST_F(CopyPropArrayPassTest, BasicPropagateArray) {
28  const std::string before =
29      R"(
30OpCapability Shader
31OpMemoryModel Logical GLSL450
32OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
33OpExecutionMode %main OriginUpperLeft
34OpSource HLSL 600
35OpName %type_MyCBuffer "type.MyCBuffer"
36OpMemberName %type_MyCBuffer 0 "Data"
37OpName %MyCBuffer "MyCBuffer"
38OpName %main "main"
39OpName %in_var_INDEX "in.var.INDEX"
40OpName %out_var_SV_Target "out.var.SV_Target"
41OpDecorate %_arr_v4float_uint_8 ArrayStride 16
42OpMemberDecorate %type_MyCBuffer 0 Offset 0
43OpDecorate %type_MyCBuffer Block
44OpDecorate %in_var_INDEX Flat
45OpDecorate %in_var_INDEX Location 0
46OpDecorate %out_var_SV_Target Location 0
47OpDecorate %MyCBuffer DescriptorSet 0
48OpDecorate %MyCBuffer Binding 0
49%float = OpTypeFloat 32
50%v4float = OpTypeVector %float 4
51%uint = OpTypeInt 32 0
52%uint_8 = OpConstant %uint 8
53%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
54%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
55%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
56%void = OpTypeVoid
57%13 = OpTypeFunction %void
58%int = OpTypeInt 32 1
59%_ptr_Input_int = OpTypePointer Input %int
60%_ptr_Output_v4float = OpTypePointer Output %v4float
61%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
62%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
63%int_0 = OpConstant %int 0
64%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
65%_ptr_Function_v4float = OpTypePointer Function %v4float
66%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
67%in_var_INDEX = OpVariable %_ptr_Input_int Input
68%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
69; CHECK: OpFunction
70; CHECK: OpLabel
71; CHECK: OpVariable
72; CHECK: OpAccessChain
73; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
74; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
75; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
76; CHECK: OpStore %out_var_SV_Target [[load]]
77%main = OpFunction %void None %13
78%22 = OpLabel
79%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
80%24 = OpLoad %int %in_var_INDEX
81%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
82%26 = OpLoad %_arr_v4float_uint_8 %25
83%27 = OpCompositeExtract %v4float %26 0
84%28 = OpCompositeExtract %v4float %26 1
85%29 = OpCompositeExtract %v4float %26 2
86%30 = OpCompositeExtract %v4float %26 3
87%31 = OpCompositeExtract %v4float %26 4
88%32 = OpCompositeExtract %v4float %26 5
89%33 = OpCompositeExtract %v4float %26 6
90%34 = OpCompositeExtract %v4float %26 7
91%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
92OpStore %23 %35
93%36 = OpAccessChain %_ptr_Function_v4float %23 %24
94%37 = OpLoad %v4float %36
95OpStore %out_var_SV_Target %37
96OpReturn
97OpFunctionEnd
98)";
99
100  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
101  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
102                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
103  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
104}
105
106TEST_F(CopyPropArrayPassTest, BasicPropagateArrayWithName) {
107  const std::string before =
108      R"(
109OpCapability Shader
110OpMemoryModel Logical GLSL450
111OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
112OpExecutionMode %main OriginUpperLeft
113OpSource HLSL 600
114OpName %type_MyCBuffer "type.MyCBuffer"
115OpMemberName %type_MyCBuffer 0 "Data"
116OpName %MyCBuffer "MyCBuffer"
117OpName %main "main"
118OpName %local "local"
119OpName %in_var_INDEX "in.var.INDEX"
120OpName %out_var_SV_Target "out.var.SV_Target"
121OpDecorate %_arr_v4float_uint_8 ArrayStride 16
122OpMemberDecorate %type_MyCBuffer 0 Offset 0
123OpDecorate %type_MyCBuffer Block
124OpDecorate %in_var_INDEX Flat
125OpDecorate %in_var_INDEX Location 0
126OpDecorate %out_var_SV_Target Location 0
127OpDecorate %MyCBuffer DescriptorSet 0
128OpDecorate %MyCBuffer Binding 0
129%float = OpTypeFloat 32
130%v4float = OpTypeVector %float 4
131%uint = OpTypeInt 32 0
132%uint_8 = OpConstant %uint 8
133%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
134%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
135%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
136%void = OpTypeVoid
137%13 = OpTypeFunction %void
138%int = OpTypeInt 32 1
139%_ptr_Input_int = OpTypePointer Input %int
140%_ptr_Output_v4float = OpTypePointer Output %v4float
141%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
142%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
143%int_0 = OpConstant %int 0
144%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
145%_ptr_Function_v4float = OpTypePointer Function %v4float
146%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
147%in_var_INDEX = OpVariable %_ptr_Input_int Input
148%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
149; CHECK: OpFunction
150; CHECK: OpLabel
151; CHECK: OpVariable
152; CHECK: OpAccessChain
153; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
154; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
155; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
156; CHECK: OpStore %out_var_SV_Target [[load]]
157%main = OpFunction %void None %13
158%22 = OpLabel
159%local = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
160%24 = OpLoad %int %in_var_INDEX
161%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
162%26 = OpLoad %_arr_v4float_uint_8 %25
163%27 = OpCompositeExtract %v4float %26 0
164%28 = OpCompositeExtract %v4float %26 1
165%29 = OpCompositeExtract %v4float %26 2
166%30 = OpCompositeExtract %v4float %26 3
167%31 = OpCompositeExtract %v4float %26 4
168%32 = OpCompositeExtract %v4float %26 5
169%33 = OpCompositeExtract %v4float %26 6
170%34 = OpCompositeExtract %v4float %26 7
171%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
172OpStore %local %35
173%36 = OpAccessChain %_ptr_Function_v4float %local %24
174%37 = OpLoad %v4float %36
175OpStore %out_var_SV_Target %37
176OpReturn
177OpFunctionEnd
178)";
179
180  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
181  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
182                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
183  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
184}
185
186// Propagate 2d array.  This test identifying a copy through multiple levels.
187// Also has to traverse multiple OpAccessChains.
188TEST_F(CopyPropArrayPassTest, Propagate2DArray) {
189  const std::string text =
190      R"(OpCapability Shader
191OpMemoryModel Logical GLSL450
192OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
193OpExecutionMode %main OriginUpperLeft
194OpSource HLSL 600
195OpName %type_MyCBuffer "type.MyCBuffer"
196OpMemberName %type_MyCBuffer 0 "Data"
197OpName %MyCBuffer "MyCBuffer"
198OpName %main "main"
199OpName %in_var_INDEX "in.var.INDEX"
200OpName %out_var_SV_Target "out.var.SV_Target"
201OpDecorate %_arr_v4float_uint_2 ArrayStride 16
202OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
203OpMemberDecorate %type_MyCBuffer 0 Offset 0
204OpDecorate %type_MyCBuffer Block
205OpDecorate %in_var_INDEX Flat
206OpDecorate %in_var_INDEX Location 0
207OpDecorate %out_var_SV_Target Location 0
208OpDecorate %MyCBuffer DescriptorSet 0
209OpDecorate %MyCBuffer Binding 0
210%float = OpTypeFloat 32
211%v4float = OpTypeVector %float 4
212%uint = OpTypeInt 32 0
213%uint_2 = OpConstant %uint 2
214%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
215%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
216%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
217%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
218%void = OpTypeVoid
219%14 = OpTypeFunction %void
220%int = OpTypeInt 32 1
221%_ptr_Input_int = OpTypePointer Input %int
222%_ptr_Output_v4float = OpTypePointer Output %v4float
223%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
224%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
225%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
226%int_0 = OpConstant %int 0
227%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
228%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
229%_ptr_Function_v4float = OpTypePointer Function %v4float
230%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
231%in_var_INDEX = OpVariable %_ptr_Input_int Input
232%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
233; CHECK: OpFunction
234; CHECK: OpLabel
235; CHECK: OpVariable
236; CHECK: OpVariable
237; CHECK: OpAccessChain
238; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
239%main = OpFunction %void None %14
240%25 = OpLabel
241%26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
242%27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
243%28 = OpLoad %int %in_var_INDEX
244%29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
245%30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
246%31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
247%32 = OpCompositeExtract %v4float %31 0
248%33 = OpCompositeExtract %v4float %31 1
249%34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
250%35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
251%36 = OpCompositeExtract %v4float %35 0
252%37 = OpCompositeExtract %v4float %35 1
253%38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
254%39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
255; CHECK: OpStore
256OpStore %27 %39
257%40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
258%42 = OpAccessChain %_ptr_Function_v4float %40 %28
259%43 = OpLoad %v4float %42
260; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
261; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
262; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
263; CHECK: OpStore %out_var_SV_Target [[load]]
264OpStore %out_var_SV_Target %43
265OpReturn
266OpFunctionEnd
267)";
268
269  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
270  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
271                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
272  SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
273}
274
275// Propagate 2d array.  This test identifying a copy through multiple levels.
276// Also has to traverse multiple OpAccessChains.
277TEST_F(CopyPropArrayPassTest, Propagate2DArrayWithMultiLevelExtract) {
278  const std::string text =
279      R"(OpCapability Shader
280OpMemoryModel Logical GLSL450
281OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
282OpExecutionMode %main OriginUpperLeft
283OpSource HLSL 600
284OpName %type_MyCBuffer "type.MyCBuffer"
285OpMemberName %type_MyCBuffer 0 "Data"
286OpName %MyCBuffer "MyCBuffer"
287OpName %main "main"
288OpName %in_var_INDEX "in.var.INDEX"
289OpName %out_var_SV_Target "out.var.SV_Target"
290OpDecorate %_arr_v4float_uint_2 ArrayStride 16
291OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
292OpMemberDecorate %type_MyCBuffer 0 Offset 0
293OpDecorate %type_MyCBuffer Block
294OpDecorate %in_var_INDEX Flat
295OpDecorate %in_var_INDEX Location 0
296OpDecorate %out_var_SV_Target Location 0
297OpDecorate %MyCBuffer DescriptorSet 0
298OpDecorate %MyCBuffer Binding 0
299%float = OpTypeFloat 32
300%v4float = OpTypeVector %float 4
301%uint = OpTypeInt 32 0
302%uint_2 = OpConstant %uint 2
303%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
304%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
305%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
306%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
307%void = OpTypeVoid
308%14 = OpTypeFunction %void
309%int = OpTypeInt 32 1
310%_ptr_Input_int = OpTypePointer Input %int
311%_ptr_Output_v4float = OpTypePointer Output %v4float
312%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
313%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
314%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
315%int_0 = OpConstant %int 0
316%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
317%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
318%_ptr_Function_v4float = OpTypePointer Function %v4float
319%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
320%in_var_INDEX = OpVariable %_ptr_Input_int Input
321%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
322; CHECK: OpFunction
323; CHECK: OpLabel
324; CHECK: OpVariable
325; CHECK: OpVariable
326; CHECK: OpAccessChain
327; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
328%main = OpFunction %void None %14
329%25 = OpLabel
330%26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
331%27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
332%28 = OpLoad %int %in_var_INDEX
333%29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
334%30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
335%32 = OpCompositeExtract %v4float %30 0 0
336%33 = OpCompositeExtract %v4float %30 0 1
337%34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
338%36 = OpCompositeExtract %v4float %30 1 0
339%37 = OpCompositeExtract %v4float %30 1 1
340%38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
341%39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
342; CHECK: OpStore
343OpStore %27 %39
344%40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
345%42 = OpAccessChain %_ptr_Function_v4float %40 %28
346%43 = OpLoad %v4float %42
347; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2 [[new_address]] %28
348; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[ac1]] %28
349; CHECK: [[load:%\w+]] = OpLoad %v4float [[ac2]]
350; CHECK: OpStore %out_var_SV_Target [[load]]
351OpStore %out_var_SV_Target %43
352OpReturn
353OpFunctionEnd
354)";
355
356  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
357  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
358                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
359  SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
360}
361
362// Test decomposing an object when we need to "rewrite" a store.
363TEST_F(CopyPropArrayPassTest, DecomposeObjectForArrayStore) {
364  const std::string text =
365      R"(               OpCapability Shader
366               OpMemoryModel Logical GLSL450
367               OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
368               OpExecutionMode %main OriginUpperLeft
369               OpSource HLSL 600
370               OpName %type_MyCBuffer "type.MyCBuffer"
371               OpMemberName %type_MyCBuffer 0 "Data"
372               OpName %MyCBuffer "MyCBuffer"
373               OpName %main "main"
374               OpName %in_var_INDEX "in.var.INDEX"
375               OpName %out_var_SV_Target "out.var.SV_Target"
376               OpDecorate %_arr_v4float_uint_2 ArrayStride 16
377               OpDecorate %_arr__arr_v4float_uint_2_uint_2 ArrayStride 32
378               OpMemberDecorate %type_MyCBuffer 0 Offset 0
379               OpDecorate %type_MyCBuffer Block
380               OpDecorate %in_var_INDEX Flat
381               OpDecorate %in_var_INDEX Location 0
382               OpDecorate %out_var_SV_Target Location 0
383               OpDecorate %MyCBuffer DescriptorSet 0
384               OpDecorate %MyCBuffer Binding 0
385      %float = OpTypeFloat 32
386    %v4float = OpTypeVector %float 4
387       %uint = OpTypeInt 32 0
388     %uint_2 = OpConstant %uint 2
389%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
390%_arr__arr_v4float_uint_2_uint_2 = OpTypeArray %_arr_v4float_uint_2 %uint_2
391%type_MyCBuffer = OpTypeStruct %_arr__arr_v4float_uint_2_uint_2
392%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
393       %void = OpTypeVoid
394         %14 = OpTypeFunction %void
395        %int = OpTypeInt 32 1
396%_ptr_Input_int = OpTypePointer Input %int
397%_ptr_Output_v4float = OpTypePointer Output %v4float
398%_arr_v4float_uint_2_0 = OpTypeArray %v4float %uint_2
399%_arr__arr_v4float_uint_2_0_uint_2 = OpTypeArray %_arr_v4float_uint_2_0 %uint_2
400%_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 = OpTypePointer Function %_arr__arr_v4float_uint_2_0_uint_2
401      %int_0 = OpConstant %int 0
402%_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 = OpTypePointer Uniform %_arr__arr_v4float_uint_2_uint_2
403%_ptr_Function__arr_v4float_uint_2_0 = OpTypePointer Function %_arr_v4float_uint_2_0
404%_ptr_Function_v4float = OpTypePointer Function %v4float
405  %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
406%in_var_INDEX = OpVariable %_ptr_Input_int Input
407%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
408       %main = OpFunction %void None %14
409         %25 = OpLabel
410         %26 = OpVariable %_ptr_Function__arr_v4float_uint_2_0 Function
411         %27 = OpVariable %_ptr_Function__arr__arr_v4float_uint_2_0_uint_2 Function
412         %28 = OpLoad %int %in_var_INDEX
413         %29 = OpAccessChain %_ptr_Uniform__arr__arr_v4float_uint_2_uint_2 %MyCBuffer %int_0
414         %30 = OpLoad %_arr__arr_v4float_uint_2_uint_2 %29
415         %31 = OpCompositeExtract %_arr_v4float_uint_2 %30 0
416         %32 = OpCompositeExtract %v4float %31 0
417         %33 = OpCompositeExtract %v4float %31 1
418         %34 = OpCompositeConstruct %_arr_v4float_uint_2_0 %32 %33
419         %35 = OpCompositeExtract %_arr_v4float_uint_2 %30 1
420         %36 = OpCompositeExtract %v4float %35 0
421         %37 = OpCompositeExtract %v4float %35 1
422         %38 = OpCompositeConstruct %_arr_v4float_uint_2_0 %36 %37
423         %39 = OpCompositeConstruct %_arr__arr_v4float_uint_2_0_uint_2 %34 %38
424               OpStore %27 %39
425; CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_2
426         %40 = OpAccessChain %_ptr_Function__arr_v4float_uint_2_0 %27 %28
427; CHECK: [[load:%\w+]] = OpLoad %_arr_v4float_uint_2 [[access_chain]]
428         %41 = OpLoad %_arr_v4float_uint_2_0 %40
429; CHECK: [[extract1:%\w+]] = OpCompositeExtract %v4float [[load]] 0
430; CHECK: [[extract2:%\w+]] = OpCompositeExtract %v4float [[load]] 1
431; CHECK: [[construct:%\w+]] = OpCompositeConstruct %_arr_v4float_uint_2_0 [[extract1]] [[extract2]]
432; CHECK: OpStore %26 [[construct]]
433               OpStore %26 %41
434         %42 = OpAccessChain %_ptr_Function_v4float %26 %28
435         %43 = OpLoad %v4float %42
436               OpStore %out_var_SV_Target %43
437               OpReturn
438               OpFunctionEnd
439)";
440
441  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
442  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
443                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
444  SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
445}
446
447// Test decomposing an object when we need to "rewrite" a store.
448TEST_F(CopyPropArrayPassTest, DecomposeObjectForStructStore) {
449  const std::string text =
450      R"(               OpCapability Shader
451               OpMemoryModel Logical GLSL450
452               OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
453               OpExecutionMode %main OriginUpperLeft
454               OpSource HLSL 600
455               OpName %type_MyCBuffer "type.MyCBuffer"
456               OpMemberName %type_MyCBuffer 0 "Data"
457               OpName %MyCBuffer "MyCBuffer"
458               OpName %main "main"
459               OpName %in_var_INDEX "in.var.INDEX"
460               OpName %out_var_SV_Target "out.var.SV_Target"
461               OpMemberDecorate %type_MyCBuffer 0 Offset 0
462               OpDecorate %type_MyCBuffer Block
463               OpDecorate %in_var_INDEX Flat
464               OpDecorate %in_var_INDEX Location 0
465               OpDecorate %out_var_SV_Target Location 0
466               OpDecorate %MyCBuffer DescriptorSet 0
467               OpDecorate %MyCBuffer Binding 0
468; CHECK: OpDecorate [[decorated_type:%\w+]] GLSLPacked
469               OpDecorate %struct GLSLPacked
470      %float = OpTypeFloat 32
471    %v4float = OpTypeVector %float 4
472       %uint = OpTypeInt 32 0
473     %uint_2 = OpConstant %uint 2
474; CHECK: [[decorated_type]] = OpTypeStruct
475%struct = OpTypeStruct %float %uint
476%_arr_struct_uint_2 = OpTypeArray %struct %uint_2
477%type_MyCBuffer = OpTypeStruct %_arr_struct_uint_2
478%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
479       %void = OpTypeVoid
480         %14 = OpTypeFunction %void
481        %int = OpTypeInt 32 1
482%_ptr_Input_int = OpTypePointer Input %int
483%_ptr_Output_v4float = OpTypePointer Output %v4float
484; CHECK: [[struct:%\w+]] = OpTypeStruct %float %uint
485%struct_0 = OpTypeStruct %float %uint
486%_arr_struct_0_uint_2 = OpTypeArray %struct_0 %uint_2
487%_ptr_Function__arr_struct_0_uint_2 = OpTypePointer Function %_arr_struct_0_uint_2
488      %int_0 = OpConstant %int 0
489%_ptr_Uniform__arr_struct_uint_2 = OpTypePointer Uniform %_arr_struct_uint_2
490; CHECK: [[decorated_ptr:%\w+]] = OpTypePointer Uniform [[decorated_type]]
491%_ptr_Function_struct_0 = OpTypePointer Function %struct_0
492%_ptr_Function_v4float = OpTypePointer Function %v4float
493  %MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
494%in_var_INDEX = OpVariable %_ptr_Input_int Input
495%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
496       %main = OpFunction %void None %14
497         %25 = OpLabel
498         %26 = OpVariable %_ptr_Function_struct_0 Function
499         %27 = OpVariable %_ptr_Function__arr_struct_0_uint_2 Function
500         %28 = OpLoad %int %in_var_INDEX
501         %29 = OpAccessChain %_ptr_Uniform__arr_struct_uint_2 %MyCBuffer %int_0
502         %30 = OpLoad %_arr_struct_uint_2 %29
503         %31 = OpCompositeExtract %struct %30 0
504         %32 = OpCompositeExtract %v4float %31 0
505         %33 = OpCompositeExtract %v4float %31 1
506         %34 = OpCompositeConstruct %struct_0 %32 %33
507         %35 = OpCompositeExtract %struct %30 1
508         %36 = OpCompositeExtract %float %35 0
509         %37 = OpCompositeExtract %uint %35 1
510         %38 = OpCompositeConstruct %struct_0 %36 %37
511         %39 = OpCompositeConstruct %_arr_struct_0_uint_2 %34 %38
512               OpStore %27 %39
513; CHECK: [[access_chain:%\w+]] = OpAccessChain [[decorated_ptr]]
514         %40 = OpAccessChain %_ptr_Function_struct_0 %27 %28
515; CHECK: [[load:%\w+]] = OpLoad [[decorated_type]] [[access_chain]]
516         %41 = OpLoad %struct_0 %40
517; CHECK: [[extract1:%\w+]] = OpCompositeExtract %float [[load]] 0
518; CHECK: [[extract2:%\w+]] = OpCompositeExtract %uint [[load]] 1
519; CHECK: [[construct:%\w+]] = OpCompositeConstruct [[struct]] [[extract1]] [[extract2]]
520; CHECK: OpStore %26 [[construct]]
521               OpStore %26 %41
522         %42 = OpAccessChain %_ptr_Function_v4float %26 %28
523         %43 = OpLoad %v4float %42
524               OpStore %out_var_SV_Target %43
525               OpReturn
526               OpFunctionEnd
527)";
528
529  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
530  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
531                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
532  SinglePassRunAndMatch<CopyPropagateArrays>(text, false);
533}
534
535TEST_F(CopyPropArrayPassTest, CopyViaInserts) {
536  const std::string before =
537      R"(
538OpCapability Shader
539OpMemoryModel Logical GLSL450
540OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
541OpExecutionMode %main OriginUpperLeft
542OpSource HLSL 600
543OpName %type_MyCBuffer "type.MyCBuffer"
544OpMemberName %type_MyCBuffer 0 "Data"
545OpName %MyCBuffer "MyCBuffer"
546OpName %main "main"
547OpName %in_var_INDEX "in.var.INDEX"
548OpName %out_var_SV_Target "out.var.SV_Target"
549OpDecorate %_arr_v4float_uint_8 ArrayStride 16
550OpMemberDecorate %type_MyCBuffer 0 Offset 0
551OpDecorate %type_MyCBuffer Block
552OpDecorate %in_var_INDEX Flat
553OpDecorate %in_var_INDEX Location 0
554OpDecorate %out_var_SV_Target Location 0
555OpDecorate %MyCBuffer DescriptorSet 0
556OpDecorate %MyCBuffer Binding 0
557%float = OpTypeFloat 32
558%v4float = OpTypeVector %float 4
559%uint = OpTypeInt 32 0
560%uint_8 = OpConstant %uint 8
561%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
562%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
563%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
564%void = OpTypeVoid
565%13 = OpTypeFunction %void
566%int = OpTypeInt 32 1
567%_ptr_Input_int = OpTypePointer Input %int
568%_ptr_Output_v4float = OpTypePointer Output %v4float
569%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
570%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
571%int_0 = OpConstant %int 0
572%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
573%_ptr_Function_v4float = OpTypePointer Function %v4float
574%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
575%in_var_INDEX = OpVariable %_ptr_Input_int Input
576%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
577; CHECK: OpFunction
578; CHECK: OpLabel
579; CHECK: OpVariable
580; CHECK: OpAccessChain
581; CHECK: [[new_address:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
582; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[new_address]] %24
583; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
584; CHECK: OpStore %out_var_SV_Target [[load]]
585%main = OpFunction %void None %13
586%22 = OpLabel
587%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
588%undef = OpUndef %_arr_v4float_uint_8_0
589%24 = OpLoad %int %in_var_INDEX
590%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
591%26 = OpLoad %_arr_v4float_uint_8 %25
592%27 = OpCompositeExtract %v4float %26 0
593%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
594%28 = OpCompositeExtract %v4float %26 1
595%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
596%29 = OpCompositeExtract %v4float %26 2
597%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
598%30 = OpCompositeExtract %v4float %26 3
599%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
600%31 = OpCompositeExtract %v4float %26 4
601%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
602%32 = OpCompositeExtract %v4float %26 5
603%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
604%33 = OpCompositeExtract %v4float %26 6
605%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
606%34 = OpCompositeExtract %v4float %26 7
607%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
608OpStore %23 %i7
609%36 = OpAccessChain %_ptr_Function_v4float %23 %24
610%37 = OpLoad %v4float %36
611OpStore %out_var_SV_Target %37
612OpReturn
613OpFunctionEnd
614)";
615
616  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
617  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
618                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
619  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
620}
621
622TEST_F(CopyPropArrayPassTest, IsomorphicTypes1) {
623  const std::string before =
624      R"(
625; CHECK: [[int:%\w+]] = OpTypeInt 32 0
626; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
627; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
628; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
629; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
630; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
631; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
632; CHECK: [[p_a1:%\w+]] = OpTypePointer Uniform [[a1]]
633; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
634; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_a1]] [[global_var]] %uint_0
635; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s2]] [[ac1]] %uint_0
636; CHECK: [[ld:%\w+]] = OpLoad [[s2]] [[ac2]]
637; CHECK: [[ex:%\w+]] = OpCompositeExtract [[s1]] [[ld]]
638               OpCapability Shader
639          %1 = OpExtInstImport "GLSL.std.450"
640               OpMemoryModel Logical GLSL450
641               OpEntryPoint Fragment %2 "PS_main"
642               OpExecutionMode %2 OriginUpperLeft
643               OpSource HLSL 600
644               OpDecorate %3 DescriptorSet 0
645               OpDecorate %3 Binding 101
646       %uint = OpTypeInt 32 0
647     %uint_1 = OpConstant %uint 1
648  %s1 = OpTypeStruct %uint
649  %s2 = OpTypeStruct %s1
650%a1 = OpTypeArray %s2 %uint_1
651  %s3 = OpTypeStruct %a1
652 %s1_1 = OpTypeStruct %uint
653%_ptr_Uniform_uint = OpTypePointer Uniform %uint
654       %void = OpTypeVoid
655         %13 = OpTypeFunction %void
656     %uint_0 = OpConstant %uint 0
657 %s1_0 = OpTypeStruct %uint
658 %s2_0 = OpTypeStruct %s1_0
659%a1_0 = OpTypeArray %s2_0 %uint_1
660 %s3_0 = OpTypeStruct %a1_0
661%p_s3 = OpTypePointer Uniform %s3
662%p_s3_0 = OpTypePointer Function %s3_0
663          %3 = OpVariable %p_s3 Uniform
664%p_a1_0 = OpTypePointer Function %a1_0
665%p_s2_0 = OpTypePointer Function %s2_0
666          %2 = OpFunction %void None %13
667         %20 = OpLabel
668         %21 = OpVariable %p_a1_0 Function
669         %22 = OpLoad %s3 %3
670         %23 = OpCompositeExtract %a1 %22 0
671         %24 = OpCompositeExtract %s2 %23 0
672         %25 = OpCompositeExtract %s1 %24 0
673         %26 = OpCompositeExtract %uint %25 0
674         %27 = OpCompositeConstruct %s1_0 %26
675         %32 = OpCompositeConstruct %s2_0 %27
676         %28 = OpCompositeConstruct %a1_0 %32
677               OpStore %21 %28
678         %29 = OpAccessChain %p_s2_0 %21 %uint_0
679         %30 = OpLoad %s2 %29
680         %31 = OpCompositeExtract %s1 %30 0
681               OpReturn
682               OpFunctionEnd
683)";
684
685  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
686  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
687                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
688  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
689}
690
691TEST_F(CopyPropArrayPassTest, IsomorphicTypes2) {
692  const std::string before =
693      R"(
694; CHECK: [[int:%\w+]] = OpTypeInt 32 0
695; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
696; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
697; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
698; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
699; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
700; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
701; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
702; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
703; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
704; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
705; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
706; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
707               OpCapability Shader
708          %1 = OpExtInstImport "GLSL.std.450"
709               OpMemoryModel Logical GLSL450
710               OpEntryPoint Fragment %2 "PS_main"
711               OpExecutionMode %2 OriginUpperLeft
712               OpSource HLSL 600
713               OpDecorate %3 DescriptorSet 0
714               OpDecorate %3 Binding 101
715       %uint = OpTypeInt 32 0
716     %uint_1 = OpConstant %uint 1
717  %_struct_6 = OpTypeStruct %uint
718  %_struct_7 = OpTypeStruct %_struct_6
719%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
720  %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
721 %_struct_10 = OpTypeStruct %uint
722%_ptr_Uniform_uint = OpTypePointer Uniform %uint
723       %void = OpTypeVoid
724         %13 = OpTypeFunction %void
725     %uint_0 = OpConstant %uint 0
726 %_struct_15 = OpTypeStruct %uint
727%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
728%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
729%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
730          %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
731%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
732          %2 = OpFunction %void None %13
733         %20 = OpLabel
734         %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
735         %22 = OpLoad %_struct_9 %3
736         %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
737         %24 = OpCompositeExtract %_struct_7 %23 0
738         %25 = OpCompositeExtract %_struct_6 %24 0
739         %26 = OpCompositeExtract %uint %25 0
740         %27 = OpCompositeConstruct %_struct_15 %26
741         %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
742               OpStore %21 %28
743         %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
744         %30 = OpLoad %_struct_15 %29
745         %31 = OpCompositeExtract %uint %30 0
746               OpReturn
747               OpFunctionEnd
748)";
749
750  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
751  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
752                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
753  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
754}
755
756TEST_F(CopyPropArrayPassTest, IsomorphicTypes3) {
757  const std::string before =
758      R"(
759; CHECK: [[int:%\w+]] = OpTypeInt 32 0
760; CHECK: [[s1:%\w+]] = OpTypeStruct [[int]]
761; CHECK: [[s2:%\w+]] = OpTypeStruct [[s1]]
762; CHECK: [[a1:%\w+]] = OpTypeArray [[s2]]
763; CHECK: [[s3:%\w+]] = OpTypeStruct [[a1]]
764; CHECK: [[s1_1:%\w+]] = OpTypeStruct [[int]]
765; CHECK: [[p_s3:%\w+]] = OpTypePointer Uniform [[s3]]
766; CHECK: [[p_s1_1:%\w+]] = OpTypePointer Function [[s1_1]]
767; CHECK: [[global_var:%\w+]] = OpVariable [[p_s3]] Uniform
768; CHECK: [[p_s2:%\w+]] = OpTypePointer Uniform [[s2]]
769; CHECK: [[p_s1:%\w+]] = OpTypePointer Uniform [[s1]]
770; CHECK: [[var:%\w+]] = OpVariable [[p_s1_1]] Function
771; CHECK: [[ac1:%\w+]] = OpAccessChain [[p_s2]] [[global_var]] %uint_0 %uint_0
772; CHECK: [[ac2:%\w+]] = OpAccessChain [[p_s1]] [[ac1]] %uint_0
773; CHECK: [[ld:%\w+]] = OpLoad [[s1]] [[ac2]]
774; CHECK: [[ex:%\w+]] = OpCompositeExtract [[int]] [[ld]]
775; CHECK: [[copy:%\w+]] = OpCompositeConstruct [[s1_1]] [[ex]]
776; CHECK: OpStore [[var]] [[copy]]
777               OpCapability Shader
778          %1 = OpExtInstImport "GLSL.std.450"
779               OpMemoryModel Logical GLSL450
780               OpEntryPoint Fragment %2 "PS_main"
781               OpExecutionMode %2 OriginUpperLeft
782               OpSource HLSL 600
783               OpDecorate %3 DescriptorSet 0
784               OpDecorate %3 Binding 101
785       %uint = OpTypeInt 32 0
786     %uint_1 = OpConstant %uint 1
787  %_struct_6 = OpTypeStruct %uint
788  %_struct_7 = OpTypeStruct %_struct_6
789%_arr__struct_7_uint_1 = OpTypeArray %_struct_7 %uint_1
790  %_struct_9 = OpTypeStruct %_arr__struct_7_uint_1
791%_ptr_Uniform_uint = OpTypePointer Uniform %uint
792       %void = OpTypeVoid
793         %13 = OpTypeFunction %void
794     %uint_0 = OpConstant %uint 0
795 %_struct_15 = OpTypeStruct %uint
796 %_struct_10 = OpTypeStruct %uint
797%_arr__struct_15_uint_1 = OpTypeArray %_struct_15 %uint_1
798%_ptr_Uniform__struct_9 = OpTypePointer Uniform %_struct_9
799%_ptr_Function__struct_15 = OpTypePointer Function %_struct_15
800          %3 = OpVariable %_ptr_Uniform__struct_9 Uniform
801%_ptr_Function__arr__struct_15_uint_1 = OpTypePointer Function %_arr__struct_15_uint_1
802          %2 = OpFunction %void None %13
803         %20 = OpLabel
804         %21 = OpVariable %_ptr_Function__arr__struct_15_uint_1 Function
805        %var = OpVariable %_ptr_Function__struct_15 Function
806         %22 = OpLoad %_struct_9 %3
807         %23 = OpCompositeExtract %_arr__struct_7_uint_1 %22 0
808         %24 = OpCompositeExtract %_struct_7 %23 0
809         %25 = OpCompositeExtract %_struct_6 %24 0
810         %26 = OpCompositeExtract %uint %25 0
811         %27 = OpCompositeConstruct %_struct_15 %26
812         %28 = OpCompositeConstruct %_arr__struct_15_uint_1 %27
813               OpStore %21 %28
814         %29 = OpAccessChain %_ptr_Function__struct_15 %21 %uint_0
815         %30 = OpLoad %_struct_15 %29
816               OpStore %var %30
817               OpReturn
818               OpFunctionEnd
819)";
820
821  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
822  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
823                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
824  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
825}
826
827TEST_F(CopyPropArrayPassTest, BadMergingTwoObjects) {
828  // The second element in the |OpCompositeConstruct| is from a different
829  // object.
830  const std::string text =
831      R"(OpCapability Shader
832OpMemoryModel Logical GLSL450
833OpEntryPoint Fragment %main "main"
834OpExecutionMode %main OriginUpperLeft
835OpName %type_ConstBuf "type.ConstBuf"
836OpMemberName %type_ConstBuf 0 "TexSizeU"
837OpMemberName %type_ConstBuf 1 "TexSizeV"
838OpName %ConstBuf "ConstBuf"
839OpName %main "main"
840OpMemberDecorate %type_ConstBuf 0 Offset 0
841OpMemberDecorate %type_ConstBuf 1 Offset 8
842OpDecorate %type_ConstBuf Block
843OpDecorate %ConstBuf DescriptorSet 0
844OpDecorate %ConstBuf Binding 2
845%float = OpTypeFloat 32
846%v2float = OpTypeVector %float 2
847%type_ConstBuf = OpTypeStruct %v2float %v2float
848%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
849%void = OpTypeVoid
850%9 = OpTypeFunction %void
851%uint = OpTypeInt 32 0
852%int_0 = OpConstant %uint 0
853%uint_2 = OpConstant %uint 2
854%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
855%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
856%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
857%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
858%main = OpFunction %void None %9
859%24 = OpLabel
860%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
861%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
862%28 = OpLoad %v2float %27
863%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
864%30 = OpLoad %v2float %29
865%31 = OpFNegate %v2float %30
866%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %31
867OpStore %25 %37
868OpReturn
869OpFunctionEnd
870)";
871
872  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
873      text, /* skip_nop = */ true, /* do_validation = */ false);
874  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
875}
876
877TEST_F(CopyPropArrayPassTest, SecondElementNotContained) {
878  // The second element in the |OpCompositeConstruct| is not a memory object.
879  // Make sure no change happends.
880  const std::string text =
881      R"(OpCapability Shader
882OpMemoryModel Logical GLSL450
883OpEntryPoint Fragment %main "main"
884OpExecutionMode %main OriginUpperLeft
885OpName %type_ConstBuf "type.ConstBuf"
886OpMemberName %type_ConstBuf 0 "TexSizeU"
887OpMemberName %type_ConstBuf 1 "TexSizeV"
888OpName %ConstBuf "ConstBuf"
889OpName %main "main"
890OpMemberDecorate %type_ConstBuf 0 Offset 0
891OpMemberDecorate %type_ConstBuf 1 Offset 8
892OpDecorate %type_ConstBuf Block
893OpDecorate %ConstBuf DescriptorSet 0
894OpDecorate %ConstBuf Binding 2
895OpDecorate %ConstBuf2 DescriptorSet 1
896OpDecorate %ConstBuf2 Binding 2
897%float = OpTypeFloat 32
898%v2float = OpTypeVector %float 2
899%type_ConstBuf = OpTypeStruct %v2float %v2float
900%_ptr_Uniform_type_ConstBuf = OpTypePointer Uniform %type_ConstBuf
901%void = OpTypeVoid
902%9 = OpTypeFunction %void
903%uint = OpTypeInt 32 0
904%int_0 = OpConstant %uint 0
905%int_1 = OpConstant %uint 1
906%uint_2 = OpConstant %uint 2
907%_arr_v2float_uint_2 = OpTypeArray %v2float %uint_2
908%_ptr_Function__arr_v2float_uint_2 = OpTypePointer Function %_arr_v2float_uint_2
909%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float
910%ConstBuf = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
911%ConstBuf2 = OpVariable %_ptr_Uniform_type_ConstBuf Uniform
912%main = OpFunction %void None %9
913%24 = OpLabel
914%25 = OpVariable %_ptr_Function__arr_v2float_uint_2 Function
915%27 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf %int_0
916%28 = OpLoad %v2float %27
917%29 = OpAccessChain %_ptr_Uniform_v2float %ConstBuf2 %int_1
918%30 = OpLoad %v2float %29
919%37 = OpCompositeConstruct %_arr_v2float_uint_2 %28 %30
920OpStore %25 %37
921OpReturn
922OpFunctionEnd
923)";
924
925  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
926      text, /* skip_nop = */ true, /* do_validation = */ false);
927  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
928}
929// This test will place a load before the store.  We cannot propagate in this
930// case.
931TEST_F(CopyPropArrayPassTest, LoadBeforeStore) {
932  const std::string text =
933      R"(
934OpCapability Shader
935OpMemoryModel Logical GLSL450
936OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
937OpExecutionMode %main OriginUpperLeft
938OpSource HLSL 600
939OpName %type_MyCBuffer "type.MyCBuffer"
940OpMemberName %type_MyCBuffer 0 "Data"
941OpName %MyCBuffer "MyCBuffer"
942OpName %main "main"
943OpName %in_var_INDEX "in.var.INDEX"
944OpName %out_var_SV_Target "out.var.SV_Target"
945OpDecorate %_arr_v4float_uint_8 ArrayStride 16
946OpMemberDecorate %type_MyCBuffer 0 Offset 0
947OpDecorate %type_MyCBuffer Block
948OpDecorate %in_var_INDEX Flat
949OpDecorate %in_var_INDEX Location 0
950OpDecorate %out_var_SV_Target Location 0
951OpDecorate %MyCBuffer DescriptorSet 0
952OpDecorate %MyCBuffer Binding 0
953%float = OpTypeFloat 32
954%v4float = OpTypeVector %float 4
955%uint = OpTypeInt 32 0
956%uint_8 = OpConstant %uint 8
957%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
958%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
959%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
960%void = OpTypeVoid
961%13 = OpTypeFunction %void
962%int = OpTypeInt 32 1
963%_ptr_Input_int = OpTypePointer Input %int
964%_ptr_Output_v4float = OpTypePointer Output %v4float
965%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
966%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
967%int_0 = OpConstant %int 0
968%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
969%_ptr_Function_v4float = OpTypePointer Function %v4float
970%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
971%in_var_INDEX = OpVariable %_ptr_Input_int Input
972%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
973%main = OpFunction %void None %13
974%22 = OpLabel
975%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
976%38 = OpAccessChain %_ptr_Function_v4float %23 %24
977%39 = OpLoad %v4float %36
978%24 = OpLoad %int %in_var_INDEX
979%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
980%26 = OpLoad %_arr_v4float_uint_8 %25
981%27 = OpCompositeExtract %v4float %26 0
982%28 = OpCompositeExtract %v4float %26 1
983%29 = OpCompositeExtract %v4float %26 2
984%30 = OpCompositeExtract %v4float %26 3
985%31 = OpCompositeExtract %v4float %26 4
986%32 = OpCompositeExtract %v4float %26 5
987%33 = OpCompositeExtract %v4float %26 6
988%34 = OpCompositeExtract %v4float %26 7
989%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
990OpStore %23 %35
991%36 = OpAccessChain %_ptr_Function_v4float %23 %24
992%37 = OpLoad %v4float %36
993OpStore %out_var_SV_Target %37
994OpReturn
995OpFunctionEnd
996)";
997
998  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
999  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1000                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1001  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1002      text, /* skip_nop = */ true, /* do_validation = */ false);
1003
1004  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1005}
1006
1007// This test will place a load where it is not dominated by the store.  We
1008// cannot propagate in this case.
1009TEST_F(CopyPropArrayPassTest, LoadNotDominated) {
1010  const std::string text =
1011      R"(
1012OpCapability Shader
1013OpMemoryModel Logical GLSL450
1014OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1015OpExecutionMode %main OriginUpperLeft
1016OpSource HLSL 600
1017OpName %type_MyCBuffer "type.MyCBuffer"
1018OpMemberName %type_MyCBuffer 0 "Data"
1019OpName %MyCBuffer "MyCBuffer"
1020OpName %main "main"
1021OpName %in_var_INDEX "in.var.INDEX"
1022OpName %out_var_SV_Target "out.var.SV_Target"
1023OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1024OpMemberDecorate %type_MyCBuffer 0 Offset 0
1025OpDecorate %type_MyCBuffer Block
1026OpDecorate %in_var_INDEX Flat
1027OpDecorate %in_var_INDEX Location 0
1028OpDecorate %out_var_SV_Target Location 0
1029OpDecorate %MyCBuffer DescriptorSet 0
1030OpDecorate %MyCBuffer Binding 0
1031%bool = OpTypeBool
1032%true = OpConstantTrue %bool
1033%float = OpTypeFloat 32
1034%v4float = OpTypeVector %float 4
1035%uint = OpTypeInt 32 0
1036%uint_8 = OpConstant %uint 8
1037%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1038%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1039%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1040%void = OpTypeVoid
1041%13 = OpTypeFunction %void
1042%int = OpTypeInt 32 1
1043%_ptr_Input_int = OpTypePointer Input %int
1044%_ptr_Output_v4float = OpTypePointer Output %v4float
1045%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1046%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1047%int_0 = OpConstant %int 0
1048%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1049%_ptr_Function_v4float = OpTypePointer Function %v4float
1050%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1051%in_var_INDEX = OpVariable %_ptr_Input_int Input
1052%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1053%main = OpFunction %void None %13
1054%22 = OpLabel
1055%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1056OpSelectionMerge %merge None
1057OpBranchConditional %true %if %else
1058%if = OpLabel
1059%24 = OpLoad %int %in_var_INDEX
1060%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1061%26 = OpLoad %_arr_v4float_uint_8 %25
1062%27 = OpCompositeExtract %v4float %26 0
1063%28 = OpCompositeExtract %v4float %26 1
1064%29 = OpCompositeExtract %v4float %26 2
1065%30 = OpCompositeExtract %v4float %26 3
1066%31 = OpCompositeExtract %v4float %26 4
1067%32 = OpCompositeExtract %v4float %26 5
1068%33 = OpCompositeExtract %v4float %26 6
1069%34 = OpCompositeExtract %v4float %26 7
1070%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1071OpStore %23 %35
1072%38 = OpAccessChain %_ptr_Function_v4float %23 %24
1073%39 = OpLoad %v4float %36
1074OpBranch %merge
1075%else = OpLabel
1076%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1077%37 = OpLoad %v4float %36
1078OpBranch %merge
1079%merge = OpLabel
1080%phi = OpPhi %out_var_SV_Target %39 %if %37 %else
1081OpStore %out_var_SV_Target %phi
1082OpReturn
1083OpFunctionEnd
1084)";
1085
1086  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1087  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1088                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1089  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1090      text, /* skip_nop = */ true, /* do_validation = */ false);
1091
1092  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1093}
1094
1095// This test has a partial store to the variable.  We cannot propagate in this
1096// case.
1097TEST_F(CopyPropArrayPassTest, PartialStore) {
1098  const std::string text =
1099      R"(
1100OpCapability Shader
1101OpMemoryModel Logical GLSL450
1102OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1103OpExecutionMode %main OriginUpperLeft
1104OpSource HLSL 600
1105OpName %type_MyCBuffer "type.MyCBuffer"
1106OpMemberName %type_MyCBuffer 0 "Data"
1107OpName %MyCBuffer "MyCBuffer"
1108OpName %main "main"
1109OpName %in_var_INDEX "in.var.INDEX"
1110OpName %out_var_SV_Target "out.var.SV_Target"
1111OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1112OpMemberDecorate %type_MyCBuffer 0 Offset 0
1113OpDecorate %type_MyCBuffer Block
1114OpDecorate %in_var_INDEX Flat
1115OpDecorate %in_var_INDEX Location 0
1116OpDecorate %out_var_SV_Target Location 0
1117OpDecorate %MyCBuffer DescriptorSet 0
1118OpDecorate %MyCBuffer Binding 0
1119%float = OpTypeFloat 32
1120%v4float = OpTypeVector %float 4
1121%uint = OpTypeInt 32 0
1122%uint_8 = OpConstant %uint 8
1123%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1124%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1125%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1126%void = OpTypeVoid
1127%13 = OpTypeFunction %void
1128%int = OpTypeInt 32 1
1129%_ptr_Input_int = OpTypePointer Input %int
1130%_ptr_Output_v4float = OpTypePointer Output %v4float
1131%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1132%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1133%int_0 = OpConstant %int 0
1134%f0 = OpConstant %float 0
1135%v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
1136%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1137%_ptr_Function_v4float = OpTypePointer Function %v4float
1138%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1139%in_var_INDEX = OpVariable %_ptr_Input_int Input
1140%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1141%main = OpFunction %void None %13
1142%22 = OpLabel
1143%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1144%24 = OpLoad %int %in_var_INDEX
1145%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1146%26 = OpLoad %_arr_v4float_uint_8 %25
1147%27 = OpCompositeExtract %v4float %26 0
1148%28 = OpCompositeExtract %v4float %26 1
1149%29 = OpCompositeExtract %v4float %26 2
1150%30 = OpCompositeExtract %v4float %26 3
1151%31 = OpCompositeExtract %v4float %26 4
1152%32 = OpCompositeExtract %v4float %26 5
1153%33 = OpCompositeExtract %v4float %26 6
1154%34 = OpCompositeExtract %v4float %26 7
1155%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1156OpStore %23 %35
1157%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1158%37 = OpLoad %v4float %36
1159      OpStore %36 %v4const
1160OpStore %out_var_SV_Target %37
1161OpReturn
1162OpFunctionEnd
1163)";
1164
1165  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1166  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1167                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1168  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1169      text, /* skip_nop = */ true, /* do_validation = */ false);
1170
1171  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1172}
1173
1174// This test does not have a proper copy of an object.  We cannot propagate in
1175// this case.
1176TEST_F(CopyPropArrayPassTest, NotACopy) {
1177  const std::string text =
1178      R"(
1179OpCapability Shader
1180OpMemoryModel Logical GLSL450
1181OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1182OpExecutionMode %main OriginUpperLeft
1183OpSource HLSL 600
1184OpName %type_MyCBuffer "type.MyCBuffer"
1185OpMemberName %type_MyCBuffer 0 "Data"
1186OpName %MyCBuffer "MyCBuffer"
1187OpName %main "main"
1188OpName %in_var_INDEX "in.var.INDEX"
1189OpName %out_var_SV_Target "out.var.SV_Target"
1190OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1191OpMemberDecorate %type_MyCBuffer 0 Offset 0
1192OpDecorate %type_MyCBuffer Block
1193OpDecorate %in_var_INDEX Flat
1194OpDecorate %in_var_INDEX Location 0
1195OpDecorate %out_var_SV_Target Location 0
1196OpDecorate %MyCBuffer DescriptorSet 0
1197OpDecorate %MyCBuffer Binding 0
1198%float = OpTypeFloat 32
1199%v4float = OpTypeVector %float 4
1200%uint = OpTypeInt 32 0
1201%uint_8 = OpConstant %uint 8
1202%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1203%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1204%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1205%void = OpTypeVoid
1206%13 = OpTypeFunction %void
1207%int = OpTypeInt 32 1
1208%_ptr_Input_int = OpTypePointer Input %int
1209%_ptr_Output_v4float = OpTypePointer Output %v4float
1210%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1211%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1212%int_0 = OpConstant %int 0
1213%f0 = OpConstant %float 0
1214%v4const = OpConstantComposite %v4float %f0 %f0 %f0 %f0
1215%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1216%_ptr_Function_v4float = OpTypePointer Function %v4float
1217%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1218%in_var_INDEX = OpVariable %_ptr_Input_int Input
1219%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1220%main = OpFunction %void None %13
1221%22 = OpLabel
1222%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1223%24 = OpLoad %int %in_var_INDEX
1224%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1225%26 = OpLoad %_arr_v4float_uint_8 %25
1226%27 = OpCompositeExtract %v4float %26 0
1227%28 = OpCompositeExtract %v4float %26 0
1228%29 = OpCompositeExtract %v4float %26 2
1229%30 = OpCompositeExtract %v4float %26 3
1230%31 = OpCompositeExtract %v4float %26 4
1231%32 = OpCompositeExtract %v4float %26 5
1232%33 = OpCompositeExtract %v4float %26 6
1233%34 = OpCompositeExtract %v4float %26 7
1234%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1235OpStore %23 %35
1236%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1237%37 = OpLoad %v4float %36
1238OpStore %out_var_SV_Target %37
1239OpReturn
1240OpFunctionEnd
1241)";
1242
1243  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1244  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1245                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1246  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1247      text, /* skip_nop = */ true, /* do_validation = */ false);
1248
1249  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1250}
1251
1252TEST_F(CopyPropArrayPassTest, BadCopyViaInserts1) {
1253  const std::string text =
1254      R"(
1255OpCapability Shader
1256OpMemoryModel Logical GLSL450
1257OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1258OpExecutionMode %main OriginUpperLeft
1259OpSource HLSL 600
1260OpName %type_MyCBuffer "type.MyCBuffer"
1261OpMemberName %type_MyCBuffer 0 "Data"
1262OpName %MyCBuffer "MyCBuffer"
1263OpName %main "main"
1264OpName %in_var_INDEX "in.var.INDEX"
1265OpName %out_var_SV_Target "out.var.SV_Target"
1266OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1267OpMemberDecorate %type_MyCBuffer 0 Offset 0
1268OpDecorate %type_MyCBuffer Block
1269OpDecorate %in_var_INDEX Flat
1270OpDecorate %in_var_INDEX Location 0
1271OpDecorate %out_var_SV_Target Location 0
1272OpDecorate %MyCBuffer DescriptorSet 0
1273OpDecorate %MyCBuffer Binding 0
1274%float = OpTypeFloat 32
1275%v4float = OpTypeVector %float 4
1276%uint = OpTypeInt 32 0
1277%uint_8 = OpConstant %uint 8
1278%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1279%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1280%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1281%void = OpTypeVoid
1282%13 = OpTypeFunction %void
1283%int = OpTypeInt 32 1
1284%_ptr_Input_int = OpTypePointer Input %int
1285%_ptr_Output_v4float = OpTypePointer Output %v4float
1286%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1287%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1288%int_0 = OpConstant %int 0
1289%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1290%_ptr_Function_v4float = OpTypePointer Function %v4float
1291%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1292%in_var_INDEX = OpVariable %_ptr_Input_int Input
1293%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1294%main = OpFunction %void None %13
1295%22 = OpLabel
1296%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1297%undef = OpUndef %_arr_v4float_uint_8_0
1298%24 = OpLoad %int %in_var_INDEX
1299%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1300%26 = OpLoad %_arr_v4float_uint_8 %25
1301%27 = OpCompositeExtract %v4float %26 0
1302%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
1303%28 = OpCompositeExtract %v4float %26 1
1304%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
1305%29 = OpCompositeExtract %v4float %26 2
1306%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 3
1307%30 = OpCompositeExtract %v4float %26 3
1308%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1309%31 = OpCompositeExtract %v4float %26 4
1310%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1311%32 = OpCompositeExtract %v4float %26 5
1312%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1313%33 = OpCompositeExtract %v4float %26 6
1314%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1315%34 = OpCompositeExtract %v4float %26 7
1316%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1317OpStore %23 %i7
1318%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1319%37 = OpLoad %v4float %36
1320OpStore %out_var_SV_Target %37
1321OpReturn
1322OpFunctionEnd
1323)";
1324
1325  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1326  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1327                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1328  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1329      text, /* skip_nop = */ true, /* do_validation = */ false);
1330
1331  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1332}
1333
1334TEST_F(CopyPropArrayPassTest, BadCopyViaInserts2) {
1335  const std::string text =
1336      R"(
1337OpCapability Shader
1338OpMemoryModel Logical GLSL450
1339OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1340OpExecutionMode %main OriginUpperLeft
1341OpSource HLSL 600
1342OpName %type_MyCBuffer "type.MyCBuffer"
1343OpMemberName %type_MyCBuffer 0 "Data"
1344OpName %MyCBuffer "MyCBuffer"
1345OpName %main "main"
1346OpName %in_var_INDEX "in.var.INDEX"
1347OpName %out_var_SV_Target "out.var.SV_Target"
1348OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1349OpMemberDecorate %type_MyCBuffer 0 Offset 0
1350OpDecorate %type_MyCBuffer Block
1351OpDecorate %in_var_INDEX Flat
1352OpDecorate %in_var_INDEX Location 0
1353OpDecorate %out_var_SV_Target Location 0
1354OpDecorate %MyCBuffer DescriptorSet 0
1355OpDecorate %MyCBuffer Binding 0
1356%float = OpTypeFloat 32
1357%v4float = OpTypeVector %float 4
1358%uint = OpTypeInt 32 0
1359%uint_8 = OpConstant %uint 8
1360%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1361%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1362%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1363%void = OpTypeVoid
1364%13 = OpTypeFunction %void
1365%int = OpTypeInt 32 1
1366%_ptr_Input_int = OpTypePointer Input %int
1367%_ptr_Output_v4float = OpTypePointer Output %v4float
1368%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1369%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1370%int_0 = OpConstant %int 0
1371%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1372%_ptr_Function_v4float = OpTypePointer Function %v4float
1373%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1374%in_var_INDEX = OpVariable %_ptr_Input_int Input
1375%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1376%main = OpFunction %void None %13
1377%22 = OpLabel
1378%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1379%undef = OpUndef %_arr_v4float_uint_8_0
1380%24 = OpLoad %int %in_var_INDEX
1381%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1382%26 = OpLoad %_arr_v4float_uint_8 %25
1383%27 = OpCompositeExtract %v4float %26 0
1384%i0 = OpCompositeInsert %_arr_v4float_uint_8_0 %27 %undef 0
1385%28 = OpCompositeExtract %v4float %26 1
1386%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %i0 1
1387%29 = OpCompositeExtract %v4float %26 3
1388%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
1389%30 = OpCompositeExtract %v4float %26 3
1390%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1391%31 = OpCompositeExtract %v4float %26 4
1392%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1393%32 = OpCompositeExtract %v4float %26 5
1394%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1395%33 = OpCompositeExtract %v4float %26 6
1396%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1397%34 = OpCompositeExtract %v4float %26 7
1398%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1399OpStore %23 %i7
1400%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1401%37 = OpLoad %v4float %36
1402OpStore %out_var_SV_Target %37
1403OpReturn
1404OpFunctionEnd
1405)";
1406
1407  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1408  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1409                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1410  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1411      text, /* skip_nop = */ true, /* do_validation = */ false);
1412
1413  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1414}
1415
1416TEST_F(CopyPropArrayPassTest, BadCopyViaInserts3) {
1417  const std::string text =
1418      R"(
1419OpCapability Shader
1420OpMemoryModel Logical GLSL450
1421OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1422OpExecutionMode %main OriginUpperLeft
1423OpSource HLSL 600
1424OpName %type_MyCBuffer "type.MyCBuffer"
1425OpMemberName %type_MyCBuffer 0 "Data"
1426OpName %MyCBuffer "MyCBuffer"
1427OpName %main "main"
1428OpName %in_var_INDEX "in.var.INDEX"
1429OpName %out_var_SV_Target "out.var.SV_Target"
1430OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1431OpMemberDecorate %type_MyCBuffer 0 Offset 0
1432OpDecorate %type_MyCBuffer Block
1433OpDecorate %in_var_INDEX Flat
1434OpDecorate %in_var_INDEX Location 0
1435OpDecorate %out_var_SV_Target Location 0
1436OpDecorate %MyCBuffer DescriptorSet 0
1437OpDecorate %MyCBuffer Binding 0
1438%float = OpTypeFloat 32
1439%v4float = OpTypeVector %float 4
1440%uint = OpTypeInt 32 0
1441%uint_8 = OpConstant %uint 8
1442%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1443%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1444%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1445%void = OpTypeVoid
1446%13 = OpTypeFunction %void
1447%int = OpTypeInt 32 1
1448%_ptr_Input_int = OpTypePointer Input %int
1449%_ptr_Output_v4float = OpTypePointer Output %v4float
1450%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1451%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1452%int_0 = OpConstant %int 0
1453%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1454%_ptr_Function_v4float = OpTypePointer Function %v4float
1455%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1456%in_var_INDEX = OpVariable %_ptr_Input_int Input
1457%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1458%main = OpFunction %void None %13
1459%22 = OpLabel
1460%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1461%undef = OpUndef %_arr_v4float_uint_8_0
1462%24 = OpLoad %int %in_var_INDEX
1463%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1464%26 = OpLoad %_arr_v4float_uint_8 %25
1465%28 = OpCompositeExtract %v4float %26 1
1466%i1 = OpCompositeInsert %_arr_v4float_uint_8_0 %28 %undef 1
1467%29 = OpCompositeExtract %v4float %26 2
1468%i2 = OpCompositeInsert %_arr_v4float_uint_8_0 %29 %i1 2
1469%30 = OpCompositeExtract %v4float %26 3
1470%i3 = OpCompositeInsert %_arr_v4float_uint_8_0 %30 %i2 3
1471%31 = OpCompositeExtract %v4float %26 4
1472%i4 = OpCompositeInsert %_arr_v4float_uint_8_0 %31 %i3 4
1473%32 = OpCompositeExtract %v4float %26 5
1474%i5 = OpCompositeInsert %_arr_v4float_uint_8_0 %32 %i4 5
1475%33 = OpCompositeExtract %v4float %26 6
1476%i6 = OpCompositeInsert %_arr_v4float_uint_8_0 %33 %i5 6
1477%34 = OpCompositeExtract %v4float %26 7
1478%i7 = OpCompositeInsert %_arr_v4float_uint_8_0 %34 %i6 7
1479OpStore %23 %i7
1480%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1481%37 = OpLoad %v4float %36
1482OpStore %out_var_SV_Target %37
1483OpReturn
1484OpFunctionEnd
1485)";
1486
1487  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1488  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1489                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1490  auto result = SinglePassRunAndDisassemble<CopyPropagateArrays>(
1491      text, /* skip_nop = */ true, /* do_validation = */ false);
1492
1493  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
1494}
1495
1496TEST_F(CopyPropArrayPassTest, AtomicAdd) {
1497  const std::string before = R"(OpCapability SampledBuffer
1498OpCapability StorageImageExtendedFormats
1499OpCapability ImageBuffer
1500OpCapability Shader
1501%1 = OpExtInstImport "GLSL.std.450"
1502OpMemoryModel Logical GLSL450
1503OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
1504OpExecutionMode %2 LocalSize 64 1 1
1505OpSource HLSL 600
1506OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
1507OpDecorate %4 DescriptorSet 4
1508OpDecorate %4 Binding 70
1509%uint = OpTypeInt 32 0
1510%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
1511%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
1512%_ptr_Function_6 = OpTypePointer Function %6
1513%void = OpTypeVoid
1514%10 = OpTypeFunction %void
1515%uint_0 = OpConstant %uint 0
1516%uint_1 = OpConstant %uint 1
1517%v3uint = OpTypeVector %uint 3
1518%_ptr_Input_v3uint = OpTypePointer Input %v3uint
1519%_ptr_Image_uint = OpTypePointer Image %uint
1520%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
1521%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
1522%2 = OpFunction %void None %10
1523%17 = OpLabel
1524%16 = OpVariable %_ptr_Function_6 Function
1525%18 = OpLoad %6 %4
1526OpStore %16 %18
1527%19 = OpImageTexelPointer %_ptr_Image_uint %16 %uint_0 %uint_0
1528%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
1529OpReturn
1530OpFunctionEnd
1531)";
1532
1533  const std::string after = R"(OpCapability SampledBuffer
1534OpCapability StorageImageExtendedFormats
1535OpCapability ImageBuffer
1536OpCapability Shader
1537%1 = OpExtInstImport "GLSL.std.450"
1538OpMemoryModel Logical GLSL450
1539OpEntryPoint GLCompute %2 "min" %gl_GlobalInvocationID
1540OpExecutionMode %2 LocalSize 64 1 1
1541OpSource HLSL 600
1542OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
1543OpDecorate %4 DescriptorSet 4
1544OpDecorate %4 Binding 70
1545%uint = OpTypeInt 32 0
1546%6 = OpTypeImage %uint Buffer 0 0 0 2 R32ui
1547%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
1548%_ptr_Function_6 = OpTypePointer Function %6
1549%void = OpTypeVoid
1550%10 = OpTypeFunction %void
1551%uint_0 = OpConstant %uint 0
1552%uint_1 = OpConstant %uint 1
1553%v3uint = OpTypeVector %uint 3
1554%_ptr_Input_v3uint = OpTypePointer Input %v3uint
1555%_ptr_Image_uint = OpTypePointer Image %uint
1556%4 = OpVariable %_ptr_UniformConstant_6 UniformConstant
1557%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
1558%2 = OpFunction %void None %10
1559%17 = OpLabel
1560%16 = OpVariable %_ptr_Function_6 Function
1561%18 = OpLoad %6 %4
1562OpStore %16 %18
1563%19 = OpImageTexelPointer %_ptr_Image_uint %4 %uint_0 %uint_0
1564%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
1565OpReturn
1566OpFunctionEnd
1567)";
1568
1569  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1570  SinglePassRunAndCheck<CopyPropagateArrays>(before, after, true, true);
1571}
1572
1573TEST_F(CopyPropArrayPassTest, IndexIsNullConstnat) {
1574  const std::string text = R"(
1575; CHECK: [[var:%\w+]] = OpVariable {{%\w+}} Uniform
1576; CHECK: [[null:%\w+]] = OpConstantNull %uint
1577; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform__arr_uint_uint_1 [[var]] %uint_0 %uint_0
1578; CHECK: OpAccessChain %_ptr_Uniform_uint [[ac1]] [[null]]
1579; CHECK-NEXT: OpReturn
1580               OpCapability Shader
1581               OpMemoryModel Logical GLSL450
1582               OpEntryPoint Fragment %main "main"
1583               OpExecutionMode %main OriginUpperLeft
1584               OpSource HLSL 600
1585               OpDecorate %myCBuffer DescriptorSet 0
1586               OpDecorate %myCBuffer Binding 0
1587               OpDecorate %_arr_v4float_uint_1 ArrayStride 16
1588               OpMemberDecorate %MyConstantBuffer 0 Offset 0
1589               OpMemberDecorate %type_myCBuffer 0 Offset 0
1590               OpDecorate %type_myCBuffer Block
1591       %uint = OpTypeInt 32 0
1592      %int_0 = OpConstant %uint 0
1593     %uint_1 = OpConstant %uint 1
1594%_arr_v4float_uint_1 = OpTypeArray %uint %uint_1
1595%MyConstantBuffer = OpTypeStruct %_arr_v4float_uint_1
1596%type_myCBuffer = OpTypeStruct %MyConstantBuffer
1597%_ptr_Uniform_type_myCBuffer = OpTypePointer Uniform %type_myCBuffer
1598%_arr_v4float_uint_1_0 = OpTypeArray %uint %uint_1
1599       %void = OpTypeVoid
1600         %19 = OpTypeFunction %void
1601%_ptr_Function_v4float = OpTypePointer Function %uint
1602%_ptr_Uniform_MyConstantBuffer = OpTypePointer Uniform %MyConstantBuffer
1603  %myCBuffer = OpVariable %_ptr_Uniform_type_myCBuffer Uniform
1604%_ptr_Function__arr_v4float_uint_1_0 = OpTypePointer Function %_arr_v4float_uint_1_0
1605         %23 = OpConstantNull %uint
1606       %main = OpFunction %void None %19
1607         %24 = OpLabel
1608         %25 = OpVariable %_ptr_Function__arr_v4float_uint_1_0 Function
1609         %26 = OpAccessChain %_ptr_Uniform_MyConstantBuffer %myCBuffer %int_0
1610         %27 = OpLoad %MyConstantBuffer %26
1611         %28 = OpCompositeExtract %_arr_v4float_uint_1 %27 0
1612         %29 = OpCompositeExtract %uint %28 0
1613         %30 = OpCompositeConstruct %_arr_v4float_uint_1_0 %29
1614               OpStore %25 %30
1615         %31 = OpAccessChain %_ptr_Function_v4float %25 %23
1616               OpReturn
1617               OpFunctionEnd
1618)";
1619
1620  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1621  SinglePassRunAndMatch<CopyPropagateArrays>(text, true);
1622}
1623
1624TEST_F(CopyPropArrayPassTest, DebugDeclare) {
1625  const std::string before =
1626      R"(OpCapability Shader
1627%ext = OpExtInstImport "OpenCL.DebugInfo.100"
1628OpMemoryModel Logical GLSL450
1629OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1630OpExecutionMode %main OriginUpperLeft
1631OpSource HLSL 600
1632%file_name = OpString "test"
1633%float_name = OpString "float"
1634%main_name = OpString "main"
1635%f_name = OpString "f"
1636OpName %type_MyCBuffer "type.MyCBuffer"
1637OpMemberName %type_MyCBuffer 0 "Data"
1638OpName %MyCBuffer "MyCBuffer"
1639OpName %main "main"
1640OpName %in_var_INDEX "in.var.INDEX"
1641OpName %out_var_SV_Target "out.var.SV_Target"
1642OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1643OpMemberDecorate %type_MyCBuffer 0 Offset 0
1644OpDecorate %type_MyCBuffer Block
1645OpDecorate %in_var_INDEX Flat
1646OpDecorate %in_var_INDEX Location 0
1647OpDecorate %out_var_SV_Target Location 0
1648OpDecorate %MyCBuffer DescriptorSet 0
1649OpDecorate %MyCBuffer Binding 0
1650%float = OpTypeFloat 32
1651%v4float = OpTypeVector %float 4
1652%uint = OpTypeInt 32 0
1653%uint_8 = OpConstant %uint 8
1654%uint_32 = OpConstant %uint 32
1655%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1656%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1657%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1658%void = OpTypeVoid
1659%13 = OpTypeFunction %void
1660%int = OpTypeInt 32 1
1661%_ptr_Input_int = OpTypePointer Input %int
1662%_ptr_Output_v4float = OpTypePointer Output %v4float
1663%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1664%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1665%int_0 = OpConstant %int 0
1666%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1667%_ptr_Function_v4float = OpTypePointer Function %v4float
1668%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1669%in_var_INDEX = OpVariable %_ptr_Input_int Input
1670%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1671%null_expr = OpExtInst %void %ext DebugExpression
1672%src = OpExtInst %void %ext DebugSource %file_name
1673%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
1674%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
1675%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
1676%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
1677
1678; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
1679; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
1680%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
1681
1682; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
1683; CHECK: OpAccessChain
1684; CHECK: [[newptr:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1685; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[newptr]] [[deref_expr]]
1686; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[newptr]] %24
1687; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
1688; CHECK: OpStore %out_var_SV_Target [[load]]
1689%main = OpFunction %void None %13
1690%22 = OpLabel
1691%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1692%24 = OpLoad %int %in_var_INDEX
1693%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1694%26 = OpLoad %_arr_v4float_uint_8 %25
1695%27 = OpCompositeExtract %v4float %26 0
1696%28 = OpCompositeExtract %v4float %26 1
1697%29 = OpCompositeExtract %v4float %26 2
1698%30 = OpCompositeExtract %v4float %26 3
1699%31 = OpCompositeExtract %v4float %26 4
1700%32 = OpCompositeExtract %v4float %26 5
1701%33 = OpCompositeExtract %v4float %26 6
1702%34 = OpCompositeExtract %v4float %26 7
1703%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1704OpStore %23 %35
1705%decl = OpExtInst %void %ext DebugDeclare %dbg_f %23 %null_expr
1706%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1707%37 = OpLoad %v4float %36
1708OpStore %out_var_SV_Target %37
1709OpReturn
1710OpFunctionEnd
1711)";
1712
1713  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1714  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1715                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1716  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
1717}
1718
1719TEST_F(CopyPropArrayPassTest, DebugValue) {
1720  const std::string before =
1721      R"(OpCapability Shader
1722%ext = OpExtInstImport "OpenCL.DebugInfo.100"
1723OpMemoryModel Logical GLSL450
1724OpEntryPoint Fragment %main "main" %in_var_INDEX %out_var_SV_Target
1725OpExecutionMode %main OriginUpperLeft
1726OpSource HLSL 600
1727%file_name = OpString "test"
1728%float_name = OpString "float"
1729%main_name = OpString "main"
1730%f_name = OpString "f"
1731OpName %type_MyCBuffer "type.MyCBuffer"
1732OpMemberName %type_MyCBuffer 0 "Data"
1733OpName %MyCBuffer "MyCBuffer"
1734OpName %main "main"
1735OpName %in_var_INDEX "in.var.INDEX"
1736OpName %out_var_SV_Target "out.var.SV_Target"
1737OpDecorate %_arr_v4float_uint_8 ArrayStride 16
1738OpMemberDecorate %type_MyCBuffer 0 Offset 0
1739OpDecorate %type_MyCBuffer Block
1740OpDecorate %in_var_INDEX Flat
1741OpDecorate %in_var_INDEX Location 0
1742OpDecorate %out_var_SV_Target Location 0
1743OpDecorate %MyCBuffer DescriptorSet 0
1744OpDecorate %MyCBuffer Binding 0
1745%float = OpTypeFloat 32
1746%v4float = OpTypeVector %float 4
1747%uint = OpTypeInt 32 0
1748%uint_8 = OpConstant %uint 8
1749%uint_32 = OpConstant %uint 32
1750%_arr_v4float_uint_8 = OpTypeArray %v4float %uint_8
1751%type_MyCBuffer = OpTypeStruct %_arr_v4float_uint_8
1752%_ptr_Uniform_type_MyCBuffer = OpTypePointer Uniform %type_MyCBuffer
1753%void = OpTypeVoid
1754%13 = OpTypeFunction %void
1755%int = OpTypeInt 32 1
1756%_ptr_Input_int = OpTypePointer Input %int
1757%_ptr_Output_v4float = OpTypePointer Output %v4float
1758%_arr_v4float_uint_8_0 = OpTypeArray %v4float %uint_8
1759%_ptr_Function__arr_v4float_uint_8_0 = OpTypePointer Function %_arr_v4float_uint_8_0
1760%int_0 = OpConstant %int 0
1761%_ptr_Uniform__arr_v4float_uint_8 = OpTypePointer Uniform %_arr_v4float_uint_8
1762%_ptr_Function_v4float = OpTypePointer Function %v4float
1763%MyCBuffer = OpVariable %_ptr_Uniform_type_MyCBuffer Uniform
1764%in_var_INDEX = OpVariable %_ptr_Input_int Input
1765%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
1766
1767; CHECK: [[deref:%\w+]] = OpExtInst %void [[ext:%\w+]] DebugOperation Deref
1768; CHECK: [[deref_expr:%\w+]] = OpExtInst %void [[ext]] DebugExpression [[deref]]
1769%deref = OpExtInst %void %ext DebugOperation Deref
1770%expr = OpExtInst %void %ext DebugExpression %deref
1771%src = OpExtInst %void %ext DebugSource %file_name
1772%cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
1773%dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
1774%main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
1775%dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
1776
1777; CHECK: [[dbg_f:%\w+]] = OpExtInst %void [[ext]] DebugLocalVariable
1778%dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
1779%main = OpFunction %void None %13
1780%22 = OpLabel
1781%23 = OpVariable %_ptr_Function__arr_v4float_uint_8_0 Function
1782%24 = OpLoad %int %in_var_INDEX
1783%25 = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1784%26 = OpLoad %_arr_v4float_uint_8 %25
1785%27 = OpCompositeExtract %v4float %26 0
1786%28 = OpCompositeExtract %v4float %26 1
1787%29 = OpCompositeExtract %v4float %26 2
1788%30 = OpCompositeExtract %v4float %26 3
1789%31 = OpCompositeExtract %v4float %26 4
1790%32 = OpCompositeExtract %v4float %26 5
1791%33 = OpCompositeExtract %v4float %26 6
1792%34 = OpCompositeExtract %v4float %26 7
1793%35 = OpCompositeConstruct %_arr_v4float_uint_8_0 %27 %28 %29 %30 %31 %32 %33 %34
1794OpStore %23 %35
1795
1796; CHECK: OpAccessChain
1797; CHECK: [[newptr:%\w+]] = OpAccessChain %_ptr_Uniform__arr_v4float_uint_8 %MyCBuffer %int_0
1798; CHECK: OpExtInst %void [[ext]] DebugValue [[dbg_f]] [[newptr]] [[deref_expr]]
1799; CHECK: [[element_ptr:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[newptr]] %24
1800; CHECK: [[load:%\w+]] = OpLoad %v4float [[element_ptr]]
1801; CHECK: OpStore %out_var_SV_Target [[load]]
1802%decl = OpExtInst %void %ext DebugValue %dbg_f %23 %expr
1803%36 = OpAccessChain %_ptr_Function_v4float %23 %24
1804%37 = OpLoad %v4float %36
1805OpStore %out_var_SV_Target %37
1806OpReturn
1807OpFunctionEnd
1808)";
1809
1810  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1811  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
1812                        SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1813  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
1814}
1815
1816TEST_F(CopyPropArrayPassTest, FunctionDeclaration) {
1817  // Make sure the pass works with a function declaration that is called.
1818  const std::string text = R"(OpCapability Addresses
1819OpCapability Linkage
1820OpCapability Kernel
1821OpCapability Int8
1822%1 = OpExtInstImport "OpenCL.std"
1823OpMemoryModel Physical64 OpenCL
1824OpEntryPoint Kernel %2 "_Z23julia__1166_kernel_77094Bool"
1825OpExecutionMode %2 ContractionOff
1826OpSource Unknown 0
1827OpDecorate %3 LinkageAttributes "julia_error_7712" Import
1828%void = OpTypeVoid
1829%5 = OpTypeFunction %void
1830%3 = OpFunction %void None %5
1831OpFunctionEnd
1832%2 = OpFunction %void None %5
1833%6 = OpLabel
1834%7 = OpFunctionCall %void %3
1835OpReturn
1836OpFunctionEnd
1837)";
1838
1839  SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
1840}
1841
1842// Since Spir-V 1.4, resources that are used by a shader must be on the
1843// OpEntryPoint instruction with the inputs and outputs. This test ensures that
1844// this does not stop the pass from working.
1845TEST_F(CopyPropArrayPassTest, EntryPointUser) {
1846  const std::string before = R"(OpCapability Shader
1847OpMemoryModel Logical GLSL450
1848OpEntryPoint GLCompute %main "main" %g_rwTexture3d
1849OpExecutionMode %main LocalSize 256 1 1
1850OpSource HLSL 660
1851OpName %type_3d_image "type.3d.image"
1852OpName %g_rwTexture3d "g_rwTexture3d"
1853OpName %main "main"
1854OpDecorate %g_rwTexture3d DescriptorSet 0
1855OpDecorate %g_rwTexture3d Binding 0
1856%uint = OpTypeInt 32 0
1857%uint_0 = OpConstant %uint 0
1858%uint_1 = OpConstant %uint 1
1859%uint_2 = OpConstant %uint 2
1860%uint_3 = OpConstant %uint 3
1861%v3uint = OpTypeVector %uint 3
1862%10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3
1863%type_3d_image = OpTypeImage %uint 3D 2 0 0 2 R32ui
1864%_ptr_UniformConstant_type_3d_image = OpTypePointer UniformConstant %type_3d_image
1865%void = OpTypeVoid
1866%13 = OpTypeFunction %void
1867%_ptr_Function_type_3d_image = OpTypePointer Function %type_3d_image
1868%_ptr_Image_uint = OpTypePointer Image %uint
1869%g_rwTexture3d = OpVariable %_ptr_UniformConstant_type_3d_image UniformConstant
1870%main = OpFunction %void None %13
1871%16 = OpLabel
1872%17 = OpVariable %_ptr_Function_type_3d_image Function
1873%18 = OpLoad %type_3d_image %g_rwTexture3d
1874OpStore %17 %18
1875; CHECK: %19 = OpImageTexelPointer %_ptr_Image_uint %g_rwTexture3d %10 %uint_0
1876%19 = OpImageTexelPointer %_ptr_Image_uint %17 %10 %uint_0
1877%20 = OpAtomicIAdd %uint %19 %uint_1 %uint_0 %uint_1
1878OpReturn
1879OpFunctionEnd
1880)";
1881
1882  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1883  SetTargetEnv(SPV_ENV_UNIVERSAL_1_4);
1884  SinglePassRunAndMatch<CopyPropagateArrays>(before, false);
1885}
1886
1887// As per SPIRV spec, struct cannot be indexed with non-constant indices
1888// through OpAccessChain, only arrays.
1889// The copy-propagate-array pass tries to remove superfluous copies when the
1890// original array could be indexed instead of the copy.
1891//
1892// This test verifies we handle this case:
1893//  struct SRC { int field1; ...; int fieldN }
1894//  int tmp_arr[N] = { SRC.field1, ..., SRC.fieldN }
1895//  return tmp_arr[index];
1896//
1897// In such case, we cannot optimize the access: this array was added to allow
1898// dynamic indexing in the struct.
1899TEST_F(CopyPropArrayPassTest, StructIndexCannotBecomeDynamic) {
1900  const std::string text = R"(OpCapability Shader
1901OpMemoryModel Logical GLSL450
1902OpEntryPoint Vertex %1 "main"
1903OpDecorate %2 DescriptorSet 0
1904OpDecorate %2 Binding 0
1905OpMemberDecorate %_struct_3 0 Offset 0
1906OpDecorate %_struct_3 Block
1907%int = OpTypeInt 32 1
1908%int_0 = OpConstant %int 0
1909%float = OpTypeFloat 32
1910%v4float = OpTypeVector %float 4
1911%_struct_3 = OpTypeStruct %v4float
1912%_ptr_Uniform__struct_3 = OpTypePointer Uniform %_struct_3
1913%uint = OpTypeInt 32 0
1914%void = OpTypeVoid
1915%11 = OpTypeFunction %void
1916%_ptr_Function_uint = OpTypePointer Function %uint
1917%13 = OpTypeFunction %v4float %_ptr_Function_uint
1918%uint_1 = OpConstant %uint 1
1919%_arr_v4float_uint_1 = OpTypeArray %v4float %uint_1
1920%_ptr_Function__arr_v4float_uint_1 = OpTypePointer Function %_arr_v4float_uint_1
1921%_ptr_Function_v4float = OpTypePointer Function %v4float
1922%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
1923%2 = OpVariable %_ptr_Uniform__struct_3 Uniform
1924%19 = OpUndef %v4float
1925%1 = OpFunction %void None %11
1926%20 = OpLabel
1927OpReturn
1928OpFunctionEnd
1929%21 = OpFunction %v4float None %13
1930%22 = OpFunctionParameter %_ptr_Function_uint
1931%23 = OpLabel
1932%24 = OpVariable %_ptr_Function__arr_v4float_uint_1 Function
1933%25 = OpAccessChain %_ptr_Uniform_v4float %2 %int_0
1934%26 = OpLoad %v4float %25
1935%27 = OpCompositeConstruct %_arr_v4float_uint_1 %26
1936OpStore %24 %27
1937%28 = OpLoad %uint %22
1938%29 = OpAccessChain %_ptr_Function_v4float %24 %28
1939OpReturnValue %19
1940OpFunctionEnd
1941)";
1942
1943  SinglePassRunAndCheck<CopyPropagateArrays>(text, text, false);
1944}
1945}  // namespace
1946}  // namespace opt
1947}  // namespace spvtools
1948