1 // Copyright (c) 2020 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 "source/reduce/remove_unused_struct_member_reduction_opportunity_finder.h"
16 
17 #include "source/opt/build_module.h"
18 #include "source/reduce/reduction_opportunity.h"
19 #include "test/reduce/reduce_test_util.h"
20 
21 namespace spvtools {
22 namespace reduce {
23 namespace {
24 
TEST(RemoveUnusedStructMemberTest, RemoveOneMember)25 TEST(RemoveUnusedStructMemberTest, RemoveOneMember) {
26   std::string shader = R"(
27                OpCapability Shader
28           %1 = OpExtInstImport "GLSL.std.450"
29                OpMemoryModel Logical GLSL450
30                OpEntryPoint Fragment %4 "main"
31                OpExecutionMode %4 OriginUpperLeft
32                OpSource ESSL 310
33           %2 = OpTypeVoid
34           %3 = OpTypeFunction %2
35           %6 = OpTypeInt 32 1
36           %7 = OpTypeStruct %6 %6
37           %8 = OpTypePointer Function %7
38          %50 = OpConstant %6 0
39          %10 = OpConstant %6 1
40          %11 = OpConstant %6 2
41          %12 = OpConstantComposite %7 %10 %11
42          %13 = OpConstant %6 4
43          %14 = OpTypePointer Function %6
44           %4 = OpFunction %2 None %3
45           %5 = OpLabel
46           %9 = OpVariable %8 Function
47                OpStore %9 %12
48          %15 = OpAccessChain %14 %9 %10
49          %22 = OpInBoundsAccessChain %14 %9 %10
50          %20 = OpLoad %7 %9
51          %21 = OpCompositeExtract %6 %20 1
52          %23 = OpCompositeInsert %7 %10 %20 1
53                OpStore %15 %13
54                OpReturn
55                OpFunctionEnd
56   )";
57 
58   const auto env = SPV_ENV_UNIVERSAL_1_3;
59   const auto consumer = nullptr;
60   const auto context =
61       BuildModule(env, consumer, shader, kReduceAssembleOption);
62 
63   auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
64                  .GetAvailableOpportunities(context.get(), 0);
65   ASSERT_EQ(1, ops.size());
66   ASSERT_TRUE(ops[0]->PreconditionHolds());
67   ops[0]->TryToApply();
68 
69   CheckValid(env, context.get());
70 
71   std::string expected = R"(
72                OpCapability Shader
73           %1 = OpExtInstImport "GLSL.std.450"
74                OpMemoryModel Logical GLSL450
75                OpEntryPoint Fragment %4 "main"
76                OpExecutionMode %4 OriginUpperLeft
77                OpSource ESSL 310
78           %2 = OpTypeVoid
79           %3 = OpTypeFunction %2
80           %6 = OpTypeInt 32 1
81           %7 = OpTypeStruct %6
82           %8 = OpTypePointer Function %7
83          %50 = OpConstant %6 0
84          %10 = OpConstant %6 1
85          %11 = OpConstant %6 2
86          %12 = OpConstantComposite %7 %11
87          %13 = OpConstant %6 4
88          %14 = OpTypePointer Function %6
89           %4 = OpFunction %2 None %3
90           %5 = OpLabel
91           %9 = OpVariable %8 Function
92                OpStore %9 %12
93          %15 = OpAccessChain %14 %9 %50
94          %22 = OpInBoundsAccessChain %14 %9 %50
95          %20 = OpLoad %7 %9
96          %21 = OpCompositeExtract %6 %20 0
97          %23 = OpCompositeInsert %7 %10 %20 0
98                OpStore %15 %13
99                OpReturn
100                OpFunctionEnd
101   )";
102 
103   CheckEqual(env, expected, context.get());
104 }
105 
TEST(RemoveUnusedStructMemberTest, RemoveUniformBufferMember)106 TEST(RemoveUnusedStructMemberTest, RemoveUniformBufferMember) {
107   std::string shader = R"(
108                OpCapability Shader
109           %1 = OpExtInstImport "GLSL.std.450"
110                OpMemoryModel Logical GLSL450
111                OpEntryPoint Fragment %4 "main"
112                OpExecutionMode %4 OriginUpperLeft
113                OpSource ESSL 310
114                OpMemberDecorate %10 0 Offset 0
115                OpMemberDecorate %10 1 Offset 4
116                OpDecorate %10 Block
117                OpDecorate %12 DescriptorSet 0
118                OpDecorate %12 Binding 0
119           %2 = OpTypeVoid
120           %3 = OpTypeFunction %2
121           %6 = OpTypeFloat 32
122           %7 = OpTypePointer Function %6
123           %9 = OpTypeInt 32 1
124          %10 = OpTypeStruct %9 %6
125          %11 = OpTypePointer Uniform %10
126          %12 = OpVariable %11 Uniform
127          %13 = OpConstant %9 1
128          %20 = OpConstant %9 0
129          %14 = OpTypePointer Uniform %6
130           %4 = OpFunction %2 None %3
131           %5 = OpLabel
132           %8 = OpVariable %7 Function
133          %15 = OpAccessChain %14 %12 %13
134          %16 = OpLoad %6 %15
135                OpStore %8 %16
136                OpReturn
137                OpFunctionEnd
138   )";
139 
140   const auto env = SPV_ENV_UNIVERSAL_1_3;
141   const auto consumer = nullptr;
142   const auto context =
143       BuildModule(env, consumer, shader, kReduceAssembleOption);
144 
145   auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
146                  .GetAvailableOpportunities(context.get(), 0);
147   ASSERT_EQ(1, ops.size());
148   ASSERT_TRUE(ops[0]->PreconditionHolds());
149   ops[0]->TryToApply();
150 
151   CheckValid(env, context.get());
152 
153   std::string expected = R"(
154                OpCapability Shader
155           %1 = OpExtInstImport "GLSL.std.450"
156                OpMemoryModel Logical GLSL450
157                OpEntryPoint Fragment %4 "main"
158                OpExecutionMode %4 OriginUpperLeft
159                OpSource ESSL 310
160                OpMemberDecorate %10 0 Offset 4
161                OpDecorate %10 Block
162                OpDecorate %12 DescriptorSet 0
163                OpDecorate %12 Binding 0
164           %2 = OpTypeVoid
165           %3 = OpTypeFunction %2
166           %6 = OpTypeFloat 32
167           %7 = OpTypePointer Function %6
168           %9 = OpTypeInt 32 1
169          %10 = OpTypeStruct %6
170          %11 = OpTypePointer Uniform %10
171          %12 = OpVariable %11 Uniform
172          %13 = OpConstant %9 1
173          %20 = OpConstant %9 0
174          %14 = OpTypePointer Uniform %6
175           %4 = OpFunction %2 None %3
176           %5 = OpLabel
177           %8 = OpVariable %7 Function
178          %15 = OpAccessChain %14 %12 %20
179          %16 = OpLoad %6 %15
180                OpStore %8 %16
181                OpReturn
182                OpFunctionEnd
183   )";
184 
185   CheckEqual(env, expected, context.get());
186 }
187 
TEST(RemoveUnusedStructMemberTest, DoNotRemoveNamedMemberRemoveOneMember)188 TEST(RemoveUnusedStructMemberTest, DoNotRemoveNamedMemberRemoveOneMember) {
189   // This illustrates that naming a member is enough to prevent its removal.
190   // Removal of names is done by a different pass.
191 
192   std::string shader = R"(
193                OpCapability Shader
194           %1 = OpExtInstImport "GLSL.std.450"
195                OpMemoryModel Logical GLSL450
196                OpEntryPoint Fragment %4 "main"
197                OpExecutionMode %4 OriginUpperLeft
198                OpSource ESSL 310
199                OpMemberName %7 0 "someName"
200                OpMemberName %7 1 "someOtherName"
201           %2 = OpTypeVoid
202           %3 = OpTypeFunction %2
203           %6 = OpTypeInt 32 1
204           %7 = OpTypeStruct %6 %6
205           %8 = OpTypePointer Function %7
206          %50 = OpConstant %6 0
207          %10 = OpConstant %6 1
208          %11 = OpConstant %6 2
209          %12 = OpConstantComposite %7 %10 %11
210          %13 = OpConstant %6 4
211          %14 = OpTypePointer Function %6
212           %4 = OpFunction %2 None %3
213           %5 = OpLabel
214           %9 = OpVariable %8 Function
215                OpStore %9 %12
216          %15 = OpAccessChain %14 %9 %10
217          %22 = OpInBoundsAccessChain %14 %9 %10
218          %20 = OpLoad %7 %9
219          %21 = OpCompositeExtract %6 %20 1
220          %23 = OpCompositeInsert %7 %10 %20 1
221                OpStore %15 %13
222                OpReturn
223                OpFunctionEnd
224   )";
225 
226   const auto env = SPV_ENV_UNIVERSAL_1_3;
227   const auto consumer = nullptr;
228   const auto context =
229       BuildModule(env, consumer, shader, kReduceAssembleOption);
230 
231   auto ops = RemoveUnusedStructMemberReductionOpportunityFinder()
232                  .GetAvailableOpportunities(context.get(), 0);
233   ASSERT_EQ(0, ops.size());
234 }
235 
236 }  // namespace
237 }  // namespace reduce
238 }  // namespace spvtools
239