• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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