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