1 // Copyright (c) 2021 Shiyu Liu
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_two_functions.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(TransformationSwapTwoFunctionsTest,SimpleTest)25 TEST(TransformationSwapTwoFunctionsTest, SimpleTest) {
26 // float multiplyBy2(in float value) {
27 // return value*2.0;
28 // }
29
30 // float multiplyBy4(in float value) {
31 // return multiplyBy2(value)*2.0;
32 // }
33
34 // float multiplyBy8(in float value) {
35 // return multiplyBy2(value)*multiplyBy4(value);
36 // }
37
38 // layout(location=0) in float value;
39 // void main() { //4
40 // multiplyBy2(3.7); //10
41 // multiplyBy4(3.9); //13
42 // multiplyBy8(5.0); //16
43 // }
44
45 std::string shader = R"(
46 OpCapability Shader
47 %1 = OpExtInstImport "GLSL.std.450"
48 OpMemoryModel Logical GLSL450
49 OpEntryPoint Fragment %4 "main" %48
50 OpExecutionMode %4 OriginUpperLeft
51 OpSource ESSL 310
52 OpName %4 "main"
53 OpName %10 "multiplyBy2(f1;"
54 OpName %9 "value"
55 OpName %13 "multiplyBy4(f1;"
56 OpName %12 "value"
57 OpName %16 "multiplyBy8(f1;"
58 OpName %15 "value"
59 OpName %23 "param"
60 OpName %29 "param"
61 OpName %32 "param"
62 OpName %39 "param"
63 OpName %42 "param"
64 OpName %45 "param"
65 OpName %48 "value"
66 OpDecorate %48 Location 0
67 %2 = OpTypeVoid
68 %3 = OpTypeFunction %2
69 %6 = OpTypeFloat 32
70 %7 = OpTypePointer Function %6
71 %8 = OpTypeFunction %6 %7
72 %19 = OpConstant %6 2
73 %38 = OpConstant %6 3.70000005
74 %41 = OpConstant %6 3.9000001
75 %44 = OpConstant %6 5
76 %47 = OpTypePointer Input %6
77 %48 = OpVariable %47 Input
78 %4 = OpFunction %2 None %3
79 %5 = OpLabel
80 %39 = OpVariable %7 Function
81 %42 = OpVariable %7 Function
82 %45 = OpVariable %7 Function
83 OpStore %39 %38
84 %40 = OpFunctionCall %6 %10 %39
85 OpStore %42 %41
86 %43 = OpFunctionCall %6 %13 %42
87 OpStore %45 %44
88 %46 = OpFunctionCall %6 %16 %45
89 OpReturn
90 OpFunctionEnd
91 %10 = OpFunction %6 None %8
92 %9 = OpFunctionParameter %7
93 %11 = OpLabel
94 %18 = OpLoad %6 %9
95 %20 = OpFMul %6 %18 %19
96 OpReturnValue %20
97 OpFunctionEnd
98 %13 = OpFunction %6 None %8
99 %12 = OpFunctionParameter %7
100 %14 = OpLabel
101 %23 = OpVariable %7 Function
102 %24 = OpLoad %6 %12
103 OpStore %23 %24
104 %25 = OpFunctionCall %6 %10 %23
105 %26 = OpFMul %6 %25 %19
106 OpReturnValue %26
107 OpFunctionEnd
108 %16 = OpFunction %6 None %8
109 %15 = OpFunctionParameter %7
110 %17 = OpLabel
111 %29 = OpVariable %7 Function
112 %32 = OpVariable %7 Function
113 %30 = OpLoad %6 %15
114 OpStore %29 %30
115 %31 = OpFunctionCall %6 %10 %29
116 %33 = OpLoad %6 %15
117 OpStore %32 %33
118 %34 = OpFunctionCall %6 %13 %32
119 %35 = OpFMul %6 %31 %34
120 OpReturnValue %35
121 OpFunctionEnd
122 )";
123 const auto env = SPV_ENV_UNIVERSAL_1_3;
124 const auto consumer = nullptr;
125 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
126 spvtools::ValidatorOptions validator_options;
127
128 // Check context validity.
129 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
130 kConsoleMessageConsumer));
131
132 TransformationContext transformation_context(
133 MakeUnique<FactManager>(context.get()), validator_options);
134
135 #ifndef NDEBUG
136 // Function should not swap with itself.
137 ASSERT_DEATH(TransformationSwapTwoFunctions(4, 4).IsApplicable(
138 context.get(), transformation_context),
139 "The two function ids cannot be the same.");
140 #endif
141
142 // Function with id 29 does not exist.
143 ASSERT_FALSE(TransformationSwapTwoFunctions(10, 29).IsApplicable(
144 context.get(), transformation_context));
145
146 // Function with id 30 does not exist.
147 ASSERT_FALSE(TransformationSwapTwoFunctions(30, 13).IsApplicable(
148 context.get(), transformation_context));
149
150 // Both functions with id 5 and 6 do not exist.
151 ASSERT_FALSE(TransformationSwapTwoFunctions(5, 6).IsApplicable(
152 context.get(), transformation_context));
153
154 // Function with result_id 10 and 13 should swap successfully.
155 auto swap_test5 = TransformationSwapTwoFunctions(10, 13);
156 ASSERT_TRUE(swap_test5.IsApplicable(context.get(), transformation_context));
157
158 // Get the definitions of functions 10 and 13, as recorded by the def-use
159 // manager.
160 auto def_use_manager = context->get_def_use_mgr();
161 auto function_10_inst = def_use_manager->GetDef(10);
162 auto function_13_inst = def_use_manager->GetDef(13);
163
164 ApplyAndCheckFreshIds(swap_test5, context.get(), &transformation_context);
165
166 // Check that def-use information for functions 10 and 13 has been preserved
167 // by the transformation.
168 ASSERT_EQ(function_10_inst, def_use_manager->GetDef(10));
169 ASSERT_EQ(function_13_inst, def_use_manager->GetDef(13));
170
171 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
172 kConsoleMessageConsumer));
173
174 std::string after_transformation = R"(
175 OpCapability Shader
176 %1 = OpExtInstImport "GLSL.std.450"
177 OpMemoryModel Logical GLSL450
178 OpEntryPoint Fragment %4 "main" %48
179 OpExecutionMode %4 OriginUpperLeft
180 OpSource ESSL 310
181 OpName %4 "main"
182 OpName %10 "multiplyBy2(f1;"
183 OpName %9 "value"
184 OpName %13 "multiplyBy4(f1;"
185 OpName %12 "value"
186 OpName %16 "multiplyBy8(f1;"
187 OpName %15 "value"
188 OpName %23 "param"
189 OpName %29 "param"
190 OpName %32 "param"
191 OpName %39 "param"
192 OpName %42 "param"
193 OpName %45 "param"
194 OpName %48 "value"
195 OpDecorate %48 Location 0
196 %2 = OpTypeVoid
197 %3 = OpTypeFunction %2
198 %6 = OpTypeFloat 32
199 %7 = OpTypePointer Function %6
200 %8 = OpTypeFunction %6 %7
201 %19 = OpConstant %6 2
202 %38 = OpConstant %6 3.70000005
203 %41 = OpConstant %6 3.9000001
204 %44 = OpConstant %6 5
205 %47 = OpTypePointer Input %6
206 %48 = OpVariable %47 Input
207 %4 = OpFunction %2 None %3
208 %5 = OpLabel
209 %39 = OpVariable %7 Function
210 %42 = OpVariable %7 Function
211 %45 = OpVariable %7 Function
212 OpStore %39 %38
213 %40 = OpFunctionCall %6 %10 %39
214 OpStore %42 %41
215 %43 = OpFunctionCall %6 %13 %42
216 OpStore %45 %44
217 %46 = OpFunctionCall %6 %16 %45
218 OpReturn
219 OpFunctionEnd
220 %13 = OpFunction %6 None %8
221 %12 = OpFunctionParameter %7
222 %14 = OpLabel
223 %23 = OpVariable %7 Function
224 %24 = OpLoad %6 %12
225 OpStore %23 %24
226 %25 = OpFunctionCall %6 %10 %23
227 %26 = OpFMul %6 %25 %19
228 OpReturnValue %26
229 OpFunctionEnd
230 %10 = OpFunction %6 None %8
231 %9 = OpFunctionParameter %7
232 %11 = OpLabel
233 %18 = OpLoad %6 %9
234 %20 = OpFMul %6 %18 %19
235 OpReturnValue %20
236 OpFunctionEnd
237 %16 = OpFunction %6 None %8
238 %15 = OpFunctionParameter %7
239 %17 = OpLabel
240 %29 = OpVariable %7 Function
241 %32 = OpVariable %7 Function
242 %30 = OpLoad %6 %15
243 OpStore %29 %30
244 %31 = OpFunctionCall %6 %10 %29
245 %33 = OpLoad %6 %15
246 OpStore %32 %33
247 %34 = OpFunctionCall %6 %13 %32
248 %35 = OpFMul %6 %31 %34
249 OpReturnValue %35
250 OpFunctionEnd
251 )";
252 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
253 }
254
255 } // namespace
256 } // namespace fuzz
257 } // namespace spvtools
258