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/fuzz/transformation_add_loop_preheader.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
TEST(TransformationAddLoopPreheaderTest,SimpleTest)25 TEST(TransformationAddLoopPreheaderTest, SimpleTest) {
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 OpName %4 "main"
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeBool
37 %7 = OpConstantFalse %6
38 %4 = OpFunction %2 None %3
39 %5 = OpLabel
40 OpSelectionMerge %10 None
41 OpBranchConditional %7 %8 %9
42 %8 = OpLabel
43 OpBranch %10
44 %9 = OpLabel
45 OpBranch %10
46 %10 = OpLabel
47 OpLoopMerge %12 %11 None
48 OpBranch %11
49 %11 = OpLabel
50 OpBranchConditional %7 %10 %12
51 %12 = OpLabel
52 OpLoopMerge %14 %13 None
53 OpBranch %13
54 %13 = OpLabel
55 OpBranchConditional %7 %14 %12
56 %15 = OpLabel
57 OpLoopMerge %17 %16 None
58 OpBranch %16
59 %16 = OpLabel
60 OpBranchConditional %7 %15 %17
61 %17 = OpLabel
62 OpBranch %14
63 %14 = OpLabel
64 OpReturn
65 OpFunctionEnd
66 )";
67
68 const auto env = SPV_ENV_UNIVERSAL_1_5;
69 const auto consumer = nullptr;
70 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
71
72 spvtools::ValidatorOptions validator_options;
73 TransformationContext transformation_context(
74 MakeUnique<FactManager>(context.get()), validator_options);
75 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
76 kConsoleMessageConsumer));
77
78 // %9 is not a loop header
79 ASSERT_FALSE(TransformationAddLoopPreheader(9, 15, {}).IsApplicable(
80 context.get(), transformation_context));
81
82 // The id %12 is not fresh
83 ASSERT_FALSE(TransformationAddLoopPreheader(10, 12, {})
84 .IsApplicable(context.get(), transformation_context));
85
86 // Loop header %15 is not reachable (the only predecessor is the back-edge
87 // block)
88 ASSERT_FALSE(TransformationAddLoopPreheader(15, 100, {})
89 .IsApplicable(context.get(), transformation_context));
90
91 auto transformation1 = TransformationAddLoopPreheader(10, 20, {});
92 ASSERT_TRUE(
93 transformation1.IsApplicable(context.get(), transformation_context));
94 ApplyAndCheckFreshIds(transformation1, context.get(),
95 &transformation_context);
96
97 auto transformation2 = TransformationAddLoopPreheader(12, 21, {});
98 ASSERT_TRUE(
99 transformation2.IsApplicable(context.get(), transformation_context));
100 ApplyAndCheckFreshIds(transformation2, context.get(),
101 &transformation_context);
102
103 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
104 kConsoleMessageConsumer));
105
106 std::string after_transformations = R"(
107 OpCapability Shader
108 %1 = OpExtInstImport "GLSL.std.450"
109 OpMemoryModel Logical GLSL450
110 OpEntryPoint Fragment %4 "main"
111 OpExecutionMode %4 OriginUpperLeft
112 OpSource ESSL 310
113 OpName %4 "main"
114 %2 = OpTypeVoid
115 %3 = OpTypeFunction %2
116 %6 = OpTypeBool
117 %7 = OpConstantFalse %6
118 %4 = OpFunction %2 None %3
119 %5 = OpLabel
120 OpSelectionMerge %20 None
121 OpBranchConditional %7 %8 %9
122 %8 = OpLabel
123 OpBranch %20
124 %9 = OpLabel
125 OpBranch %20
126 %20 = OpLabel
127 OpBranch %10
128 %10 = OpLabel
129 OpLoopMerge %21 %11 None
130 OpBranch %11
131 %11 = OpLabel
132 OpBranchConditional %7 %10 %21
133 %21 = OpLabel
134 OpBranch %12
135 %12 = OpLabel
136 OpLoopMerge %14 %13 None
137 OpBranch %13
138 %13 = OpLabel
139 OpBranchConditional %7 %14 %12
140 %15 = OpLabel
141 OpLoopMerge %17 %16 None
142 OpBranch %16
143 %16 = OpLabel
144 OpBranchConditional %7 %15 %17
145 %17 = OpLabel
146 OpBranch %14
147 %14 = OpLabel
148 OpReturn
149 OpFunctionEnd
150 )";
151
152 ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
153 }
154
TEST(TransformationAddLoopPreheaderTest,OpPhi)155 TEST(TransformationAddLoopPreheaderTest, OpPhi) {
156 std::string shader = R"(
157 OpCapability Shader
158 %1 = OpExtInstImport "GLSL.std.450"
159 OpMemoryModel Logical GLSL450
160 OpEntryPoint Fragment %4 "main"
161 OpExecutionMode %4 OriginUpperLeft
162 OpSource ESSL 310
163 OpName %4 "main"
164 %2 = OpTypeVoid
165 %3 = OpTypeFunction %2
166 %6 = OpTypeBool
167 %7 = OpConstantFalse %6
168 %4 = OpFunction %2 None %3
169 %5 = OpLabel
170 %20 = OpCopyObject %6 %7
171 OpBranch %8
172 %8 = OpLabel
173 %31 = OpPhi %6 %20 %5 %21 %9
174 OpLoopMerge %10 %9 None
175 OpBranch %9
176 %9 = OpLabel
177 %21 = OpCopyObject %6 %7
178 OpBranchConditional %7 %8 %10
179 %10 = OpLabel
180 OpSelectionMerge %13 None
181 OpBranchConditional %7 %11 %12
182 %11 = OpLabel
183 %22 = OpCopyObject %6 %7
184 OpBranch %13
185 %12 = OpLabel
186 %23 = OpCopyObject %6 %7
187 OpBranch %13
188 %13 = OpLabel
189 %32 = OpPhi %6 %22 %11 %23 %12 %24 %14
190 %33 = OpPhi %6 %7 %11 %7 %12 %24 %14
191 OpLoopMerge %15 %14 None
192 OpBranch %14
193 %14 = OpLabel
194 %24 = OpCopyObject %6 %7
195 OpBranchConditional %7 %13 %15
196 %15 = OpLabel
197 OpReturn
198 OpFunctionEnd
199 )";
200
201 const auto env = SPV_ENV_UNIVERSAL_1_5;
202 const auto consumer = nullptr;
203 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
204
205 spvtools::ValidatorOptions validator_options;
206 TransformationContext transformation_context(
207 MakeUnique<FactManager>(context.get()), validator_options);
208 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
209 kConsoleMessageConsumer));
210
211 auto transformation1 = TransformationAddLoopPreheader(8, 40, {});
212 ASSERT_TRUE(
213 transformation1.IsApplicable(context.get(), transformation_context));
214 ApplyAndCheckFreshIds(transformation1, context.get(),
215 &transformation_context);
216
217 // Not enough ids for the OpPhi instructions are given
218 ASSERT_FALSE(TransformationAddLoopPreheader(13, 41, {})
219 .IsApplicable(context.get(), transformation_context));
220
221 // Not enough ids for the OpPhi instructions are given
222 ASSERT_FALSE(TransformationAddLoopPreheader(13, 41, {42})
223 .IsApplicable(context.get(), transformation_context));
224
225 // One of the ids is not fresh
226 ASSERT_FALSE(TransformationAddLoopPreheader(13, 41, {31, 42})
227 .IsApplicable(context.get(), transformation_context));
228
229 // One of the ids is repeated
230 ASSERT_FALSE(TransformationAddLoopPreheader(13, 41, {41, 42})
231 .IsApplicable(context.get(), transformation_context));
232
233 auto transformation2 = TransformationAddLoopPreheader(13, 41, {42, 43});
234 ASSERT_TRUE(
235 transformation2.IsApplicable(context.get(), transformation_context));
236 ApplyAndCheckFreshIds(transformation2, context.get(),
237 &transformation_context);
238
239 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
240 kConsoleMessageConsumer));
241
242 std::string after_transformations = R"(
243 OpCapability Shader
244 %1 = OpExtInstImport "GLSL.std.450"
245 OpMemoryModel Logical GLSL450
246 OpEntryPoint Fragment %4 "main"
247 OpExecutionMode %4 OriginUpperLeft
248 OpSource ESSL 310
249 OpName %4 "main"
250 %2 = OpTypeVoid
251 %3 = OpTypeFunction %2
252 %6 = OpTypeBool
253 %7 = OpConstantFalse %6
254 %4 = OpFunction %2 None %3
255 %5 = OpLabel
256 %20 = OpCopyObject %6 %7
257 OpBranch %40
258 %40 = OpLabel
259 OpBranch %8
260 %8 = OpLabel
261 %31 = OpPhi %6 %20 %40 %21 %9
262 OpLoopMerge %10 %9 None
263 OpBranch %9
264 %9 = OpLabel
265 %21 = OpCopyObject %6 %7
266 OpBranchConditional %7 %8 %10
267 %10 = OpLabel
268 OpSelectionMerge %41 None
269 OpBranchConditional %7 %11 %12
270 %11 = OpLabel
271 %22 = OpCopyObject %6 %7
272 OpBranch %41
273 %12 = OpLabel
274 %23 = OpCopyObject %6 %7
275 OpBranch %41
276 %41 = OpLabel
277 %42 = OpPhi %6 %22 %11 %23 %12
278 %43 = OpPhi %6 %7 %11 %7 %12
279 OpBranch %13
280 %13 = OpLabel
281 %32 = OpPhi %6 %42 %41 %24 %14
282 %33 = OpPhi %6 %43 %41 %24 %14
283 OpLoopMerge %15 %14 None
284 OpBranch %14
285 %14 = OpLabel
286 %24 = OpCopyObject %6 %7
287 OpBranchConditional %7 %13 %15
288 %15 = OpLabel
289 OpReturn
290 OpFunctionEnd
291 )";
292
293 ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
294 }
295
296 } // namespace
297 } // namespace fuzz
298 } // namespace spvtools
299