• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fuzzer_pass_add_opphi_synonyms.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/pseudo_random_generator.h"
20 #include "test/fuzz/fuzz_test_util.h"
21 
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25 
MakeSynonymFact(uint32_t first,uint32_t second)26 protobufs::Fact MakeSynonymFact(uint32_t first, uint32_t second) {
27   protobufs::FactDataSynonym data_synonym_fact;
28   *data_synonym_fact.mutable_data1() = MakeDataDescriptor(first, {});
29   *data_synonym_fact.mutable_data2() = MakeDataDescriptor(second, {});
30   protobufs::Fact result;
31   *result.mutable_data_synonym_fact() = data_synonym_fact;
32   return result;
33 }
34 
35 // Adds synonym facts to the fact manager.
SetUpIdSynonyms(FactManager * fact_manager)36 void SetUpIdSynonyms(FactManager* fact_manager) {
37   // Synonyms {9, 11, 15, 16, 21, 22}
38   fact_manager->MaybeAddFact(MakeSynonymFact(11, 9));
39   fact_manager->MaybeAddFact(MakeSynonymFact(15, 9));
40   fact_manager->MaybeAddFact(MakeSynonymFact(16, 9));
41   fact_manager->MaybeAddFact(MakeSynonymFact(21, 9));
42   fact_manager->MaybeAddFact(MakeSynonymFact(22, 9));
43 
44   // Synonyms {10, 23}
45   fact_manager->MaybeAddFact(MakeSynonymFact(10, 23));
46 
47   // Synonyms {14, 27}
48   fact_manager->MaybeAddFact(MakeSynonymFact(14, 27));
49 
50   // Synonyms {24, 26, 30}
51   fact_manager->MaybeAddFact(MakeSynonymFact(26, 24));
52   fact_manager->MaybeAddFact(MakeSynonymFact(30, 24));
53 }
54 
55 // Returns true if the given lists have the same elements, regardless of their
56 // order.
57 template <typename T>
ListsHaveTheSameElements(const std::vector<T> & list1,const std::vector<T> & list2)58 bool ListsHaveTheSameElements(const std::vector<T>& list1,
59                               const std::vector<T>& list2) {
60   auto sorted1 = list1;
61   std::sort(sorted1.begin(), sorted1.end());
62 
63   auto sorted2 = list2;
64   std::sort(sorted2.begin(), sorted2.end());
65 
66   return sorted1 == sorted2;
67 }
68 
69 std::string shader = R"(
70                OpCapability Shader
71           %1 = OpExtInstImport "GLSL.std.450"
72                OpMemoryModel Logical GLSL450
73                OpEntryPoint Fragment %2 "main"
74                OpExecutionMode %2 OriginUpperLeft
75                OpSource ESSL 310
76                OpName %2 "main"
77           %3 = OpTypeVoid
78           %4 = OpTypeFunction %3
79           %5 = OpTypeBool
80           %6 = OpConstantTrue %5
81           %7 = OpTypeInt 32 1
82          %31 = OpTypeFunction %7
83           %8 = OpTypeInt 32 0
84           %9 = OpConstant %7 1
85          %10 = OpConstant %7 2
86          %11 = OpConstant %8 1
87          %12 = OpTypePointer Function %7
88           %2 = OpFunction %3 None %4
89          %13 = OpLabel
90          %14 = OpVariable %12 Function
91          %15 = OpCopyObject %7 %9
92          %16 = OpCopyObject %8 %11
93                OpBranch %17
94          %17 = OpLabel
95                OpSelectionMerge %18 None
96                OpBranchConditional %6 %19 %20
97          %19 = OpLabel
98          %21 = OpCopyObject %7 %15
99          %22 = OpCopyObject %8 %16
100          %23 = OpCopyObject %7 %10
101          %24 = OpIAdd %7 %9 %10
102                OpBranch %18
103          %20 = OpLabel
104                OpBranch %18
105          %18 = OpLabel
106          %26 = OpIAdd %7 %15 %10
107          %27 = OpCopyObject %12 %14
108                OpSelectionMerge %28 None
109                OpBranchConditional %6 %29 %28
110          %29 = OpLabel
111          %30 = OpCopyObject %7 %26
112                OpBranch %28
113          %28 = OpLabel
114                OpReturn
115                OpFunctionEnd
116          %32 = OpFunction %7 None %31
117          %33 = OpLabel
118                OpReturnValue %9
119                OpFunctionEnd
120 )";
121 
TEST(FuzzerPassAddOpPhiSynonymsTest,HelperFunctions)122 TEST(FuzzerPassAddOpPhiSynonymsTest, HelperFunctions) {
123   const auto env = SPV_ENV_UNIVERSAL_1_5;
124   const auto consumer = nullptr;
125   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
126   spvtools::ValidatorOptions validator_options;
127   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
128                                                kConsoleMessageConsumer));
129   TransformationContext transformation_context(
130       MakeUnique<FactManager>(context.get()), validator_options);
131   FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
132                                false);
133   protobufs::TransformationSequence transformation_sequence;
134 
135   FuzzerPassAddOpPhiSynonyms fuzzer_pass(context.get(), &transformation_context,
136                                          &fuzzer_context,
137                                          &transformation_sequence, false);
138 
139   SetUpIdSynonyms(transformation_context.GetFactManager());
140 
141   std::vector<std::set<uint32_t>> expected_equivalence_classes = {
142       {9, 15, 21}, {11, 16, 22}, {10, 23}, {6}, {24, 26, 30}};
143 
144   ASSERT_TRUE(ListsHaveTheSameElements<std::set<uint32_t>>(
145       fuzzer_pass.GetIdEquivalenceClasses(), expected_equivalence_classes));
146 
147   // The set {24, 26, 30} is not suitable for 18 (none if the ids is available
148   // for predecessor 20).
149   ASSERT_FALSE(
150       fuzzer_pass.EquivalenceClassIsSuitableForBlock({24, 26, 30}, 18, 1));
151 
152   // The set {6} is not suitable for 18 if we require at least 2 distinct
153   // available ids.
154   ASSERT_FALSE(fuzzer_pass.EquivalenceClassIsSuitableForBlock({6}, 18, 2));
155 
156   // Only id 26 from the set {24, 26, 30} is available to use for the
157   // transformation at block 29, so the set is not suitable if we want at least
158   // 2 available ids.
159   ASSERT_FALSE(
160       fuzzer_pass.EquivalenceClassIsSuitableForBlock({24, 26, 30}, 29, 2));
161 
162   ASSERT_TRUE(
163       fuzzer_pass.EquivalenceClassIsSuitableForBlock({24, 26, 30}, 29, 1));
164 
165   // %21 is not available at the end of block 20.
166   ASSERT_TRUE(ListsHaveTheSameElements<uint32_t>(
167       fuzzer_pass.GetSuitableIds({9, 15, 21}, 20), {9, 15}));
168 
169   // %24 and %30 are not available at the end of block 18.
170   ASSERT_TRUE(ListsHaveTheSameElements<uint32_t>(
171       fuzzer_pass.GetSuitableIds({24, 26, 30}, 18), {26}));
172 }
173 
174 }  // namespace
175 }  // namespace fuzz
176 }  // namespace spvtools
177