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 "source/fuzz/transformation_add_dead_block.h"
16 #include "test/fuzz/fuzz_test_util.h"
17
18 namespace spvtools {
19 namespace fuzz {
20 namespace {
21
TEST(TransformationAddDeadBlockTest,BasicTest)22 TEST(TransformationAddDeadBlockTest, BasicTest) {
23 std::string shader = R"(
24 OpCapability Shader
25 %1 = OpExtInstImport "GLSL.std.450"
26 OpMemoryModel Logical GLSL450
27 OpEntryPoint Fragment %4 "main"
28 OpExecutionMode %4 OriginUpperLeft
29 OpSource ESSL 310
30 OpName %4 "main"
31 %2 = OpTypeVoid
32 %3 = OpTypeFunction %2
33 %6 = OpTypeBool
34 %7 = OpConstantTrue %6
35 %4 = OpFunction %2 None %3
36 %5 = OpLabel
37 OpBranch %8
38 %8 = OpLabel
39 OpReturn
40 OpFunctionEnd
41 )";
42
43 const auto env = SPV_ENV_UNIVERSAL_1_4;
44 const auto consumer = nullptr;
45 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
46 ASSERT_TRUE(IsValid(env, context.get()));
47
48 FactManager fact_manager;
49 spvtools::ValidatorOptions validator_options;
50 TransformationContext transformation_context(&fact_manager,
51 validator_options);
52
53 // Id 4 is already in use
54 ASSERT_FALSE(TransformationAddDeadBlock(4, 5, true)
55 .IsApplicable(context.get(), transformation_context));
56
57 // Id 7 is not a block
58 ASSERT_FALSE(TransformationAddDeadBlock(100, 7, true)
59 .IsApplicable(context.get(), transformation_context));
60
61 TransformationAddDeadBlock transformation(100, 5, true);
62 ASSERT_TRUE(
63 transformation.IsApplicable(context.get(), transformation_context));
64 transformation.Apply(context.get(), &transformation_context);
65 ASSERT_TRUE(IsValid(env, context.get()));
66
67 ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(100));
68
69 std::string after_transformation = R"(
70 OpCapability Shader
71 %1 = OpExtInstImport "GLSL.std.450"
72 OpMemoryModel Logical GLSL450
73 OpEntryPoint Fragment %4 "main"
74 OpExecutionMode %4 OriginUpperLeft
75 OpSource ESSL 310
76 OpName %4 "main"
77 %2 = OpTypeVoid
78 %3 = OpTypeFunction %2
79 %6 = OpTypeBool
80 %7 = OpConstantTrue %6
81 %4 = OpFunction %2 None %3
82 %5 = OpLabel
83 OpSelectionMerge %8 None
84 OpBranchConditional %7 %8 %100
85 %100 = OpLabel
86 OpBranch %8
87 %8 = OpLabel
88 OpReturn
89 OpFunctionEnd
90 )";
91 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
92 }
93
TEST(TransformationAddDeadBlockTest,TargetBlockMustNotBeSelectionMerge)94 TEST(TransformationAddDeadBlockTest, TargetBlockMustNotBeSelectionMerge) {
95 std::string shader = R"(
96 OpCapability Shader
97 %1 = OpExtInstImport "GLSL.std.450"
98 OpMemoryModel Logical GLSL450
99 OpEntryPoint Fragment %4 "main"
100 OpExecutionMode %4 OriginUpperLeft
101 OpSource ESSL 310
102 OpName %4 "main"
103 %2 = OpTypeVoid
104 %3 = OpTypeFunction %2
105 %6 = OpTypeBool
106 %7 = OpConstantTrue %6
107 %4 = OpFunction %2 None %3
108 %5 = OpLabel
109 OpSelectionMerge %10 None
110 OpBranchConditional %7 %8 %9
111 %8 = OpLabel
112 OpBranch %10
113 %9 = OpLabel
114 OpBranch %10
115 %10 = OpLabel
116 OpReturn
117 OpFunctionEnd
118 )";
119
120 const auto env = SPV_ENV_UNIVERSAL_1_4;
121 const auto consumer = nullptr;
122 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
123 ASSERT_TRUE(IsValid(env, context.get()));
124
125 FactManager fact_manager;
126 spvtools::ValidatorOptions validator_options;
127 TransformationContext transformation_context(&fact_manager,
128 validator_options);
129
130 ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true)
131 .IsApplicable(context.get(), transformation_context));
132 }
133
TEST(TransformationAddDeadBlockTest,TargetBlockMustNotBeLoopMergeOrContinue)134 TEST(TransformationAddDeadBlockTest, TargetBlockMustNotBeLoopMergeOrContinue) {
135 std::string shader = R"(
136 OpCapability Shader
137 %1 = OpExtInstImport "GLSL.std.450"
138 OpMemoryModel Logical GLSL450
139 OpEntryPoint Fragment %4 "main"
140 OpExecutionMode %4 OriginUpperLeft
141 OpSource ESSL 310
142 OpName %4 "main"
143 %2 = OpTypeVoid
144 %3 = OpTypeFunction %2
145 %6 = OpTypeBool
146 %7 = OpConstantTrue %6
147 %4 = OpFunction %2 None %3
148 %5 = OpLabel
149 OpBranch %8
150 %8 = OpLabel
151 OpLoopMerge %11 %12 None
152 OpBranchConditional %7 %9 %10
153 %9 = OpLabel
154 OpBranch %12
155 %10 = OpLabel
156 OpBranch %11
157 %12 = OpLabel
158 OpBranch %8
159 %11 = OpLabel
160 OpReturn
161 OpFunctionEnd
162 )";
163
164 const auto env = SPV_ENV_UNIVERSAL_1_4;
165 const auto consumer = nullptr;
166 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
167 ASSERT_TRUE(IsValid(env, context.get()));
168
169 FactManager fact_manager;
170 spvtools::ValidatorOptions validator_options;
171 TransformationContext transformation_context(&fact_manager,
172 validator_options);
173
174 // Bad because 9's successor is the loop continue target.
175 ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true)
176 .IsApplicable(context.get(), transformation_context));
177 // Bad because 10's successor is the loop merge.
178 ASSERT_FALSE(TransformationAddDeadBlock(100, 10, true)
179 .IsApplicable(context.get(), transformation_context));
180 }
181
TEST(TransformationAddDeadBlockTest,SourceBlockMustNotBeLoopHead)182 TEST(TransformationAddDeadBlockTest, SourceBlockMustNotBeLoopHead) {
183 std::string shader = R"(
184 OpCapability Shader
185 %1 = OpExtInstImport "GLSL.std.450"
186 OpMemoryModel Logical GLSL450
187 OpEntryPoint Fragment %4 "main"
188 OpExecutionMode %4 OriginUpperLeft
189 OpSource ESSL 310
190 OpName %4 "main"
191 %2 = OpTypeVoid
192 %3 = OpTypeFunction %2
193 %6 = OpTypeBool
194 %7 = OpConstantTrue %6
195 %4 = OpFunction %2 None %3
196 %5 = OpLabel
197 OpBranch %8
198 %8 = OpLabel
199 OpLoopMerge %11 %12 None
200 OpBranch %9
201 %9 = OpLabel
202 OpBranchConditional %7 %11 %12
203 %12 = OpLabel
204 OpBranch %8
205 %11 = OpLabel
206 OpReturn
207 OpFunctionEnd
208 )";
209
210 const auto env = SPV_ENV_UNIVERSAL_1_4;
211 const auto consumer = nullptr;
212 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
213 ASSERT_TRUE(IsValid(env, context.get()));
214
215 FactManager fact_manager;
216 spvtools::ValidatorOptions validator_options;
217 TransformationContext transformation_context(&fact_manager,
218 validator_options);
219
220 // Bad because 8 is a loop head.
221 ASSERT_FALSE(TransformationAddDeadBlock(100, 8, true)
222 .IsApplicable(context.get(), transformation_context));
223 }
224
TEST(TransformationAddDeadBlockTest,OpPhiInTarget)225 TEST(TransformationAddDeadBlockTest, OpPhiInTarget) {
226 std::string shader = R"(
227 OpCapability Shader
228 %1 = OpExtInstImport "GLSL.std.450"
229 OpMemoryModel Logical GLSL450
230 OpEntryPoint Fragment %4 "main"
231 OpExecutionMode %4 OriginUpperLeft
232 OpSource ESSL 310
233 OpName %4 "main"
234 %2 = OpTypeVoid
235 %3 = OpTypeFunction %2
236 %6 = OpTypeBool
237 %7 = OpConstantTrue %6
238 %9 = OpTypeInt 32 0
239 %10 = OpConstant %9 1
240 %4 = OpFunction %2 None %3
241 %5 = OpLabel
242 OpBranch %8
243 %8 = OpLabel
244 %12 = OpPhi %6 %7 %5
245 %13 = OpPhi %9 %10 %5
246 OpReturn
247 OpFunctionEnd
248 )";
249
250 const auto env = SPV_ENV_UNIVERSAL_1_4;
251 const auto consumer = nullptr;
252 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
253 ASSERT_TRUE(IsValid(env, context.get()));
254
255 FactManager fact_manager;
256 spvtools::ValidatorOptions validator_options;
257 TransformationContext transformation_context(&fact_manager,
258 validator_options);
259
260 TransformationAddDeadBlock transformation(100, 5, true);
261 ASSERT_TRUE(
262 transformation.IsApplicable(context.get(), transformation_context));
263 transformation.Apply(context.get(), &transformation_context);
264 ASSERT_TRUE(IsValid(env, context.get()));
265
266 ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(100));
267
268 std::string after_transformation = R"(
269 OpCapability Shader
270 %1 = OpExtInstImport "GLSL.std.450"
271 OpMemoryModel Logical GLSL450
272 OpEntryPoint Fragment %4 "main"
273 OpExecutionMode %4 OriginUpperLeft
274 OpSource ESSL 310
275 OpName %4 "main"
276 %2 = OpTypeVoid
277 %3 = OpTypeFunction %2
278 %6 = OpTypeBool
279 %7 = OpConstantTrue %6
280 %9 = OpTypeInt 32 0
281 %10 = OpConstant %9 1
282 %4 = OpFunction %2 None %3
283 %5 = OpLabel
284 OpSelectionMerge %8 None
285 OpBranchConditional %7 %8 %100
286 %100 = OpLabel
287 OpBranch %8
288 %8 = OpLabel
289 %12 = OpPhi %6 %7 %5 %7 %100
290 %13 = OpPhi %9 %10 %5 %10 %100
291 OpReturn
292 OpFunctionEnd
293 )";
294 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
295 }
296
TEST(TransformationAddDeadBlockTest,BackEdge)297 TEST(TransformationAddDeadBlockTest, BackEdge) {
298 std::string shader = R"(
299 OpCapability Shader
300 %1 = OpExtInstImport "GLSL.std.450"
301 OpMemoryModel Logical GLSL450
302 OpEntryPoint Fragment %4 "main"
303 OpExecutionMode %4 OriginUpperLeft
304 OpSource ESSL 310
305 OpName %4 "main"
306 %2 = OpTypeVoid
307 %3 = OpTypeFunction %2
308 %6 = OpTypeBool
309 %7 = OpConstantTrue %6
310 %4 = OpFunction %2 None %3
311 %5 = OpLabel
312 OpBranch %8
313 %8 = OpLabel
314 OpLoopMerge %10 %9 None
315 OpBranchConditional %7 %9 %10
316 %9 = OpLabel
317 OpBranch %8
318 %10 = OpLabel
319 OpReturn
320 OpFunctionEnd
321 )";
322
323 const auto env = SPV_ENV_UNIVERSAL_1_4;
324 const auto consumer = nullptr;
325 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
326 ASSERT_TRUE(IsValid(env, context.get()));
327
328 FactManager fact_manager;
329 spvtools::ValidatorOptions validator_options;
330 TransformationContext transformation_context(&fact_manager,
331 validator_options);
332
333 // 9 is a back edge block, so it would not be OK to add a dead block here,
334 // as then both 9 and the dead block would branch to the loop header, 8.
335 ASSERT_FALSE(TransformationAddDeadBlock(100, 9, true)
336 .IsApplicable(context.get(), transformation_context));
337 }
338
339 } // namespace
340 } // namespace fuzz
341 } // namespace spvtools
342