• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_composite_extract.h"
16 #include "source/fuzz/instruction_descriptor.h"
17 #include "test/fuzz/fuzz_test_util.h"
18 
19 namespace spvtools {
20 namespace fuzz {
21 namespace {
22 
TEST(TransformationCompositeExtractTest,BasicTest)23 TEST(TransformationCompositeExtractTest, BasicTest) {
24   std::string shader = R"(
25                OpCapability Shader
26           %1 = OpExtInstImport "GLSL.std.450"
27                OpMemoryModel Logical GLSL450
28                OpEntryPoint Fragment %4 "main"
29                OpExecutionMode %4 OriginUpperLeft
30                OpSource ESSL 310
31                OpName %4 "main"
32                OpName %8 "a"
33                OpName %10 "b"
34                OpName %17 "FunnyPoint"
35                OpMemberName %17 0 "x"
36                OpMemberName %17 1 "y"
37                OpMemberName %17 2 "z"
38                OpName %19 "p"
39           %2 = OpTypeVoid
40           %3 = OpTypeFunction %2
41           %6 = OpTypeInt 32 1
42           %7 = OpTypePointer Function %6
43          %12 = OpTypeBool
44          %16 = OpTypeFloat 32
45          %17 = OpTypeStruct %16 %16 %6
46          %81 = OpTypeStruct %17 %16
47          %18 = OpTypePointer Function %17
48          %20 = OpConstant %6 0
49          %23 = OpTypePointer Function %16
50          %26 = OpConstant %6 1
51          %30 = OpConstant %6 2
52          %80 = OpUndef %16
53           %4 = OpFunction %2 None %3
54           %5 = OpLabel
55           %8 = OpVariable %7 Function
56          %10 = OpVariable %7 Function
57          %19 = OpVariable %18 Function
58           %9 = OpLoad %6 %8
59          %11 = OpLoad %6 %10
60         %100 = OpCompositeConstruct %17 %80 %80 %26
61         %104 = OpCompositeConstruct %81 %100 %80
62          %13 = OpIEqual %12 %9 %11
63                OpSelectionMerge %15 None
64                OpBranchConditional %13 %14 %25
65          %14 = OpLabel
66          %21 = OpLoad %6 %8
67          %22 = OpConvertSToF %16 %21
68         %101 = OpCompositeConstruct %17 %22 %80 %30
69          %24 = OpAccessChain %23 %19 %20
70                OpStore %24 %22
71                OpBranch %15
72          %25 = OpLabel
73          %27 = OpLoad %6 %10
74          %28 = OpConvertSToF %16 %27
75         %102 = OpCompositeConstruct %17 %80 %28 %27
76          %29 = OpAccessChain %23 %19 %26
77                OpStore %29 %28
78                OpBranch %15
79          %15 = OpLabel
80          %31 = OpAccessChain %23 %19 %20
81          %32 = OpLoad %16 %31
82          %33 = OpAccessChain %23 %19 %26
83          %34 = OpLoad %16 %33
84         %103 = OpCompositeConstruct %17 %34 %32 %9
85          %35 = OpFAdd %16 %32 %34
86          %36 = OpConvertFToS %6 %35
87          %37 = OpAccessChain %7 %19 %30
88                OpStore %37 %36
89                OpReturn
90                OpFunctionEnd
91   )";
92 
93   const auto env = SPV_ENV_UNIVERSAL_1_4;
94   const auto consumer = nullptr;
95   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
96   ASSERT_TRUE(IsValid(env, context.get()));
97 
98   FactManager fact_manager;
99   spvtools::ValidatorOptions validator_options;
100   TransformationContext transformation_context(&fact_manager,
101                                                validator_options);
102 
103   // Instruction does not exist.
104   ASSERT_FALSE(TransformationCompositeExtract(
105                    MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0})
106                    .IsApplicable(context.get(), transformation_context));
107 
108   // Id for composite is not a composite.
109   ASSERT_FALSE(TransformationCompositeExtract(
110                    MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {})
111                    .IsApplicable(context.get(), transformation_context));
112 
113   // Composite does not dominate instruction being inserted before.
114   ASSERT_FALSE(
115       TransformationCompositeExtract(
116           MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0})
117           .IsApplicable(context.get(), transformation_context));
118 
119   // Too many indices for extraction from struct composite.
120   ASSERT_FALSE(
121       TransformationCompositeExtract(
122           MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0})
123           .IsApplicable(context.get(), transformation_context));
124 
125   // Too many indices for extraction from struct composite.
126   ASSERT_FALSE(
127       TransformationCompositeExtract(
128           MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0})
129           .IsApplicable(context.get(), transformation_context));
130 
131   // Out of bounds index for extraction from struct composite.
132   ASSERT_FALSE(
133       TransformationCompositeExtract(
134           MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3})
135           .IsApplicable(context.get(), transformation_context));
136 
137   // Result id already used.
138   ASSERT_FALSE(TransformationCompositeExtract(
139                    MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0})
140                    .IsApplicable(context.get(), transformation_context));
141 
142   TransformationCompositeExtract transformation_1(
143       MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
144   ASSERT_TRUE(
145       transformation_1.IsApplicable(context.get(), transformation_context));
146   transformation_1.Apply(context.get(), &transformation_context);
147   ASSERT_TRUE(IsValid(env, context.get()));
148 
149   TransformationCompositeExtract transformation_2(
150       MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2});
151   ASSERT_TRUE(
152       transformation_2.IsApplicable(context.get(), transformation_context));
153   transformation_2.Apply(context.get(), &transformation_context);
154   ASSERT_TRUE(IsValid(env, context.get()));
155 
156   TransformationCompositeExtract transformation_3(
157       MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0});
158   ASSERT_TRUE(
159       transformation_3.IsApplicable(context.get(), transformation_context));
160   transformation_3.Apply(context.get(), &transformation_context);
161   ASSERT_TRUE(IsValid(env, context.get()));
162 
163   TransformationCompositeExtract transformation_4(
164       MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0});
165   ASSERT_TRUE(
166       transformation_4.IsApplicable(context.get(), transformation_context));
167   transformation_4.Apply(context.get(), &transformation_context);
168   ASSERT_TRUE(IsValid(env, context.get()));
169 
170   TransformationCompositeExtract transformation_5(
171       MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2});
172   ASSERT_TRUE(
173       transformation_5.IsApplicable(context.get(), transformation_context));
174   transformation_5.Apply(context.get(), &transformation_context);
175   ASSERT_TRUE(IsValid(env, context.get()));
176 
177   TransformationCompositeExtract transformation_6(
178       MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1});
179   ASSERT_TRUE(
180       transformation_6.IsApplicable(context.get(), transformation_context));
181   transformation_6.Apply(context.get(), &transformation_context);
182   ASSERT_TRUE(IsValid(env, context.get()));
183 
184   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
185       MakeDataDescriptor(201, {}), MakeDataDescriptor(100, {2}),
186       context.get()));
187   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
188       MakeDataDescriptor(202, {}), MakeDataDescriptor(104, {0, 2}),
189       context.get()));
190   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
191       MakeDataDescriptor(203, {}), MakeDataDescriptor(104, {0}),
192       context.get()));
193   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
194       MakeDataDescriptor(204, {}), MakeDataDescriptor(101, {0}),
195       context.get()));
196   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
197       MakeDataDescriptor(205, {}), MakeDataDescriptor(102, {2}),
198       context.get()));
199   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
200       MakeDataDescriptor(206, {}), MakeDataDescriptor(103, {1}),
201       context.get()));
202 
203   std::string after_transformation = R"(
204                OpCapability Shader
205           %1 = OpExtInstImport "GLSL.std.450"
206                OpMemoryModel Logical GLSL450
207                OpEntryPoint Fragment %4 "main"
208                OpExecutionMode %4 OriginUpperLeft
209                OpSource ESSL 310
210                OpName %4 "main"
211                OpName %8 "a"
212                OpName %10 "b"
213                OpName %17 "FunnyPoint"
214                OpMemberName %17 0 "x"
215                OpMemberName %17 1 "y"
216                OpMemberName %17 2 "z"
217                OpName %19 "p"
218           %2 = OpTypeVoid
219           %3 = OpTypeFunction %2
220           %6 = OpTypeInt 32 1
221           %7 = OpTypePointer Function %6
222          %12 = OpTypeBool
223          %16 = OpTypeFloat 32
224          %17 = OpTypeStruct %16 %16 %6
225          %81 = OpTypeStruct %17 %16
226          %18 = OpTypePointer Function %17
227          %20 = OpConstant %6 0
228          %23 = OpTypePointer Function %16
229          %26 = OpConstant %6 1
230          %30 = OpConstant %6 2
231          %80 = OpUndef %16
232           %4 = OpFunction %2 None %3
233           %5 = OpLabel
234           %8 = OpVariable %7 Function
235          %10 = OpVariable %7 Function
236          %19 = OpVariable %18 Function
237           %9 = OpLoad %6 %8
238          %11 = OpLoad %6 %10
239         %100 = OpCompositeConstruct %17 %80 %80 %26
240         %104 = OpCompositeConstruct %81 %100 %80
241          %13 = OpIEqual %12 %9 %11
242                OpSelectionMerge %15 None
243                OpBranchConditional %13 %14 %25
244          %14 = OpLabel
245          %21 = OpLoad %6 %8
246          %22 = OpConvertSToF %16 %21
247         %101 = OpCompositeConstruct %17 %22 %80 %30
248          %24 = OpAccessChain %23 %19 %20
249         %204 = OpCompositeExtract %16 %101 0
250                OpStore %24 %22
251                OpBranch %15
252          %25 = OpLabel
253          %27 = OpLoad %6 %10
254          %28 = OpConvertSToF %16 %27
255         %102 = OpCompositeConstruct %17 %80 %28 %27
256         %203 = OpCompositeExtract %17 %104 0
257          %29 = OpAccessChain %23 %19 %26
258                OpStore %29 %28
259         %205 = OpCompositeExtract %6 %102 2
260                OpBranch %15
261          %15 = OpLabel
262          %31 = OpAccessChain %23 %19 %20
263          %32 = OpLoad %16 %31
264          %33 = OpAccessChain %23 %19 %26
265          %34 = OpLoad %16 %33
266         %103 = OpCompositeConstruct %17 %34 %32 %9
267          %35 = OpFAdd %16 %32 %34
268         %201 = OpCompositeExtract %6 %100 2
269          %36 = OpConvertFToS %6 %35
270         %202 = OpCompositeExtract %6 %104 0 2
271          %37 = OpAccessChain %7 %19 %30
272                OpStore %37 %36
273         %206 = OpCompositeExtract %16 %103 1
274                OpReturn
275                OpFunctionEnd
276   )";
277   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
278 }
279 
TEST(TransformationCompositeExtractTest,IllegalInsertionPoints)280 TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) {
281   std::string shader = R"(
282                OpCapability Shader
283           %1 = OpExtInstImport "GLSL.std.450"
284                OpMemoryModel Logical GLSL450
285                OpEntryPoint Fragment %4 "main" %51 %27
286                OpExecutionMode %4 OriginUpperLeft
287                OpSource ESSL 310
288                OpName %4 "main"
289                OpName %25 "buf"
290                OpMemberName %25 0 "value"
291                OpName %27 ""
292                OpName %51 "color"
293                OpMemberDecorate %25 0 Offset 0
294                OpDecorate %25 Block
295                OpDecorate %27 DescriptorSet 0
296                OpDecorate %27 Binding 0
297                OpDecorate %51 Location 0
298           %2 = OpTypeVoid
299           %3 = OpTypeFunction %2
300           %6 = OpTypeFloat 32
301           %7 = OpTypeVector %6 4
302          %10 = OpConstant %6 0.300000012
303          %11 = OpConstant %6 0.400000006
304          %12 = OpConstant %6 0.5
305          %13 = OpConstant %6 1
306          %14 = OpConstantComposite %7 %10 %11 %12 %13
307          %15 = OpTypeInt 32 1
308          %18 = OpConstant %15 0
309          %25 = OpTypeStruct %6
310          %26 = OpTypePointer Uniform %25
311          %27 = OpVariable %26 Uniform
312          %28 = OpTypePointer Uniform %6
313          %32 = OpTypeBool
314         %103 = OpConstantTrue %32
315          %34 = OpConstant %6 0.100000001
316          %48 = OpConstant %15 1
317          %50 = OpTypePointer Output %7
318          %51 = OpVariable %50 Output
319         %100 = OpTypePointer Function %6
320           %4 = OpFunction %2 None %3
321           %5 = OpLabel
322         %101 = OpVariable %100 Function
323         %102 = OpVariable %100 Function
324                OpBranch %19
325          %19 = OpLabel
326          %60 = OpPhi %7 %14 %5 %58 %20
327          %59 = OpPhi %15 %18 %5 %49 %20
328          %29 = OpAccessChain %28 %27 %18
329          %30 = OpLoad %6 %29
330          %31 = OpConvertFToS %15 %30
331          %33 = OpSLessThan %32 %59 %31
332                OpLoopMerge %21 %20 None
333                OpBranchConditional %33 %20 %21
334          %20 = OpLabel
335          %39 = OpCompositeExtract %6 %60 0
336          %40 = OpFAdd %6 %39 %34
337          %55 = OpCompositeInsert %7 %40 %60 0
338          %44 = OpCompositeExtract %6 %60 1
339          %45 = OpFSub %6 %44 %34
340          %58 = OpCompositeInsert %7 %45 %55 1
341          %49 = OpIAdd %15 %59 %48
342                OpBranch %19
343          %21 = OpLabel
344                OpStore %51 %60
345                OpSelectionMerge %105 None
346                OpBranchConditional %103 %104 %105
347         %104 = OpLabel
348                OpBranch %105
349         %105 = OpLabel
350                OpReturn
351                OpFunctionEnd
352   )";
353 
354   const auto env = SPV_ENV_UNIVERSAL_1_4;
355   const auto consumer = nullptr;
356   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
357   ASSERT_TRUE(IsValid(env, context.get()));
358 
359   FactManager fact_manager;
360   spvtools::ValidatorOptions validator_options;
361   TransformationContext transformation_context(&fact_manager,
362                                                validator_options);
363 
364   // Cannot insert before the OpVariables of a function.
365   ASSERT_FALSE(
366       TransformationCompositeExtract(
367           MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0})
368           .IsApplicable(context.get(), transformation_context));
369   ASSERT_FALSE(
370       TransformationCompositeExtract(
371           MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1})
372           .IsApplicable(context.get(), transformation_context));
373   ASSERT_FALSE(
374       TransformationCompositeExtract(
375           MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1})
376           .IsApplicable(context.get(), transformation_context));
377   // OK to insert right after the OpVariables.
378   ASSERT_FALSE(TransformationCompositeExtract(
379                    MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1})
380                    .IsApplicable(context.get(), transformation_context));
381 
382   // Cannot insert before the OpPhis of a block.
383   ASSERT_FALSE(TransformationCompositeExtract(
384                    MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2})
385                    .IsApplicable(context.get(), transformation_context));
386   ASSERT_FALSE(TransformationCompositeExtract(
387                    MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3})
388                    .IsApplicable(context.get(), transformation_context));
389   // OK to insert after the OpPhis.
390   ASSERT_TRUE(
391       TransformationCompositeExtract(
392           MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3})
393           .IsApplicable(context.get(), transformation_context));
394 
395   // Cannot insert before OpLoopMerge
396   ASSERT_FALSE(TransformationCompositeExtract(
397                    MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
398                    200, 14, {3})
399                    .IsApplicable(context.get(), transformation_context));
400 
401   // Cannot insert before OpSelectionMerge
402   ASSERT_FALSE(TransformationCompositeExtract(
403                    MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
404                    200, 14, {2})
405                    .IsApplicable(context.get(), transformation_context));
406 }
407 
408 }  // namespace
409 }  // namespace fuzz
410 }  // namespace spvtools
411