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 "test/opt/pass_fixture.h"
18 #include "test/opt/pass_utils.h"
19
20 namespace spvtools {
21 namespace opt {
22 namespace {
23
24 using ReduceLoadSizeTest = PassTest<::testing::Test>;
25
TEST_F(ReduceLoadSizeTest,cbuffer_load_extract)26 TEST_F(ReduceLoadSizeTest, cbuffer_load_extract) {
27 // Originally from the following HLSL:
28 // struct S {
29 // uint f;
30 // };
31 //
32 //
33 // cbuffer gBuffer { uint a[32]; };
34 //
35 // RWStructuredBuffer<S> gRWSBuffer;
36 //
37 // uint foo(uint p[32]) {
38 // return p[1];
39 // }
40 //
41 // [numthreads(1,1,1)]
42 // void main() {
43 // gRWSBuffer[0].f = foo(a);
44 // }
45 const std::string test =
46 R"(
47 OpCapability Shader
48 OpMemoryModel Logical GLSL450
49 OpEntryPoint GLCompute %main "main"
50 OpExecutionMode %main LocalSize 1 1 1
51 OpSource HLSL 600
52 OpName %type_gBuffer "type.gBuffer"
53 OpMemberName %type_gBuffer 0 "a"
54 OpName %gBuffer "gBuffer"
55 OpName %S "S"
56 OpMemberName %S 0 "f"
57 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
58 OpName %gRWSBuffer "gRWSBuffer"
59 OpName %main "main"
60 OpDecorate %_arr_uint_uint_32 ArrayStride 16
61 OpMemberDecorate %type_gBuffer 0 Offset 0
62 OpDecorate %type_gBuffer Block
63 OpMemberDecorate %S 0 Offset 0
64 OpDecorate %_runtimearr_S ArrayStride 4
65 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
66 OpDecorate %type_RWStructuredBuffer_S BufferBlock
67 OpDecorate %gBuffer DescriptorSet 0
68 OpDecorate %gBuffer Binding 0
69 OpDecorate %gRWSBuffer DescriptorSet 0
70 OpDecorate %gRWSBuffer Binding 1
71 %uint = OpTypeInt 32 0
72 %uint_32 = OpConstant %uint 32
73 %_arr_uint_uint_32 = OpTypeArray %uint %uint_32
74 %type_gBuffer = OpTypeStruct %_arr_uint_uint_32
75 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
76 %S = OpTypeStruct %uint
77 %_runtimearr_S = OpTypeRuntimeArray %S
78 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
79 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
80 %int = OpTypeInt 32 1
81 %void = OpTypeVoid
82 %15 = OpTypeFunction %void
83 %int_0 = OpConstant %int 0
84 %_ptr_Uniform__arr_uint_uint_32 = OpTypePointer Uniform %_arr_uint_uint_32
85 %uint_0 = OpConstant %uint 0
86 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
87 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
88 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
89 %main = OpFunction %void None %15
90 %20 = OpLabel
91 ; CHECK: [[ac1:%\w+]] = OpAccessChain {{%\w+}} %gBuffer %int_0
92 ; CHECK: [[ac2:%\w+]] = OpAccessChain {{%\w+}} [[ac1]] %uint_1
93 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[ac2]]
94 ; CHECK: OpStore {{%\w+}} [[ld]]
95 %21 = OpAccessChain %_ptr_Uniform__arr_uint_uint_32 %gBuffer %int_0
96 %22 = OpLoad %_arr_uint_uint_32 %21 ; Load of 32-element array.
97 %23 = OpCompositeExtract %uint %22 1
98 %24 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
99 OpStore %24 %23
100 OpReturn
101 OpFunctionEnd
102 )";
103
104 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
105 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
106 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
107 SinglePassRunAndMatch<ReduceLoadSize>(test, false);
108 }
109
TEST_F(ReduceLoadSizeTest,cbuffer_load_extract_not_affected_by_debug_instr)110 TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_not_affected_by_debug_instr) {
111 // Originally from the following HLSL:
112 // struct S {
113 // uint f;
114 // };
115 //
116 //
117 // cbuffer gBuffer { uint a[32]; };
118 //
119 // RWStructuredBuffer<S> gRWSBuffer;
120 //
121 // uint foo(uint p[32]) {
122 // return p[1];
123 // }
124 //
125 // [numthreads(1,1,1)]
126 // void main() {
127 // gRWSBuffer[0].f = foo(a);
128 // }
129 const std::string test =
130 R"(
131 OpCapability Shader
132 %ext = OpExtInstImport "OpenCL.DebugInfo.100"
133 OpMemoryModel Logical GLSL450
134 OpEntryPoint GLCompute %main "main"
135 OpExecutionMode %main LocalSize 1 1 1
136 OpSource HLSL 600
137 %file_name = OpString "test"
138 %float_name = OpString "float"
139 %main_name = OpString "main"
140 %f_name = OpString "f"
141 OpName %type_gBuffer "type.gBuffer"
142 OpMemberName %type_gBuffer 0 "a"
143 OpName %gBuffer "gBuffer"
144 OpName %S "S"
145 OpMemberName %S 0 "f"
146 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
147 OpName %gRWSBuffer "gRWSBuffer"
148 OpName %main "main"
149 OpDecorate %_arr_uint_uint_32 ArrayStride 16
150 OpMemberDecorate %type_gBuffer 0 Offset 0
151 OpDecorate %type_gBuffer Block
152 OpMemberDecorate %S 0 Offset 0
153 OpDecorate %_runtimearr_S ArrayStride 4
154 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
155 OpDecorate %type_RWStructuredBuffer_S BufferBlock
156 OpDecorate %gBuffer DescriptorSet 0
157 OpDecorate %gBuffer Binding 0
158 OpDecorate %gRWSBuffer DescriptorSet 0
159 OpDecorate %gRWSBuffer Binding 1
160 %uint = OpTypeInt 32 0
161 %uint_32 = OpConstant %uint 32
162 %_arr_uint_uint_32 = OpTypeArray %uint %uint_32
163 %type_gBuffer = OpTypeStruct %_arr_uint_uint_32
164 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
165 %S = OpTypeStruct %uint
166 %_runtimearr_S = OpTypeRuntimeArray %S
167 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
168 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
169 %int = OpTypeInt 32 1
170 %void = OpTypeVoid
171 %15 = OpTypeFunction %void
172 %int_0 = OpConstant %int 0
173 %_ptr_Uniform__arr_uint_uint_32 = OpTypePointer Uniform %_arr_uint_uint_32
174 %uint_0 = OpConstant %uint 0
175 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
176 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
177 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
178 %null_expr = OpExtInst %void %ext DebugExpression
179 %src = OpExtInst %void %ext DebugSource %file_name
180 %cu = OpExtInst %void %ext DebugCompilationUnit 1 4 %src HLSL
181 %dbg_tf = OpExtInst %void %ext DebugTypeBasic %float_name %uint_32 Float
182 %main_ty = OpExtInst %void %ext DebugTypeFunction FlagIsProtected|FlagIsPrivate %dbg_tf
183 %dbg_main = OpExtInst %void %ext DebugFunction %main_name %main_ty %src 0 0 %cu %main_name FlagIsProtected|FlagIsPrivate 10 %main
184 %dbg_f = OpExtInst %void %ext DebugLocalVariable %f_name %dbg_tf %src 0 0 %dbg_main FlagIsLocal
185 %main = OpFunction %void None %15
186 %20 = OpLabel
187 %s = OpExtInst %void %ext DebugScope %dbg_main
188 ; CHECK: [[ac1:%\w+]] = OpAccessChain {{%\w+}} %gBuffer %int_0
189 ; CHECK: [[ac2:%\w+]] = OpAccessChain {{%\w+}} [[ac1]] %uint_1
190 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[ac2]]
191 ; CHECK: OpStore {{%\w+}} [[ld]]
192 %21 = OpAccessChain %_ptr_Uniform__arr_uint_uint_32 %gBuffer %int_0
193 %22 = OpLoad %_arr_uint_uint_32 %21 ; Load of 32-element array.
194 %value = OpExtInst %void %ext DebugValue %dbg_f %22 %null_expr
195 %23 = OpCompositeExtract %uint %22 1
196 %24 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
197 OpStore %24 %23
198 OpReturn
199 OpFunctionEnd
200 )";
201
202 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
203 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
204 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
205 SinglePassRunAndMatch<ReduceLoadSize>(test, false);
206 }
207
TEST_F(ReduceLoadSizeTest,cbuffer_load_extract_vector)208 TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_vector) {
209 // Originally from the following HLSL:
210 // struct S {
211 // uint f;
212 // };
213 //
214 //
215 // cbuffer gBuffer { uint4 a; };
216 //
217 // RWStructuredBuffer<S> gRWSBuffer;
218 //
219 // uint foo(uint p[32]) {
220 // return p[1];
221 // }
222 //
223 // [numthreads(1,1,1)]
224 // void main() {
225 // gRWSBuffer[0].f = foo(a);
226 // }
227 const std::string test =
228 R"(OpCapability Shader
229 OpMemoryModel Logical GLSL450
230 OpEntryPoint GLCompute %main "main"
231 OpExecutionMode %main LocalSize 1 1 1
232 OpSource HLSL 600
233 OpName %type_gBuffer "type.gBuffer"
234 OpMemberName %type_gBuffer 0 "a"
235 OpName %gBuffer "gBuffer"
236 OpName %S "S"
237 OpMemberName %S 0 "f"
238 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
239 OpName %gRWSBuffer "gRWSBuffer"
240 OpName %main "main"
241 OpMemberDecorate %type_gBuffer 0 Offset 0
242 OpDecorate %type_gBuffer Block
243 OpMemberDecorate %S 0 Offset 0
244 OpDecorate %_runtimearr_S ArrayStride 4
245 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
246 OpDecorate %type_RWStructuredBuffer_S BufferBlock
247 OpDecorate %gBuffer DescriptorSet 0
248 OpDecorate %gBuffer Binding 0
249 OpDecorate %gRWSBuffer DescriptorSet 0
250 OpDecorate %gRWSBuffer Binding 1
251 %uint = OpTypeInt 32 0
252 %uint_32 = OpConstant %uint 32
253 %v4uint = OpTypeVector %uint 4
254 %type_gBuffer = OpTypeStruct %v4uint
255 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
256 %S = OpTypeStruct %uint
257 %_runtimearr_S = OpTypeRuntimeArray %S
258 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
259 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
260 %int = OpTypeInt 32 1
261 %void = OpTypeVoid
262 %15 = OpTypeFunction %void
263 %int_0 = OpConstant %int 0
264 %_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
265 %uint_0 = OpConstant %uint 0
266 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
267 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
268 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
269 %main = OpFunction %void None %15
270 %20 = OpLabel
271 %21 = OpAccessChain %_ptr_Uniform_v4uint %gBuffer %int_0
272 %22 = OpLoad %v4uint %21
273 %23 = OpCompositeExtract %uint %22 1
274 %24 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
275 OpStore %24 %23
276 OpReturn
277 OpFunctionEnd
278 )";
279
280 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
281 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
282 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
283 SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
284 }
285
TEST_F(ReduceLoadSizeTest,cbuffer_load_5_extract)286 TEST_F(ReduceLoadSizeTest, cbuffer_load_5_extract) {
287 // All of the elements of the value loaded are used, so we should not
288 // change the load.
289 const std::string test =
290 R"(OpCapability Shader
291 OpMemoryModel Logical GLSL450
292 OpEntryPoint GLCompute %main "main"
293 OpExecutionMode %main LocalSize 1 1 1
294 OpSource HLSL 600
295 OpName %type_gBuffer "type.gBuffer"
296 OpMemberName %type_gBuffer 0 "a"
297 OpName %gBuffer "gBuffer"
298 OpName %S "S"
299 OpMemberName %S 0 "f"
300 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
301 OpName %gRWSBuffer "gRWSBuffer"
302 OpName %main "main"
303 OpDecorate %_arr_uint_uint_5 ArrayStride 16
304 OpMemberDecorate %type_gBuffer 0 Offset 0
305 OpDecorate %type_gBuffer Block
306 OpMemberDecorate %S 0 Offset 0
307 OpDecorate %_runtimearr_S ArrayStride 4
308 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
309 OpDecorate %type_RWStructuredBuffer_S BufferBlock
310 OpDecorate %gBuffer DescriptorSet 0
311 OpDecorate %gBuffer Binding 0
312 OpDecorate %gRWSBuffer DescriptorSet 0
313 OpDecorate %gRWSBuffer Binding 1
314 %uint = OpTypeInt 32 0
315 %uint_5 = OpConstant %uint 5
316 %_arr_uint_uint_5 = OpTypeArray %uint %uint_5
317 %type_gBuffer = OpTypeStruct %_arr_uint_uint_5
318 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
319 %S = OpTypeStruct %uint
320 %_runtimearr_S = OpTypeRuntimeArray %S
321 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
322 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
323 %int = OpTypeInt 32 1
324 %void = OpTypeVoid
325 %15 = OpTypeFunction %void
326 %int_0 = OpConstant %int 0
327 %_ptr_Uniform__arr_uint_uint_5 = OpTypePointer Uniform %_arr_uint_uint_5
328 %uint_0 = OpConstant %uint 0
329 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
330 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
331 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
332 %main = OpFunction %void None %15
333 %20 = OpLabel
334 %21 = OpAccessChain %_ptr_Uniform__arr_uint_uint_5 %gBuffer %int_0
335 %22 = OpLoad %_arr_uint_uint_5 %21
336 %23 = OpCompositeExtract %uint %22 0
337 %24 = OpCompositeExtract %uint %22 1
338 %25 = OpCompositeExtract %uint %22 2
339 %26 = OpCompositeExtract %uint %22 3
340 %27 = OpCompositeExtract %uint %22 4
341 %28 = OpIAdd %uint %23 %24
342 %29 = OpIAdd %uint %28 %25
343 %30 = OpIAdd %uint %29 %26
344 %31 = OpIAdd %uint %20 %27
345 %32 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
346 OpStore %32 %31
347 OpReturn
348 OpFunctionEnd
349 )";
350
351 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
352 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
353 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
354 SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
355 }
356
TEST_F(ReduceLoadSizeTest,cbuffer_load_fully_used)357 TEST_F(ReduceLoadSizeTest, cbuffer_load_fully_used) {
358 // The result of the load (%22) is used in an instruction that uses the whole
359 // load and has only 1 in operand. This trigger issue #1559.
360 const std::string test =
361 R"(OpCapability Shader
362 OpMemoryModel Logical GLSL450
363 OpEntryPoint GLCompute %main "main"
364 OpExecutionMode %main LocalSize 1 1 1
365 OpSource HLSL 600
366 OpName %type_gBuffer "type.gBuffer"
367 OpMemberName %type_gBuffer 0 "a"
368 OpName %gBuffer "gBuffer"
369 OpName %S "S"
370 OpMemberName %S 0 "f"
371 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
372 OpName %gRWSBuffer "gRWSBuffer"
373 OpName %main "main"
374 OpMemberDecorate %type_gBuffer 0 Offset 0
375 OpDecorate %type_gBuffer Block
376 OpMemberDecorate %S 0 Offset 0
377 OpDecorate %_runtimearr_S ArrayStride 4
378 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
379 OpDecorate %type_RWStructuredBuffer_S BufferBlock
380 OpDecorate %gBuffer DescriptorSet 0
381 OpDecorate %gBuffer Binding 0
382 OpDecorate %gRWSBuffer DescriptorSet 0
383 OpDecorate %gRWSBuffer Binding 1
384 %uint = OpTypeInt 32 0
385 %uint_32 = OpConstant %uint 32
386 %v4uint = OpTypeVector %uint 4
387 %float = OpTypeFloat 32
388 %v4float = OpTypeVector %float 4
389 %type_gBuffer = OpTypeStruct %v4uint
390 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
391 %S = OpTypeStruct %uint
392 %_runtimearr_S = OpTypeRuntimeArray %S
393 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
394 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
395 %int = OpTypeInt 32 1
396 %void = OpTypeVoid
397 %15 = OpTypeFunction %void
398 %int_0 = OpConstant %int 0
399 %_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
400 %uint_0 = OpConstant %uint 0
401 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
402 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
403 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
404 %main = OpFunction %void None %15
405 %20 = OpLabel
406 %21 = OpAccessChain %_ptr_Uniform_v4uint %gBuffer %int_0
407 %22 = OpLoad %v4uint %21
408 %23 = OpCompositeExtract %uint %22 1
409 %24 = OpConvertUToF %v4float %22
410 %25 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
411 OpStore %25 %23
412 OpReturn
413 OpFunctionEnd
414 )";
415
416 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
417 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
418 SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
419 SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
420 }
421
422 } // namespace
423 } // namespace opt
424 } // namespace spvtools
425