1 // Copyright (c) 2019 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 "test/opt/pass_fixture.h"
18 #include "test/opt/pass_utils.h"
19 
20 namespace spvtools {
21 namespace opt {
22 namespace {
23 
24 using DescriptorScalarReplacementTest = PassTest<::testing::Test>;
25 
GetStructureArrayTestSpirv()26 std::string GetStructureArrayTestSpirv() {
27   // The SPIR-V for the following high-level shader:
28   // Flattening structures and arrays should result in the following binding
29   // numbers. Only the ones that are actually used in the shader should be in
30   // the final SPIR-V.
31   //
32   // globalS[0][0].t[0]  0 (used)
33   // globalS[0][0].t[1]  1
34   // globalS[0][0].s[0]  2 (used)
35   // globalS[0][0].s[1]  3
36   // globalS[0][1].t[0]  4
37   // globalS[0][1].t[1]  5
38   // globalS[0][1].s[0]  6
39   // globalS[0][1].s[1]  7
40   // globalS[1][0].t[0]  8
41   // globalS[1][0].t[1]  9
42   // globalS[1][0].s[0]  10
43   // globalS[1][0].s[1]  11
44   // globalS[1][1].t[0]  12
45   // globalS[1][1].t[1]  13 (used)
46   // globalS[1][1].s[0]  14
47   // globalS[1][1].s[1]  15 (used)
48 
49   /*
50     struct S {
51       Texture2D t[2];
52       SamplerState s[2];
53     };
54 
55     S globalS[2][2];
56 
57     float4 main() : SV_Target {
58       return globalS[0][0].t[0].Sample(globalS[0][0].s[0], float2(0,0)) +
59              globalS[1][1].t[1].Sample(globalS[1][1].s[1], float2(0,0));
60     }
61   */
62 
63   return R"(
64                OpCapability Shader
65                OpMemoryModel Logical GLSL450
66                OpEntryPoint Fragment %main "main" %out_var_SV_Target
67                OpExecutionMode %main OriginUpperLeft
68                OpName %S "S"
69                OpMemberName %S 0 "t"
70                OpMemberName %S 1 "s"
71                OpName %type_2d_image "type.2d.image"
72                OpName %type_sampler "type.sampler"
73                OpName %globalS "globalS"
74                OpName %out_var_SV_Target "out.var.SV_Target"
75                OpName %main "main"
76                OpName %src_main "src.main"
77                OpName %bb_entry "bb.entry"
78                OpName %type_sampled_image "type.sampled.image"
79                OpDecorate %out_var_SV_Target Location 0
80                OpDecorate %globalS DescriptorSet 0
81                OpDecorate %globalS Binding 0
82         %int = OpTypeInt 32 1
83       %int_0 = OpConstant %int 0
84       %int_1 = OpConstant %int 1
85       %float = OpTypeFloat 32
86     %float_0 = OpConstant %float 0
87     %v2float = OpTypeVector %float 2
88          %10 = OpConstantComposite %v2float %float_0 %float_0
89        %uint = OpTypeInt 32 0
90      %uint_2 = OpConstant %uint 2
91 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
92 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
93 %type_sampler = OpTypeSampler
94 %_arr_type_sampler_uint_2 = OpTypeArray %type_sampler %uint_2
95           %S = OpTypeStruct %_arr_type_2d_image_uint_2 %_arr_type_sampler_uint_2
96 %_arr_S_uint_2 = OpTypeArray %S %uint_2
97 %_arr__arr_S_uint_2_uint_2 = OpTypeArray %_arr_S_uint_2 %uint_2
98 %_ptr_UniformConstant__arr__arr_S_uint_2_uint_2 = OpTypePointer UniformConstant %_arr__arr_S_uint_2_uint_2
99     %v4float = OpTypeVector %float 4
100 %_ptr_Output_v4float = OpTypePointer Output %v4float
101        %void = OpTypeVoid
102          %24 = OpTypeFunction %void
103          %28 = OpTypeFunction %v4float
104 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
105 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
106 %type_sampled_image = OpTypeSampledImage %type_2d_image
107     %globalS = OpVariable %_ptr_UniformConstant__arr__arr_S_uint_2_uint_2 UniformConstant
108 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
109        %main = OpFunction %void None %24
110          %25 = OpLabel
111          %26 = OpFunctionCall %v4float %src_main
112                OpStore %out_var_SV_Target %26
113                OpReturn
114                OpFunctionEnd
115    %src_main = OpFunction %v4float None %28
116    %bb_entry = OpLabel
117          %31 = OpAccessChain %_ptr_UniformConstant_type_2d_image %globalS %int_0 %int_0 %int_0 %int_0
118          %32 = OpLoad %type_2d_image %31
119          %34 = OpAccessChain %_ptr_UniformConstant_type_sampler %globalS %int_0 %int_0 %int_1 %int_0
120          %35 = OpLoad %type_sampler %34
121          %37 = OpSampledImage %type_sampled_image %32 %35
122          %38 = OpImageSampleImplicitLod %v4float %37 %10 None
123          %39 = OpAccessChain %_ptr_UniformConstant_type_2d_image %globalS %int_1 %int_1 %int_0 %int_1
124          %40 = OpLoad %type_2d_image %39
125          %41 = OpAccessChain %_ptr_UniformConstant_type_sampler %globalS %int_1 %int_1 %int_1 %int_1
126          %42 = OpLoad %type_sampler %41
127          %43 = OpSampledImage %type_sampled_image %40 %42
128          %44 = OpImageSampleImplicitLod %v4float %43 %10 None
129          %45 = OpFAdd %v4float %38 %44
130                OpReturnValue %45
131                OpFunctionEnd
132   )";
133 }
134 
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfTextures)135 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfTextures) {
136   const std::string text = R"(
137 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
138 ; CHECK: OpDecorate [[var1]] Binding 0
139 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
140 ; CHECK: OpDecorate [[var2]] Binding 1
141 ; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0
142 ; CHECK: OpDecorate [[var3]] Binding 2
143 ; CHECK: OpDecorate [[var4:%\w+]] DescriptorSet 0
144 ; CHECK: OpDecorate [[var4]] Binding 3
145 ; CHECK: OpDecorate [[var5:%\w+]] DescriptorSet 0
146 ; CHECK: OpDecorate [[var5]] Binding 4
147 ; CHECK: [[image_type:%\w+]] = OpTypeImage
148 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[image_type]]
149 ; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant
150 ; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant
151 ; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant
152 ; CHECK: [[var4]] = OpVariable [[ptr_type]] UniformConstant
153 ; CHECK: [[var5]] = OpVariable [[ptr_type]] UniformConstant
154 ; CHECK: OpLoad [[image_type]] [[var1]]
155 ; CHECK: OpLoad [[image_type]] [[var2]]
156 ; CHECK: OpLoad [[image_type]] [[var3]]
157 ; CHECK: OpLoad [[image_type]] [[var4]]
158 ; CHECK: OpLoad [[image_type]] [[var5]]
159                OpCapability Shader
160                OpMemoryModel Logical GLSL450
161                OpEntryPoint Fragment %main "main"
162                OpExecutionMode %main OriginUpperLeft
163                OpSource HLSL 600
164                OpDecorate %MyTextures DescriptorSet 0
165                OpDecorate %MyTextures Binding 0
166         %int = OpTypeInt 32 1
167       %int_0 = OpConstant %int 0
168       %int_1 = OpConstant %int 1
169       %int_2 = OpConstant %int 2
170       %int_3 = OpConstant %int 3
171       %int_4 = OpConstant %int 4
172        %uint = OpTypeInt 32 0
173      %uint_5 = OpConstant %uint 5
174       %float = OpTypeFloat 32
175 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
176 %_arr_type_2d_image_uint_5 = OpTypeArray %type_2d_image %uint_5
177 %_ptr_UniformConstant__arr_type_2d_image_uint_5 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_5
178     %v2float = OpTypeVector %float 2
179        %void = OpTypeVoid
180          %26 = OpTypeFunction %void
181 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
182  %MyTextures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_5 UniformConstant
183        %main = OpFunction %void None %26
184          %28 = OpLabel
185          %29 = OpUndef %v2float
186          %30 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_0
187          %31 = OpLoad %type_2d_image %30
188          %35 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_1
189          %36 = OpLoad %type_2d_image %35
190          %40 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_2
191          %41 = OpLoad %type_2d_image %40
192          %45 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_3
193          %46 = OpLoad %type_2d_image %45
194          %50 = OpAccessChain %_ptr_UniformConstant_type_2d_image %MyTextures %int_4
195          %51 = OpLoad %type_2d_image %50
196                OpReturn
197                OpFunctionEnd
198 
199   )";
200 
201   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
202 }
203 
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfSamplers)204 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSamplers) {
205   const std::string text = R"(
206 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
207 ; CHECK: OpDecorate [[var1]] Binding 1
208 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
209 ; CHECK: OpDecorate [[var2]] Binding 2
210 ; CHECK: OpDecorate [[var3:%\w+]] DescriptorSet 0
211 ; CHECK: OpDecorate [[var3]] Binding 3
212 ; CHECK: [[sampler_type:%\w+]] = OpTypeSampler
213 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer UniformConstant [[sampler_type]]
214 ; CHECK: [[var1]] = OpVariable [[ptr_type]] UniformConstant
215 ; CHECK: [[var2]] = OpVariable [[ptr_type]] UniformConstant
216 ; CHECK: [[var3]] = OpVariable [[ptr_type]] UniformConstant
217 ; CHECK: OpLoad [[sampler_type]] [[var1]]
218 ; CHECK: OpLoad [[sampler_type]] [[var2]]
219 ; CHECK: OpLoad [[sampler_type]] [[var3]]
220                OpCapability Shader
221                OpMemoryModel Logical GLSL450
222                OpEntryPoint Fragment %main "main"
223                OpExecutionMode %main OriginUpperLeft
224                OpSource HLSL 600
225                OpDecorate %MySampler DescriptorSet 0
226                OpDecorate %MySampler Binding 1
227         %int = OpTypeInt 32 1
228       %int_0 = OpConstant %int 0
229       %int_1 = OpConstant %int 1
230       %int_2 = OpConstant %int 2
231        %uint = OpTypeInt 32 0
232      %uint_3 = OpConstant %uint 3
233 %type_sampler = OpTypeSampler
234 %_arr_type_sampler_uint_3 = OpTypeArray %type_sampler %uint_3
235 %_ptr_UniformConstant__arr_type_sampler_uint_3 = OpTypePointer UniformConstant %_arr_type_sampler_uint_3
236        %void = OpTypeVoid
237          %26 = OpTypeFunction %void
238 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
239   %MySampler = OpVariable %_ptr_UniformConstant__arr_type_sampler_uint_3 UniformConstant
240        %main = OpFunction %void None %26
241          %28 = OpLabel
242          %31 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_0
243          %32 = OpLoad %type_sampler %31
244          %35 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_1
245          %36 = OpLoad %type_sampler %35
246          %40 = OpAccessChain %_ptr_UniformConstant_type_sampler %MySampler %int_2
247          %41 = OpLoad %type_sampler %40
248                OpReturn
249                OpFunctionEnd
250   )";
251 
252   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
253 }
254 
TEST_F(DescriptorScalarReplacementTest,ExpandArrayOfSSBOs)255 TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSSBOs) {
256   // Tests the expansion of an SSBO.  Also check that an access chain with more
257   // than 1 index is correctly handled.
258   const std::string text = R"(
259 ; CHECK: OpDecorate [[var1:%\w+]] DescriptorSet 0
260 ; CHECK: OpDecorate [[var1]] Binding 0
261 ; CHECK: OpDecorate [[var2:%\w+]] DescriptorSet 0
262 ; CHECK: OpDecorate [[var2]] Binding 1
263 ; CHECK: OpTypeStruct
264 ; CHECK: [[struct_type:%\w+]] = OpTypeStruct
265 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]]
266 ; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform
267 ; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform
268 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0
269 ; CHECK: OpLoad %v4float [[ac1]]
270 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0
271 ; CHECK: OpLoad %v4float [[ac2]]
272                OpCapability Shader
273                OpMemoryModel Logical GLSL450
274                OpEntryPoint Fragment %main "main"
275                OpExecutionMode %main OriginUpperLeft
276                OpSource HLSL 600
277                OpDecorate %buffers DescriptorSet 0
278                OpDecorate %buffers Binding 0
279                OpMemberDecorate %S 0 Offset 0
280                OpDecorate %_runtimearr_S ArrayStride 16
281                OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
282                OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
283                OpDecorate %type_StructuredBuffer_S BufferBlock
284        %uint = OpTypeInt 32 0
285      %uint_0 = OpConstant %uint 0
286       %uint_1 = OpConstant %uint 1
287      %uint_2 = OpConstant %uint 2
288       %float = OpTypeFloat 32
289     %v4float = OpTypeVector %float 4
290           %S = OpTypeStruct %v4float
291 %_runtimearr_S = OpTypeRuntimeArray %S
292 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
293 %_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2
294 %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2
295 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
296        %void = OpTypeVoid
297          %19 = OpTypeFunction %void
298 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
299     %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform
300        %main = OpFunction %void None %19
301          %21 = OpLabel
302          %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0
303          %23 = OpLoad %v4float %22
304          %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1
305          %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0
306          %26 = OpLoad %v4float %25
307                OpReturn
308                OpFunctionEnd
309   )";
310 
311   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
312 }
313 
TEST_F(DescriptorScalarReplacementTest,NameNewVariables)314 TEST_F(DescriptorScalarReplacementTest, NameNewVariables) {
315   // Checks that if the original variable has a name, then the new variables
316   // will have a name derived from that name.
317   const std::string text = R"(
318 ; CHECK: OpName [[var1:%\w+]] "SSBO[0]"
319 ; CHECK: OpName [[var2:%\w+]] "SSBO[1]"
320 ; CHECK: OpDecorate [[var1]] DescriptorSet 0
321 ; CHECK: OpDecorate [[var1]] Binding 0
322 ; CHECK: OpDecorate [[var2]] DescriptorSet 0
323 ; CHECK: OpDecorate [[var2]] Binding 1
324 ; CHECK: OpTypeStruct
325 ; CHECK: [[struct_type:%\w+]] = OpTypeStruct
326 ; CHECK: [[ptr_type:%\w+]] = OpTypePointer Uniform [[struct_type]]
327 ; CHECK: [[var1]] = OpVariable [[ptr_type]] Uniform
328 ; CHECK: [[var2]] = OpVariable [[ptr_type]] Uniform
329 ; CHECK: [[ac1:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var1]] %uint_0 %uint_0 %uint_0
330 ; CHECK: OpLoad %v4float [[ac1]]
331 ; CHECK: [[ac2:%\w+]] = OpAccessChain %_ptr_Uniform_v4float [[var2]] %uint_0 %uint_0 %uint_0
332 ; CHECK: OpLoad %v4float [[ac2]]
333                OpCapability Shader
334                OpMemoryModel Logical GLSL450
335                OpEntryPoint Fragment %main "main"
336                OpExecutionMode %main OriginUpperLeft
337                OpSource HLSL 600
338                OpName %buffers "SSBO"
339                OpDecorate %buffers DescriptorSet 0
340                OpDecorate %buffers Binding 0
341                OpMemberDecorate %S 0 Offset 0
342                OpDecorate %_runtimearr_S ArrayStride 16
343                OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
344                OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
345                OpDecorate %type_StructuredBuffer_S BufferBlock
346        %uint = OpTypeInt 32 0
347      %uint_0 = OpConstant %uint 0
348       %uint_1 = OpConstant %uint 1
349      %uint_2 = OpConstant %uint 2
350       %float = OpTypeFloat 32
351     %v4float = OpTypeVector %float 4
352           %S = OpTypeStruct %v4float
353 %_runtimearr_S = OpTypeRuntimeArray %S
354 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
355 %_arr_type_StructuredBuffer_S_uint_2 = OpTypeArray %type_StructuredBuffer_S %uint_2
356 %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 = OpTypePointer Uniform %_arr_type_StructuredBuffer_S_uint_2
357 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
358        %void = OpTypeVoid
359          %19 = OpTypeFunction %void
360 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
361     %buffers = OpVariable %_ptr_Uniform__arr_type_StructuredBuffer_S_uint_2 Uniform
362        %main = OpFunction %void None %19
363          %21 = OpLabel
364          %22 = OpAccessChain %_ptr_Uniform_v4float %buffers %uint_0 %uint_0 %uint_0 %uint_0
365          %23 = OpLoad %v4float %22
366          %24 = OpAccessChain %_ptr_Uniform_type_StructuredBuffer_S %buffers %uint_1
367          %25 = OpAccessChain %_ptr_Uniform_v4float %24 %uint_0 %uint_0 %uint_0
368          %26 = OpLoad %v4float %25
369                OpReturn
370                OpFunctionEnd
371   )";
372 
373   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
374 }
375 
TEST_F(DescriptorScalarReplacementTest,DontExpandCBuffers)376 TEST_F(DescriptorScalarReplacementTest, DontExpandCBuffers) {
377   // Checks that constant buffers are not expanded.
378   // Constant buffers are represented as global structures, but they should not
379   // be replaced with new variables for their elements.
380   /*
381     cbuffer MyCbuffer : register(b1) {
382       float2    a;
383       float2   b;
384     };
385     float main() : A {
386       return a.x + b.y;
387     }
388   */
389   const std::string text = R"(
390 ; CHECK: OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0 %int_0
391 ; CHECK: OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_1 %int_1
392                OpCapability Shader
393                OpMemoryModel Logical GLSL450
394                OpEntryPoint Vertex %main "main" %out_var_A
395                OpSource HLSL 600
396                OpName %type_MyCbuffer "type.MyCbuffer"
397                OpMemberName %type_MyCbuffer 0 "a"
398                OpMemberName %type_MyCbuffer 1 "b"
399                OpName %MyCbuffer "MyCbuffer"
400                OpName %out_var_A "out.var.A"
401                OpName %main "main"
402                OpDecorate %out_var_A Location 0
403                OpDecorate %MyCbuffer DescriptorSet 0
404                OpDecorate %MyCbuffer Binding 1
405                OpMemberDecorate %type_MyCbuffer 0 Offset 0
406                OpMemberDecorate %type_MyCbuffer 1 Offset 8
407                OpDecorate %type_MyCbuffer Block
408         %int = OpTypeInt 32 1
409       %int_0 = OpConstant %int 0
410       %int_1 = OpConstant %int 1
411       %float = OpTypeFloat 32
412     %v2float = OpTypeVector %float 2
413 %type_MyCbuffer = OpTypeStruct %v2float %v2float
414 %_ptr_Uniform_type_MyCbuffer = OpTypePointer Uniform %type_MyCbuffer
415 %_ptr_Output_float = OpTypePointer Output %float
416        %void = OpTypeVoid
417          %13 = OpTypeFunction %void
418 %_ptr_Uniform_float = OpTypePointer Uniform %float
419   %MyCbuffer = OpVariable %_ptr_Uniform_type_MyCbuffer Uniform
420   %out_var_A = OpVariable %_ptr_Output_float Output
421        %main = OpFunction %void None %13
422          %15 = OpLabel
423          %16 = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_0 %int_0
424          %17 = OpLoad %float %16
425          %18 = OpAccessChain %_ptr_Uniform_float %MyCbuffer %int_1 %int_1
426          %19 = OpLoad %float %18
427          %20 = OpFAdd %float %17 %19
428                OpStore %out_var_A %20
429                OpReturn
430                OpFunctionEnd
431 )";
432 
433   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
434 }
435 
TEST_F(DescriptorScalarReplacementTest,DontExpandStructuredBuffers)436 TEST_F(DescriptorScalarReplacementTest, DontExpandStructuredBuffers) {
437   // Checks that structured buffers are not expanded.
438   // Structured buffers are represented as global structures, that have one
439   // member which is a runtime array.
440   /*
441     struct S {
442       float2   a;
443       float2   b;
444     };
445     RWStructuredBuffer<S> sb;
446     float main() : A {
447       return sb[0].a.x + sb[0].b.x;
448     }
449   */
450   const std::string text = R"(
451 ; CHECK: OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_0 %int_0
452 ; CHECK: OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_1 %int_0
453                OpCapability Shader
454                OpMemoryModel Logical GLSL450
455                OpEntryPoint Vertex %main "main" %out_var_A
456                OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
457                OpName %S "S"
458                OpMemberName %S 0 "a"
459                OpMemberName %S 1 "b"
460                OpName %sb "sb"
461                OpName %out_var_A "out.var.A"
462                OpName %main "main"
463                OpDecorate %out_var_A Location 0
464                OpDecorate %sb DescriptorSet 0
465                OpDecorate %sb Binding 0
466                OpMemberDecorate %S 0 Offset 0
467                OpMemberDecorate %S 1 Offset 8
468                OpDecorate %_runtimearr_S ArrayStride 16
469                OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
470                OpDecorate %type_RWStructuredBuffer_S BufferBlock
471         %int = OpTypeInt 32 1
472       %int_0 = OpConstant %int 0
473        %uint = OpTypeInt 32 0
474      %uint_0 = OpConstant %uint 0
475       %int_1 = OpConstant %int 1
476       %float = OpTypeFloat 32
477     %v2float = OpTypeVector %float 2
478           %S = OpTypeStruct %v2float %v2float
479 %_runtimearr_S = OpTypeRuntimeArray %S
480 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
481 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
482 %_ptr_Output_float = OpTypePointer Output %float
483        %void = OpTypeVoid
484          %17 = OpTypeFunction %void
485 %_ptr_Uniform_float = OpTypePointer Uniform %float
486          %sb = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
487   %out_var_A = OpVariable %_ptr_Output_float Output
488        %main = OpFunction %void None %17
489          %19 = OpLabel
490          %20 = OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_0 %int_0
491          %21 = OpLoad %float %20
492          %22 = OpAccessChain %_ptr_Uniform_float %sb %int_0 %uint_0 %int_1 %int_0
493          %23 = OpLoad %float %22
494          %24 = OpFAdd %float %21 %23
495                OpStore %out_var_A %24
496                OpReturn
497                OpFunctionEnd
498 )";
499 
500   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
501 }
502 
TEST_F(DescriptorScalarReplacementTest,StructureArrayNames)503 TEST_F(DescriptorScalarReplacementTest, StructureArrayNames) {
504   // Checks that names are properly generated for multi-dimension arrays and
505   // structure members.
506   const std::string checks = R"(
507 ; CHECK: OpName %globalS_0__0__t_0_ "globalS[0][0].t[0]"
508 ; CHECK: OpName %globalS_0__0__s_0_ "globalS[0][0].s[0]"
509 ; CHECK: OpName %globalS_1__1__t_1_ "globalS[1][1].t[1]"
510 ; CHECK: OpName %globalS_1__1__s_1_ "globalS[1][1].s[1]"
511   )";
512 
513   const std::string text = checks + GetStructureArrayTestSpirv();
514   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
515 }
516 
TEST_F(DescriptorScalarReplacementTest,StructureArrayBindings)517 TEST_F(DescriptorScalarReplacementTest, StructureArrayBindings) {
518   // Checks that flattening structures and arrays results in correct binding
519   // numbers.
520   const std::string checks = R"(
521 ; CHECK: OpDecorate %globalS_0__0__t_0_ Binding 0
522 ; CHECK: OpDecorate %globalS_0__0__s_0_ Binding 2
523 ; CHECK: OpDecorate %globalS_1__1__t_1_ Binding 13
524 ; CHECK: OpDecorate %globalS_1__1__s_1_ Binding 15
525   )";
526 
527   const std::string text = checks + GetStructureArrayTestSpirv();
528   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
529 }
530 
TEST_F(DescriptorScalarReplacementTest,StructureArrayReplacements)531 TEST_F(DescriptorScalarReplacementTest, StructureArrayReplacements) {
532   // Checks that all access chains indexing into structures and/or arrays are
533   // replaced with direct access to replacement variables.
534   const std::string checks = R"(
535 ; CHECK-NOT: OpAccessChain
536 ; CHECK: OpLoad %type_2d_image %globalS_0__0__t_0_
537 ; CHECK: OpLoad %type_sampler %globalS_0__0__s_0_
538 ; CHECK: OpLoad %type_2d_image %globalS_1__1__t_1_
539 ; CHECK: OpLoad %type_sampler %globalS_1__1__s_1_
540   )";
541 
542   const std::string text = checks + GetStructureArrayTestSpirv();
543   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, true);
544 }
545 
TEST_F(DescriptorScalarReplacementTest,ResourceStructAsFunctionParam)546 TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) {
547   // Checks that a mix of OpAccessChain, OpLoad, and OpCompositeExtract patterns
548   // can be properly replaced with replacement variables.
549   // This pattern can be seen when a global structure of resources is passed to
550   // a function.
551 
552   /* High-level source:
553   // globalS[0].t[0]        binding: 0  (used)
554   // globalS[0].t[1]        binding: 1  (used)
555   // globalS[0].tt[0].s[0]  binding: 2
556   // globalS[0].tt[0].s[1]  binding: 3  (used)
557   // globalS[0].tt[0].s[2]  binding: 4
558   // globalS[0].tt[1].s[0]  binding: 5
559   // globalS[0].tt[1].s[1]  binding: 6
560   // globalS[0].tt[1].s[2]  binding: 7  (used)
561   // globalS[1].t[0]        binding: 8  (used)
562   // globalS[1].t[1]        binding: 9  (used)
563   // globalS[1].tt[0].s[0]  binding: 10
564   // globalS[1].tt[0].s[1]  binding: 11 (used)
565   // globalS[1].tt[0].s[2]  binding: 12
566   // globalS[1].tt[1].s[0]  binding: 13
567   // globalS[1].tt[1].s[1]  binding: 14
568   // globalS[1].tt[1].s[2]  binding: 15 (used)
569 
570   struct T {
571     SamplerState s[3];
572   };
573 
574   struct S {
575     Texture2D t[2];
576     T tt[2];
577   };
578 
579   float4 tex2D(S x, float2 v) {
580     return x.t[0].Sample(x.tt[0].s[1], v) + x.t[1].Sample(x.tt[1].s[2], v);
581   }
582 
583   S globalS[2];
584 
585   float4 main() : SV_Target {
586     return tex2D(globalS[0], float2(0,0)) + tex2D(globalS[1], float2(0,0)) ;
587   }
588   */
589   const std::string shader = R"(
590                OpCapability Shader
591                OpMemoryModel Logical GLSL450
592                OpEntryPoint Fragment %main "main" %out_var_SV_Target
593                OpExecutionMode %main OriginUpperLeft
594                OpName %S "S"
595                OpMemberName %S 0 "t"
596                OpMemberName %S 1 "tt"
597                OpName %type_2d_image "type.2d.image"
598                OpName %T "T"
599                OpMemberName %T 0 "s"
600                OpName %type_sampler "type.sampler"
601                OpName %globalS "globalS"
602                OpName %out_var_SV_Target "out.var.SV_Target"
603                OpName %main "main"
604                OpName %type_sampled_image "type.sampled.image"
605                OpDecorate %out_var_SV_Target Location 0
606                OpDecorate %globalS DescriptorSet 0
607                OpDecorate %globalS Binding 0
608         %int = OpTypeInt 32 1
609       %int_0 = OpConstant %int 0
610       %float = OpTypeFloat 32
611     %float_0 = OpConstant %float 0
612     %v2float = OpTypeVector %float 2
613          %14 = OpConstantComposite %v2float %float_0 %float_0
614       %int_1 = OpConstant %int 1
615        %uint = OpTypeInt 32 0
616      %uint_2 = OpConstant %uint 2
617 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
618 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
619      %uint_3 = OpConstant %uint 3
620 %type_sampler = OpTypeSampler
621 %_arr_type_sampler_uint_3 = OpTypeArray %type_sampler %uint_3
622           %T = OpTypeStruct %_arr_type_sampler_uint_3
623 %_arr_T_uint_2 = OpTypeArray %T %uint_2
624           %S = OpTypeStruct %_arr_type_2d_image_uint_2 %_arr_T_uint_2
625 %_arr_S_uint_2 = OpTypeArray %S %uint_2
626 %_ptr_UniformConstant__arr_S_uint_2 = OpTypePointer UniformConstant %_arr_S_uint_2
627     %v4float = OpTypeVector %float 4
628 %_ptr_Output_v4float = OpTypePointer Output %v4float
629        %void = OpTypeVoid
630          %27 = OpTypeFunction %void
631 %_ptr_UniformConstant_S = OpTypePointer UniformConstant %S
632 %type_sampled_image = OpTypeSampledImage %type_2d_image
633     %globalS = OpVariable %_ptr_UniformConstant__arr_S_uint_2 UniformConstant
634 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
635        %main = OpFunction %void None %27
636          %29 = OpLabel
637          %30 = OpAccessChain %_ptr_UniformConstant_S %globalS %int_0
638          %31 = OpLoad %S %30
639          %32 = OpCompositeExtract %_arr_type_2d_image_uint_2 %31 0
640          %33 = OpCompositeExtract %type_2d_image %32 0
641          %34 = OpCompositeExtract %type_2d_image %32 1
642          %35 = OpCompositeExtract %_arr_T_uint_2 %31 1
643          %36 = OpCompositeExtract %T %35 0
644          %37 = OpCompositeExtract %_arr_type_sampler_uint_3 %36 0
645          %38 = OpCompositeExtract %type_sampler %37 1
646          %39 = OpCompositeExtract %T %35 1
647          %40 = OpCompositeExtract %_arr_type_sampler_uint_3 %39 0
648          %41 = OpCompositeExtract %type_sampler %40 2
649          %42 = OpSampledImage %type_sampled_image %33 %38
650          %43 = OpImageSampleImplicitLod %v4float %42 %14 None
651          %44 = OpSampledImage %type_sampled_image %34 %41
652          %45 = OpImageSampleImplicitLod %v4float %44 %14 None
653          %46 = OpFAdd %v4float %43 %45
654          %47 = OpAccessChain %_ptr_UniformConstant_S %globalS %int_1
655          %48 = OpLoad %S %47
656          %49 = OpCompositeExtract %_arr_type_2d_image_uint_2 %48 0
657          %50 = OpCompositeExtract %type_2d_image %49 0
658          %51 = OpCompositeExtract %type_2d_image %49 1
659          %52 = OpCompositeExtract %_arr_T_uint_2 %48 1
660          %53 = OpCompositeExtract %T %52 0
661          %54 = OpCompositeExtract %_arr_type_sampler_uint_3 %53 0
662          %55 = OpCompositeExtract %type_sampler %54 1
663          %56 = OpCompositeExtract %T %52 1
664          %57 = OpCompositeExtract %_arr_type_sampler_uint_3 %56 0
665          %58 = OpCompositeExtract %type_sampler %57 2
666          %59 = OpSampledImage %type_sampled_image %50 %55
667          %60 = OpImageSampleImplicitLod %v4float %59 %14 None
668          %61 = OpSampledImage %type_sampled_image %51 %58
669          %62 = OpImageSampleImplicitLod %v4float %61 %14 None
670          %63 = OpFAdd %v4float %60 %62
671          %64 = OpFAdd %v4float %46 %63
672                OpStore %out_var_SV_Target %64
673                OpReturn
674                OpFunctionEnd
675 )";
676 
677   const std::string checks = R"(
678 ; CHECK: OpName %globalS_0__t_0_ "globalS[0].t[0]"
679 ; CHECK: OpName %globalS_0__t_1_ "globalS[0].t[1]"
680 ; CHECK: OpName %globalS_1__t_0_ "globalS[1].t[0]"
681 ; CHECK: OpName %globalS_1__t_1_ "globalS[1].t[1]"
682 ; CHECK: OpName %globalS_0__tt_0__s_1_ "globalS[0].tt[0].s[1]"
683 ; CHECK: OpName %globalS_0__tt_1__s_2_ "globalS[0].tt[1].s[2]"
684 ; CHECK: OpName %globalS_1__tt_0__s_1_ "globalS[1].tt[0].s[1]"
685 ; CHECK: OpName %globalS_1__tt_1__s_2_ "globalS[1].tt[1].s[2]"
686 ; CHECK: OpDecorate %globalS_0__t_0_ Binding 0
687 ; CHECK: OpDecorate %globalS_0__t_1_ Binding 1
688 ; CHECK: OpDecorate %globalS_1__t_0_ Binding 8
689 ; CHECK: OpDecorate %globalS_1__t_1_ Binding 9
690 ; CHECK: OpDecorate %globalS_0__tt_0__s_1_ Binding 3
691 ; CHECK: OpDecorate %globalS_0__tt_1__s_2_ Binding 7
692 ; CHECK: OpDecorate %globalS_1__tt_0__s_1_ Binding 11
693 ; CHECK: OpDecorate %globalS_1__tt_1__s_2_ Binding 15
694 
695 ; CHECK: %globalS_0__t_0_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
696 ; CHECK: %globalS_0__t_1_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
697 ; CHECK: %globalS_1__t_0_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
698 ; CHECK: %globalS_1__t_1_ = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
699 ; CHECK: %globalS_0__tt_0__s_1_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
700 ; CHECK: %globalS_0__tt_1__s_2_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
701 ; CHECK: %globalS_1__tt_0__s_1_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
702 ; CHECK: %globalS_1__tt_1__s_2_ = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
703 
704 ; CHECK:     [[img_1:%\w+]] = OpLoad %type_2d_image %globalS_0__t_0_
705 ; CHECK:     [[img_2:%\w+]] = OpLoad %type_2d_image %globalS_0__t_1_
706 ; CHECK: [[sampler_1:%\w+]] = OpLoad %type_sampler %globalS_0__tt_0__s_1_
707 ; CHECK: [[sampler_2:%\w+]] = OpLoad %type_sampler %globalS_0__tt_1__s_2_
708 
709 ; CHECK: [[sampled_img_1:%\w+]] = OpSampledImage %type_sampled_image [[img_1]] [[sampler_1]]
710 ; CHECK:      [[sample_1:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_1]]
711 ; CHECK: [[sampled_img_2:%\w+]] = OpSampledImage %type_sampled_image [[img_2]] [[sampler_2]]
712 ; CHECK:      [[sample_2:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_2]]
713 ; CHECK:                          OpFAdd %v4float [[sample_1]] [[sample_2]]
714 
715 ; CHECK:     [[img_3:%\w+]] = OpLoad %type_2d_image %globalS_1__t_0_
716 ; CHECK:     [[img_4:%\w+]] = OpLoad %type_2d_image %globalS_1__t_1_
717 ; CHECK: [[sampler_3:%\w+]] = OpLoad %type_sampler %globalS_1__tt_0__s_1_
718 ; CHECK: [[sampler_4:%\w+]] = OpLoad %type_sampler %globalS_1__tt_1__s_2_
719 
720 ; CHECK: [[sampled_img_3:%\w+]] = OpSampledImage %type_sampled_image [[img_3]] [[sampler_3]]
721 ; CHECK:      [[sample_3:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_3]]
722 ; CHECK: [[sampled_img_4:%\w+]] = OpSampledImage %type_sampled_image [[img_4]] [[sampler_4]]
723 ; CHECK:      [[sample_4:%\w+]] = OpImageSampleImplicitLod %v4float [[sampled_img_4]]
724 ; CHECK:                          OpFAdd %v4float [[sample_3]] [[sample_4]]
725 )";
726 
727   SinglePassRunAndMatch<DescriptorScalarReplacement>(checks + shader, true);
728 }
729 
TEST_F(DescriptorScalarReplacementTest,BindingForResourceArrayOfStructs)730 TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) {
731   // Check that correct binding numbers are given to an array of descriptors
732   // to structs.
733 
734   const std::string shader = R"(
735 ; CHECK: OpDecorate {{%\w+}} Binding 0
736 ; CHECK: OpDecorate {{%\w+}} Binding 1
737                OpCapability Shader
738           %1 = OpExtInstImport "GLSL.std.450"
739                OpMemoryModel Logical GLSL450
740                OpEntryPoint Fragment %2 "psmain"
741                OpExecutionMode %2 OriginUpperLeft
742                OpDecorate %5 DescriptorSet 0
743                OpDecorate %5 Binding 0
744                OpMemberDecorate %_struct_4 0 Offset 0
745                OpMemberDecorate %_struct_4 1 Offset 4
746                OpDecorate %_struct_4 Block
747       %float = OpTypeFloat 32
748         %int = OpTypeInt 32 1
749       %int_0 = OpConstant %int 0
750       %int_1 = OpConstant %int 1
751        %uint = OpTypeInt 32 0
752      %uint_2 = OpConstant %uint 2
753   %_struct_4 = OpTypeStruct %float %int
754 %_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
755 %_ptr_Uniform__arr__struct_4_uint_2 = OpTypePointer Uniform %_arr__struct_4_uint_2
756        %void = OpTypeVoid
757          %25 = OpTypeFunction %void
758 %_ptr_Uniform_int = OpTypePointer Uniform %int
759           %5 = OpVariable %_ptr_Uniform__arr__struct_4_uint_2 Uniform
760           %2 = OpFunction %void None %25
761          %29 = OpLabel
762          %40 = OpAccessChain %_ptr_Uniform_int %5 %int_0 %int_1
763          %41 = OpAccessChain %_ptr_Uniform_int %5 %int_1 %int_1
764                OpReturn
765                OpFunctionEnd
766 )";
767 
768   SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
769 }
770 
TEST_F(DescriptorScalarReplacementTest,MemberDecorationForResourceStruct)771 TEST_F(DescriptorScalarReplacementTest, MemberDecorationForResourceStruct) {
772   // Check that an OpMemberDecorate instruction is correctly converted to a
773   // OpDecorate instruction.
774 
775   const std::string shader = R"(
776 ; CHECK: OpDecorate [[t:%\w+]] DescriptorSet 0
777 ; CHECK: OpDecorate [[t]] Binding 0
778 ; CHECK: OpDecorate [[t]] RelaxedPrecision
779 ; CHECK: OpDecorate [[s:%\w+]] DescriptorSet 0
780 ; CHECK: OpDecorate [[s]] Binding 1
781                OpCapability Shader
782                OpMemoryModel Logical GLSL450
783                OpEntryPoint Fragment %PSMain "PSMain" %in_var_TEXCOORD %out_var_SV_Target
784                OpExecutionMode %PSMain OriginUpperLeft
785                OpSource HLSL 600
786                OpName %sampler2D_h "sampler2D_h"
787                OpMemberName %sampler2D_h 0 "t"
788                OpMemberName %sampler2D_h 1 "s"
789                OpName %type_2d_image "type.2d.image"
790                OpName %type_sampler "type.sampler"
791                OpName %_MainTex "_MainTex"
792                OpName %in_var_TEXCOORD "in.var.TEXCOORD"
793                OpName %out_var_SV_Target "out.var.SV_Target"
794                OpName %PSMain "PSMain"
795                OpName %type_sampled_image "type.sampled.image"
796                OpDecorate %in_var_TEXCOORD Location 0
797                OpDecorate %out_var_SV_Target Location 0
798                OpDecorate %_MainTex DescriptorSet 0
799                OpDecorate %_MainTex Binding 0
800                OpMemberDecorate %sampler2D_h 0 RelaxedPrecision
801                OpDecorate %out_var_SV_Target RelaxedPrecision
802                OpDecorate %69 RelaxedPrecision
803       %float = OpTypeFloat 32
804 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
805 %type_sampler = OpTypeSampler
806 %sampler2D_h = OpTypeStruct %type_2d_image %type_sampler
807 %_ptr_UniformConstant_sampler2D_h = OpTypePointer UniformConstant %sampler2D_h
808     %v2float = OpTypeVector %float 2
809 %_ptr_Input_v2float = OpTypePointer Input %v2float
810     %v4float = OpTypeVector %float 4
811 %_ptr_Output_v4float = OpTypePointer Output %v4float
812        %void = OpTypeVoid
813          %35 = OpTypeFunction %void
814 %type_sampled_image = OpTypeSampledImage %type_2d_image
815    %_MainTex = OpVariable %_ptr_UniformConstant_sampler2D_h UniformConstant
816 %in_var_TEXCOORD = OpVariable %_ptr_Input_v2float Input
817 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
818      %PSMain = OpFunction %void None %35
819          %43 = OpLabel
820          %44 = OpLoad %v2float %in_var_TEXCOORD
821          %57 = OpLoad %sampler2D_h %_MainTex
822          %72 = OpCompositeExtract %type_2d_image %57 0
823          %73 = OpCompositeExtract %type_sampler %57 1
824          %68 = OpSampledImage %type_sampled_image %72 %73
825          %69 = OpImageSampleImplicitLod %v4float %68 %44 None
826                OpStore %out_var_SV_Target %69
827                OpReturn
828                OpFunctionEnd
829 )";
830 
831   SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
832 }
833 
TEST_F(DescriptorScalarReplacementTest,DecorateStringForReflect)834 TEST_F(DescriptorScalarReplacementTest, DecorateStringForReflect) {
835   // Check that an OpDecorateString instruction is correctly cloned to new
836   // variable.
837 
838   const std::string shader = R"(
839 ; CHECK: OpName %g_testTextures_0_ "g_testTextures[0]"
840 ; CHECK: OpDecorate %g_testTextures_0_ DescriptorSet 0
841 ; CHECK: OpDecorate %g_testTextures_0_ Binding 0
842 ; CHECK: OpDecorateString %g_testTextures_0_ UserTypeGOOGLE "texture2d"
843                OpCapability Shader
844                OpExtension "SPV_GOOGLE_hlsl_functionality1"
845                OpExtension "SPV_GOOGLE_user_type"
846                OpMemoryModel Logical GLSL450
847                OpEntryPoint Fragment %main "main" %gl_FragCoord %out_var_SV_Target
848                OpExecutionMode %main OriginUpperLeft
849                OpSource HLSL 600
850                OpName %type_2d_image "type.2d.image"
851                OpName %g_testTextures "g_testTextures"
852                OpName %out_var_SV_Target "out.var.SV_Target"
853                OpName %main "main"
854                OpName %param_var_vPixelPos "param.var.vPixelPos"
855                OpName %src_main "src.main"
856                OpName %vPixelPos "vPixelPos"
857                OpName %bb_entry "bb.entry"
858                OpDecorate %gl_FragCoord BuiltIn FragCoord
859                OpDecorateString %gl_FragCoord UserSemantic "SV_Position"
860                OpDecorateString %out_var_SV_Target UserSemantic "SV_Target"
861                OpDecorate %out_var_SV_Target Location 0
862                OpDecorate %g_testTextures DescriptorSet 0
863                OpDecorate %g_testTextures Binding 0
864                OpDecorateString %g_testTextures UserTypeGOOGLE "texture2d"
865        %uint = OpTypeInt 32 0
866      %uint_0 = OpConstant %uint 0
867         %int = OpTypeInt 32 1
868       %int_0 = OpConstant %int 0
869      %uint_2 = OpConstant %uint 2
870       %float = OpTypeFloat 32
871 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
872 %_arr_type_2d_image_uint_2 = OpTypeArray %type_2d_image %uint_2
873 %_ptr_UniformConstant__arr_type_2d_image_uint_2 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_2
874     %v4float = OpTypeVector %float 4
875 %_ptr_Input_v4float = OpTypePointer Input %v4float
876 %_ptr_Output_v4float = OpTypePointer Output %v4float
877        %void = OpTypeVoid
878          %18 = OpTypeFunction %void
879 %_ptr_Function_v4float = OpTypePointer Function %v4float
880          %25 = OpTypeFunction %v4float %_ptr_Function_v4float
881     %v2float = OpTypeVector %float 2
882      %v3uint = OpTypeVector %uint 3
883       %v3int = OpTypeVector %int 3
884       %v2int = OpTypeVector %int 2
885 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
886 %g_testTextures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_2 UniformConstant
887 %gl_FragCoord = OpVariable %_ptr_Input_v4float Input
888 %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output
889        %main = OpFunction %void None %18
890          %19 = OpLabel
891 %param_var_vPixelPos = OpVariable %_ptr_Function_v4float Function
892          %22 = OpLoad %v4float %gl_FragCoord
893                OpStore %param_var_vPixelPos %22
894          %23 = OpFunctionCall %v4float %src_main %param_var_vPixelPos
895                OpStore %out_var_SV_Target %23
896                OpReturn
897                OpFunctionEnd
898    %src_main = OpFunction %v4float None %25
899   %vPixelPos = OpFunctionParameter %_ptr_Function_v4float
900    %bb_entry = OpLabel
901          %28 = OpLoad %v4float %vPixelPos
902          %30 = OpVectorShuffle %v2float %28 %28 0 1
903          %31 = OpCompositeExtract %float %30 0
904          %32 = OpCompositeExtract %float %30 1
905          %33 = OpConvertFToU %uint %31
906          %34 = OpConvertFToU %uint %32
907          %36 = OpCompositeConstruct %v3uint %33 %34 %uint_0
908          %38 = OpBitcast %v3int %36
909          %40 = OpVectorShuffle %v2int %38 %38 0 1
910          %41 = OpCompositeExtract %int %38 2
911          %43 = OpAccessChain %_ptr_UniformConstant_type_2d_image %g_testTextures %int_0
912          %44 = OpLoad %type_2d_image %43
913          %45 = OpImageFetch %v4float %44 %40 Lod %41
914                OpReturnValue %45
915                OpFunctionEnd
916 )";
917 
918   SinglePassRunAndMatch<DescriptorScalarReplacement>(shader, true);
919 }
920 
TEST_F(DescriptorScalarReplacementTest,ExpandArrayInOpEntryPoint)921 TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) {
922   const std::string text = R"(; SPIR-V
923 ; Version: 1.6
924 ; Bound: 31
925 ; Schema: 0
926                OpCapability Shader
927                OpMemoryModel Logical GLSL450
928 
929 ; CHECK:       OpEntryPoint GLCompute %main "main" %output_0_ %output_1_
930 
931                OpEntryPoint GLCompute %main "main" %output
932                OpExecutionMode %main LocalSize 1 1 1
933                OpSource HLSL 670
934                OpName %type_RWByteAddressBuffer "type.RWByteAddressBuffer"
935                OpName %output "output"
936                OpName %main "main"
937                OpName %src_main "src.main"
938                OpName %bb_entry "bb.entry"
939 
940 ; CHECK:       OpDecorate %output_1_ DescriptorSet 0
941 ; CHECK:       OpDecorate %output_1_ Binding 1
942 ; CHECK:       OpDecorate %output_0_ DescriptorSet 0
943 ; CHECK:       OpDecorate %output_0_ Binding 0
944 
945                OpDecorate %output DescriptorSet 0
946                OpDecorate %output Binding 0
947 
948                OpDecorate %_runtimearr_uint ArrayStride 4
949                OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0
950                OpDecorate %type_RWByteAddressBuffer Block
951         %int = OpTypeInt 32 1
952       %int_1 = OpConstant %int 1
953        %uint = OpTypeInt 32 0
954      %uint_0 = OpConstant %uint 0
955      %uint_2 = OpConstant %uint 2
956     %uint_32 = OpConstant %uint 32
957 %_runtimearr_uint = OpTypeRuntimeArray %uint
958 %type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint
959 %_arr_type_RWByteAddressBuffer_uint_2 = OpTypeArray %type_RWByteAddressBuffer %uint_2
960 %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 = OpTypePointer StorageBuffer %_arr_type_RWByteAddressBuffer_uint_2
961        %void = OpTypeVoid
962          %23 = OpTypeFunction %void
963 %_ptr_StorageBuffer_type_RWByteAddressBuffer = OpTypePointer StorageBuffer %type_RWByteAddressBuffer
964 %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
965 
966 ; CHECK: %output_1_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
967 ; CHECK: %output_0_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer
968 
969      %output = OpVariable %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 StorageBuffer
970 
971        %main = OpFunction %void None %23
972          %26 = OpLabel
973          %27 = OpFunctionCall %void %src_main
974                OpReturn
975                OpFunctionEnd
976    %src_main = OpFunction %void None %23
977    %bb_entry = OpLabel
978          %28 = OpAccessChain %_ptr_StorageBuffer_type_RWByteAddressBuffer %output %int_1
979          %29 = OpShiftRightLogical %uint %uint_0 %uint_2
980          %30 = OpAccessChain %_ptr_StorageBuffer_uint %28 %uint_0 %29
981                OpStore %30 %uint_32
982                OpReturn
983                OpFunctionEnd
984   )";
985 
986   SinglePassRunAndMatch<DescriptorScalarReplacement>(text, false);
987 }
988 
989 }  // namespace
990 }  // namespace opt
991 }  // namespace spvtools
992