1 // Copyright (c) 2020 Vasyl Teliman
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_wrap_region_in_selection.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationWrapRegionInSelectionTest,BasicTest)26 TEST(TransformationWrapRegionInSelectionTest, BasicTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main"
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %7 = OpTypeBool
37 %8 = OpConstantTrue %7
38
39 %4 = OpFunction %2 None %3
40 %5 = OpLabel
41 OpBranch %6
42
43 %6 = OpLabel
44 OpSelectionMerge %12 None
45 OpBranchConditional %8 %11 %12
46 %11 = OpLabel
47 OpReturn
48
49 %12 = OpLabel
50 OpSelectionMerge %15 None
51 OpBranchConditional %8 %13 %14
52 %13 = OpLabel
53 OpBranch %15
54 %14 = OpLabel
55 OpBranch %15
56 %15 = OpLabel
57 OpBranch %16
58
59 %16 = OpLabel
60 OpReturn
61 OpFunctionEnd
62
63 %9 = OpFunction %2 None %3
64 %10 = OpLabel
65 OpBranch %20
66
67 %20 = OpLabel
68 OpLoopMerge %23 %22 None
69 OpBranch %21
70 %21 = OpLabel
71 OpBranchConditional %8 %24 %23
72 %24 = OpLabel
73 OpBranch %22
74
75 ; continue target
76 %22 = OpLabel
77 OpLoopMerge %25 %28 None
78 OpBranchConditional %8 %27 %25
79 %27 = OpLabel
80 OpBranch %28
81 %28 = OpLabel
82 OpBranch %22
83 %25 = OpLabel
84 OpBranch %20
85
86 ; merge block
87 %23 = OpLabel
88 OpBranch %26
89
90 %26 = OpLabel
91 OpReturn
92 OpFunctionEnd
93 )";
94
95 const auto env = SPV_ENV_UNIVERSAL_1_3;
96 const auto consumer = nullptr;
97 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
98 spvtools::ValidatorOptions validator_options;
99 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
100 kConsoleMessageConsumer));
101 TransformationContext transformation_context(
102 MakeUnique<FactManager>(context.get()), validator_options);
103
104 // Boolean constant does not exist.
105 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 6, false)
106 .IsApplicable(context.get(), transformation_context));
107
108 // Irrelevant constant does not exist.
109 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 6, true)
110 .IsApplicable(context.get(), transformation_context));
111
112 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(8);
113
114 // Block ids are invalid.
115 ASSERT_FALSE(TransformationWrapRegionInSelection(100, 6, true)
116 .IsApplicable(context.get(), transformation_context));
117 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 100, true)
118 .IsApplicable(context.get(), transformation_context));
119
120 // Blocks are from different functions.
121 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 10, true)
122 .IsApplicable(context.get(), transformation_context));
123
124 // Header block candidate does not dominate merge block candidate.
125 ASSERT_FALSE(TransformationWrapRegionInSelection(13, 16, true)
126 .IsApplicable(context.get(), transformation_context));
127
128 // Header block candidate does not *strictly* dominate merge block candidate.
129 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 5, true)
130 .IsApplicable(context.get(), transformation_context));
131
132 // Merge block candidate does not postdominate header block candidate.
133 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 16, true)
134 .IsApplicable(context.get(), transformation_context));
135
136 // Header block candidate is already a header block of some other construct.
137 ASSERT_FALSE(TransformationWrapRegionInSelection(12, 16, true)
138 .IsApplicable(context.get(), transformation_context));
139
140 // Header block's terminator is not an OpBranch.
141 ASSERT_FALSE(TransformationWrapRegionInSelection(21, 24, true)
142 .IsApplicable(context.get(), transformation_context));
143
144 // Merge block candidate is already a merge block of some other construct.
145 ASSERT_FALSE(TransformationWrapRegionInSelection(5, 15, true)
146 .IsApplicable(context.get(), transformation_context));
147
148 // Header block candidate and merge block candidate are in different
149 // constructs.
150 ASSERT_FALSE(TransformationWrapRegionInSelection(10, 21, true)
151 .IsApplicable(context.get(), transformation_context));
152 ASSERT_FALSE(TransformationWrapRegionInSelection(24, 25, true)
153 .IsApplicable(context.get(), transformation_context));
154 ASSERT_FALSE(TransformationWrapRegionInSelection(24, 22, true)
155 .IsApplicable(context.get(), transformation_context));
156 ASSERT_FALSE(TransformationWrapRegionInSelection(24, 27, true)
157 .IsApplicable(context.get(), transformation_context));
158
159 {
160 // Header block candidate can be a merge block of some existing construct.
161 TransformationWrapRegionInSelection transformation(15, 16, true);
162 ASSERT_TRUE(
163 transformation.IsApplicable(context.get(), transformation_context));
164 ApplyAndCheckFreshIds(transformation, context.get(),
165 &transformation_context);
166 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
167 context.get(), validator_options, kConsoleMessageConsumer));
168 }
169 {
170 // Merge block candidate can be a header block of some existing construct.
171 TransformationWrapRegionInSelection transformation(5, 6, true);
172 ASSERT_TRUE(
173 transformation.IsApplicable(context.get(), transformation_context));
174 ApplyAndCheckFreshIds(transformation, context.get(),
175 &transformation_context);
176 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
177 context.get(), validator_options, kConsoleMessageConsumer));
178 }
179 {
180 // Wrap a loop construct.
181 TransformationWrapRegionInSelection transformation(10, 26, true);
182 ASSERT_TRUE(
183 transformation.IsApplicable(context.get(), transformation_context));
184 ApplyAndCheckFreshIds(transformation, context.get(),
185 &transformation_context);
186 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
187 context.get(), validator_options, kConsoleMessageConsumer));
188 }
189
190 std::string after_transformation = R"(
191 OpCapability Shader
192 %1 = OpExtInstImport "GLSL.std.450"
193 OpMemoryModel Logical GLSL450
194 OpEntryPoint Fragment %4 "main"
195 OpExecutionMode %4 OriginUpperLeft
196 OpSource ESSL 310
197 %2 = OpTypeVoid
198 %3 = OpTypeFunction %2
199 %7 = OpTypeBool
200 %8 = OpConstantTrue %7
201
202 %4 = OpFunction %2 None %3
203 %5 = OpLabel
204 OpSelectionMerge %6 None
205 OpBranchConditional %8 %6 %6
206
207 %6 = OpLabel
208 OpSelectionMerge %12 None
209 OpBranchConditional %8 %11 %12
210 %11 = OpLabel
211 OpReturn
212
213 %12 = OpLabel
214 OpSelectionMerge %15 None
215 OpBranchConditional %8 %13 %14
216 %13 = OpLabel
217 OpBranch %15
218 %14 = OpLabel
219 OpBranch %15
220
221 %15 = OpLabel
222 OpSelectionMerge %16 None
223 OpBranchConditional %8 %16 %16
224 %16 = OpLabel
225 OpReturn
226 OpFunctionEnd
227
228 %9 = OpFunction %2 None %3
229 %10 = OpLabel
230 OpSelectionMerge %26 None
231 OpBranchConditional %8 %20 %20
232
233 %20 = OpLabel
234 OpLoopMerge %23 %22 None
235 OpBranch %21
236 %21 = OpLabel
237 OpBranchConditional %8 %24 %23
238 %24 = OpLabel
239 OpBranch %22
240
241 ; continue target
242 %22 = OpLabel
243 OpLoopMerge %25 %28 None
244 OpBranchConditional %8 %27 %25
245 %27 = OpLabel
246 OpBranch %28
247 %28 = OpLabel
248 OpBranch %22
249 %25 = OpLabel
250 OpBranch %20
251
252 ; merge block
253 %23 = OpLabel
254 OpBranch %26
255
256 %26 = OpLabel
257 OpReturn
258 OpFunctionEnd
259 )";
260
261 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
262 }
263
264 } // namespace
265 } // namespace fuzz
266 } // namespace spvtools
267