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_vector)110 TEST_F(ReduceLoadSizeTest, cbuffer_load_extract_vector) {
111   // Originally from the following HLSL:
112   //   struct S {
113   //     uint f;
114   //   };
115   //
116   //
117   //   cbuffer gBuffer { uint4 a; };
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"(OpCapability Shader
131 OpMemoryModel Logical GLSL450
132 OpEntryPoint GLCompute %main "main"
133 OpExecutionMode %main LocalSize 1 1 1
134 OpSource HLSL 600
135 OpName %type_gBuffer "type.gBuffer"
136 OpMemberName %type_gBuffer 0 "a"
137 OpName %gBuffer "gBuffer"
138 OpName %S "S"
139 OpMemberName %S 0 "f"
140 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
141 OpName %gRWSBuffer "gRWSBuffer"
142 OpName %main "main"
143 OpMemberDecorate %type_gBuffer 0 Offset 0
144 OpDecorate %type_gBuffer Block
145 OpMemberDecorate %S 0 Offset 0
146 OpDecorate %_runtimearr_S ArrayStride 4
147 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
148 OpDecorate %type_RWStructuredBuffer_S BufferBlock
149 OpDecorate %gBuffer DescriptorSet 0
150 OpDecorate %gBuffer Binding 0
151 OpDecorate %gRWSBuffer DescriptorSet 0
152 OpDecorate %gRWSBuffer Binding 1
153 %uint = OpTypeInt 32 0
154 %uint_32 = OpConstant %uint 32
155 %v4uint = OpTypeVector %uint 4
156 %type_gBuffer = OpTypeStruct %v4uint
157 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
158 %S = OpTypeStruct %uint
159 %_runtimearr_S = OpTypeRuntimeArray %S
160 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
161 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
162 %int = OpTypeInt 32 1
163 %void = OpTypeVoid
164 %15 = OpTypeFunction %void
165 %int_0 = OpConstant %int 0
166 %_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
167 %uint_0 = OpConstant %uint 0
168 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
169 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
170 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
171 %main = OpFunction %void None %15
172 %20 = OpLabel
173 %21 = OpAccessChain %_ptr_Uniform_v4uint %gBuffer %int_0
174 %22 = OpLoad %v4uint %21
175 %23 = OpCompositeExtract %uint %22 1
176 %24 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
177 OpStore %24 %23
178 OpReturn
179 OpFunctionEnd
180 )";
181 
182   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
183   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
184                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
185   SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
186 }
187 
TEST_F(ReduceLoadSizeTest,cbuffer_load_5_extract)188 TEST_F(ReduceLoadSizeTest, cbuffer_load_5_extract) {
189   // All of the elements of the value loaded are used, so we should not
190   // change the load.
191   const std::string test =
192       R"(OpCapability Shader
193 OpMemoryModel Logical GLSL450
194 OpEntryPoint GLCompute %main "main"
195 OpExecutionMode %main LocalSize 1 1 1
196 OpSource HLSL 600
197 OpName %type_gBuffer "type.gBuffer"
198 OpMemberName %type_gBuffer 0 "a"
199 OpName %gBuffer "gBuffer"
200 OpName %S "S"
201 OpMemberName %S 0 "f"
202 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
203 OpName %gRWSBuffer "gRWSBuffer"
204 OpName %main "main"
205 OpDecorate %_arr_uint_uint_5 ArrayStride 16
206 OpMemberDecorate %type_gBuffer 0 Offset 0
207 OpDecorate %type_gBuffer Block
208 OpMemberDecorate %S 0 Offset 0
209 OpDecorate %_runtimearr_S ArrayStride 4
210 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
211 OpDecorate %type_RWStructuredBuffer_S BufferBlock
212 OpDecorate %gBuffer DescriptorSet 0
213 OpDecorate %gBuffer Binding 0
214 OpDecorate %gRWSBuffer DescriptorSet 0
215 OpDecorate %gRWSBuffer Binding 1
216 %uint = OpTypeInt 32 0
217 %uint_5 = OpConstant %uint 5
218 %_arr_uint_uint_5 = OpTypeArray %uint %uint_5
219 %type_gBuffer = OpTypeStruct %_arr_uint_uint_5
220 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
221 %S = OpTypeStruct %uint
222 %_runtimearr_S = OpTypeRuntimeArray %S
223 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
224 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
225 %int = OpTypeInt 32 1
226 %void = OpTypeVoid
227 %15 = OpTypeFunction %void
228 %int_0 = OpConstant %int 0
229 %_ptr_Uniform__arr_uint_uint_5 = OpTypePointer Uniform %_arr_uint_uint_5
230 %uint_0 = OpConstant %uint 0
231 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
232 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
233 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
234 %main = OpFunction %void None %15
235 %20 = OpLabel
236 %21 = OpAccessChain %_ptr_Uniform__arr_uint_uint_5 %gBuffer %int_0
237 %22 = OpLoad %_arr_uint_uint_5 %21
238 %23 = OpCompositeExtract %uint %22 0
239 %24 = OpCompositeExtract %uint %22 1
240 %25 = OpCompositeExtract %uint %22 2
241 %26 = OpCompositeExtract %uint %22 3
242 %27 = OpCompositeExtract %uint %22 4
243 %28 = OpIAdd %uint %23 %24
244 %29 = OpIAdd %uint %28 %25
245 %30 = OpIAdd %uint %29 %26
246 %31 = OpIAdd %uint %20 %27
247 %32 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
248 OpStore %32 %31
249 OpReturn
250 OpFunctionEnd
251 )";
252 
253   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
254   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
255                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
256   SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
257 }
258 
TEST_F(ReduceLoadSizeTest,cbuffer_load_fully_used)259 TEST_F(ReduceLoadSizeTest, cbuffer_load_fully_used) {
260   // The result of the load (%22) is used in an instruction that uses the whole
261   // load and has only 1 in operand.  This trigger issue #1559.
262   const std::string test =
263       R"(OpCapability Shader
264 OpMemoryModel Logical GLSL450
265 OpEntryPoint GLCompute %main "main"
266 OpExecutionMode %main LocalSize 1 1 1
267 OpSource HLSL 600
268 OpName %type_gBuffer "type.gBuffer"
269 OpMemberName %type_gBuffer 0 "a"
270 OpName %gBuffer "gBuffer"
271 OpName %S "S"
272 OpMemberName %S 0 "f"
273 OpName %type_RWStructuredBuffer_S "type.RWStructuredBuffer.S"
274 OpName %gRWSBuffer "gRWSBuffer"
275 OpName %main "main"
276 OpMemberDecorate %type_gBuffer 0 Offset 0
277 OpDecorate %type_gBuffer Block
278 OpMemberDecorate %S 0 Offset 0
279 OpDecorate %_runtimearr_S ArrayStride 4
280 OpMemberDecorate %type_RWStructuredBuffer_S 0 Offset 0
281 OpDecorate %type_RWStructuredBuffer_S BufferBlock
282 OpDecorate %gBuffer DescriptorSet 0
283 OpDecorate %gBuffer Binding 0
284 OpDecorate %gRWSBuffer DescriptorSet 0
285 OpDecorate %gRWSBuffer Binding 1
286 %uint = OpTypeInt 32 0
287 %uint_32 = OpConstant %uint 32
288 %v4uint = OpTypeVector %uint 4
289 %float = OpTypeFloat 32
290 %v4float = OpTypeVector %float 4
291 %type_gBuffer = OpTypeStruct %v4uint
292 %_ptr_Uniform_type_gBuffer = OpTypePointer Uniform %type_gBuffer
293 %S = OpTypeStruct %uint
294 %_runtimearr_S = OpTypeRuntimeArray %S
295 %type_RWStructuredBuffer_S = OpTypeStruct %_runtimearr_S
296 %_ptr_Uniform_type_RWStructuredBuffer_S = OpTypePointer Uniform %type_RWStructuredBuffer_S
297 %int = OpTypeInt 32 1
298 %void = OpTypeVoid
299 %15 = OpTypeFunction %void
300 %int_0 = OpConstant %int 0
301 %_ptr_Uniform_v4uint = OpTypePointer Uniform %v4uint
302 %uint_0 = OpConstant %uint 0
303 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
304 %gBuffer = OpVariable %_ptr_Uniform_type_gBuffer Uniform
305 %gRWSBuffer = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_S Uniform
306 %main = OpFunction %void None %15
307 %20 = OpLabel
308 %21 = OpAccessChain %_ptr_Uniform_v4uint %gBuffer %int_0
309 %22 = OpLoad %v4uint %21
310 %23 = OpCompositeExtract %uint %22 1
311 %24 = OpConvertUToF %v4float %22
312 %25 = OpAccessChain %_ptr_Uniform_uint %gRWSBuffer %int_0 %uint_0 %int_0
313 OpStore %25 %23
314 OpReturn
315 OpFunctionEnd
316 )";
317 
318   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
319   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER |
320                         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
321   SinglePassRunAndCheck<ReduceLoadSize>(test, test, true, false);
322 }
323 
324 }  // namespace
325 }  // namespace opt
326 }  // namespace spvtools
327