1 // Copyright (c) 2021 Mostafa Ashraf
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_swap_function_variables.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(TransformationSwapFunctionVariables,NotApplicable)26 TEST(TransformationSwapFunctionVariables, NotApplicable) {
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 320
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeInt 32 1
37 %7 = OpTypePointer Function %6
38 %8 = OpTypeFloat 32
39 %9 = OpTypePointer Function %8
40 %10 = OpTypeVector %8 2
41 %11 = OpTypePointer Function %10
42 %12 = OpTypeVector %8 3
43 %13 = OpTypeMatrix %12 3
44 %14 = OpTypePointer Function %13
45 %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
46 %4 = OpFunction %2 None %3
47 %5 = OpLabel
48 %24 = OpVariable %7 Function
49 %25 = OpVariable %9 Function
50 %26 = OpVariable %11 Function
51 %27 = OpVariable %14 Function
52 %28 = OpVariable %7 Function
53 %29 = OpVariable %7 Function
54 %30 = OpVariable %7 Function
55 %32 = OpVariable %9 Function
56 %34 = OpVariable %11 Function
57 %36 = OpVariable %14 Function
58 %38 = OpVariable %7 Function
59 %40 = OpVariable %7 Function
60 %31 = OpLoad %6 %24
61 OpStore %30 %31
62 %33 = OpLoad %8 %25
63 OpStore %32 %33
64 %35 = OpLoad %10 %26
65 OpStore %34 %35
66 %37 = OpLoad %13 %27
67 OpStore %36 %37
68 %39 = OpLoad %6 %28
69 OpStore %38 %39
70 %41 = OpLoad %6 %29
71 OpStore %40 %41
72 %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
73 OpReturn
74 OpFunctionEnd
75 %22 = OpFunction %2 None %15
76 %16 = OpFunctionParameter %7
77 %17 = OpFunctionParameter %9
78 %18 = OpFunctionParameter %11
79 %19 = OpFunctionParameter %14
80 %20 = OpFunctionParameter %7
81 %21 = OpFunctionParameter %7
82 %23 = OpLabel
83 OpReturn
84 OpFunctionEnd
85 )";
86
87 const auto env = SPV_ENV_UNIVERSAL_1_5;
88 const auto consumer = nullptr;
89 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
90 spvtools::ValidatorOptions validator_options;
91
92 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
93 kConsoleMessageConsumer));
94 TransformationContext transformation_context(
95 MakeUnique<FactManager>(context.get()), validator_options);
96
97 #ifndef NDEBUG
98 // Can't swap variable with itself.
99 ASSERT_DEATH(TransformationSwapFunctionVariables(7, 7).IsApplicable(
100 context.get(), transformation_context),
101 "Two results ids are equal");
102 #endif
103
104 // Invalid because 200 is not the id of an instruction.
105 ASSERT_FALSE(TransformationSwapFunctionVariables(1, 200).IsApplicable(
106 context.get(), transformation_context));
107 // Invalid because 5 is not the id of an instruction.
108 ASSERT_FALSE(TransformationSwapFunctionVariables(5, 24).IsApplicable(
109 context.get(), transformation_context));
110 // Can't swap two instructions from two different blocks.
111 ASSERT_FALSE(TransformationSwapFunctionVariables(16, 26).IsApplicable(
112 context.get(), transformation_context));
113 }
114
TEST(TransformationSwapFunctionVariables,IsApplicable)115 TEST(TransformationSwapFunctionVariables, IsApplicable) {
116 std::string shader = R"(
117 OpCapability Shader
118 %1 = OpExtInstImport "GLSL.std.450"
119 OpMemoryModel Logical GLSL450
120 OpEntryPoint Fragment %4 "main"
121 OpExecutionMode %4 OriginUpperLeft
122 OpSource ESSL 320
123 %2 = OpTypeVoid
124 %3 = OpTypeFunction %2
125 %6 = OpTypeInt 32 1
126 %7 = OpTypePointer Function %6
127 %8 = OpTypeFloat 32
128 %9 = OpTypePointer Function %8
129 %10 = OpTypeVector %8 2
130 %11 = OpTypePointer Function %10
131 %12 = OpTypeVector %8 3
132 %13 = OpTypeMatrix %12 3
133 %14 = OpTypePointer Function %13
134 %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
135 %4 = OpFunction %2 None %3
136 %5 = OpLabel
137 %24 = OpVariable %7 Function
138 %25 = OpVariable %9 Function
139 %26 = OpVariable %11 Function
140 %27 = OpVariable %14 Function
141 %28 = OpVariable %7 Function
142 %29 = OpVariable %7 Function
143 %30 = OpVariable %7 Function
144 %32 = OpVariable %9 Function
145 %34 = OpVariable %11 Function
146 %36 = OpVariable %14 Function
147 %38 = OpVariable %7 Function
148 %40 = OpVariable %7 Function
149 %31 = OpLoad %6 %24
150 OpStore %30 %31
151 %33 = OpLoad %8 %25
152 OpStore %32 %33
153 %35 = OpLoad %10 %26
154 OpStore %34 %35
155 %37 = OpLoad %13 %27
156 OpStore %36 %37
157 %39 = OpLoad %6 %28
158 OpStore %38 %39
159 %41 = OpLoad %6 %29
160 OpStore %40 %41
161 %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
162 OpReturn
163 OpFunctionEnd
164 %22 = OpFunction %2 None %15
165 %16 = OpFunctionParameter %7
166 %17 = OpFunctionParameter %9
167 %18 = OpFunctionParameter %11
168 %19 = OpFunctionParameter %14
169 %20 = OpFunctionParameter %7
170 %21 = OpFunctionParameter %7
171 %23 = OpLabel
172 OpReturn
173 OpFunctionEnd
174 )";
175
176 const auto env = SPV_ENV_UNIVERSAL_1_5;
177 const auto consumer = nullptr;
178 // Get Unique pointer of IRContext.
179 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
180 spvtools::ValidatorOptions validator_options;
181
182 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
183 kConsoleMessageConsumer));
184 TransformationContext transformation_context(
185 MakeUnique<FactManager>(context.get()), validator_options);
186
187 // Successful transformations
188 {
189 auto first_instruction = context->get_def_use_mgr()->GetDef(24);
190 auto second_instruction = context->get_def_use_mgr()->GetDef(28);
191 // Swap two OpVariable instructions in the same function.
192 TransformationSwapFunctionVariables transformation(24, 28);
193
194 ASSERT_TRUE(
195 transformation.IsApplicable(context.get(), transformation_context));
196
197 ApplyAndCheckFreshIds(transformation, context.get(),
198 &transformation_context);
199
200 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
201 context.get(), validator_options, kConsoleMessageConsumer));
202
203 ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(24));
204 ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(28));
205 }
206 {
207 auto first_instruction = context->get_def_use_mgr()->GetDef(38);
208 auto second_instruction = context->get_def_use_mgr()->GetDef(40);
209 // Swap two OpVariable instructions in the same function.
210 TransformationSwapFunctionVariables transformation(38, 40);
211
212 ASSERT_TRUE(
213 transformation.IsApplicable(context.get(), transformation_context));
214
215 ApplyAndCheckFreshIds(transformation, context.get(),
216 &transformation_context);
217
218 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
219 context.get(), validator_options, kConsoleMessageConsumer));
220
221 ASSERT_EQ(first_instruction, context->get_def_use_mgr()->GetDef(38));
222 ASSERT_EQ(second_instruction, context->get_def_use_mgr()->GetDef(40));
223 }
224 std::string after_transformation = R"(
225 OpCapability Shader
226 %1 = OpExtInstImport "GLSL.std.450"
227 OpMemoryModel Logical GLSL450
228 OpEntryPoint Fragment %4 "main"
229 OpExecutionMode %4 OriginUpperLeft
230 OpSource ESSL 320
231 %2 = OpTypeVoid
232 %3 = OpTypeFunction %2
233 %6 = OpTypeInt 32 1
234 %7 = OpTypePointer Function %6
235 %8 = OpTypeFloat 32
236 %9 = OpTypePointer Function %8
237 %10 = OpTypeVector %8 2
238 %11 = OpTypePointer Function %10
239 %12 = OpTypeVector %8 3
240 %13 = OpTypeMatrix %12 3
241 %14 = OpTypePointer Function %13
242 %15 = OpTypeFunction %2 %7 %9 %11 %14 %7 %7
243 %4 = OpFunction %2 None %3
244 %5 = OpLabel
245 %28 = OpVariable %7 Function
246 %25 = OpVariable %9 Function
247 %26 = OpVariable %11 Function
248 %27 = OpVariable %14 Function
249 %24 = OpVariable %7 Function
250 %29 = OpVariable %7 Function
251 %30 = OpVariable %7 Function
252 %32 = OpVariable %9 Function
253 %34 = OpVariable %11 Function
254 %36 = OpVariable %14 Function
255 %40 = OpVariable %7 Function
256 %38 = OpVariable %7 Function
257 %31 = OpLoad %6 %24
258 OpStore %30 %31
259 %33 = OpLoad %8 %25
260 OpStore %32 %33
261 %35 = OpLoad %10 %26
262 OpStore %34 %35
263 %37 = OpLoad %13 %27
264 OpStore %36 %37
265 %39 = OpLoad %6 %28
266 OpStore %38 %39
267 %41 = OpLoad %6 %29
268 OpStore %40 %41
269 %42 = OpFunctionCall %2 %22 %30 %32 %34 %36 %38 %40
270 OpReturn
271 OpFunctionEnd
272 %22 = OpFunction %2 None %15
273 %16 = OpFunctionParameter %7
274 %17 = OpFunctionParameter %9
275 %18 = OpFunctionParameter %11
276 %19 = OpFunctionParameter %14
277 %20 = OpFunctionParameter %7
278 %21 = OpFunctionParameter %7
279 %23 = OpLabel
280 OpReturn
281 OpFunctionEnd
282 )";
283 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
284 }
285
286 } // namespace
287 } // namespace fuzz
288 } // namespace spvtools
289