1 // Copyright (c) 2020 Vasyl Teliman
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_permute_phi_operands.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(TransformationPermutePhiOperandsTest,BasicTest)25 TEST(TransformationPermutePhiOperandsTest, BasicTest) {
26 std::string shader = R"(
27 OpCapability Shader
28 %1 = OpExtInstImport "GLSL.std.450"
29 OpMemoryModel Logical GLSL450
30 OpEntryPoint Fragment %4 "main"
31 OpExecutionMode %4 OriginUpperLeft
32 OpSource ESSL 310
33 %2 = OpTypeVoid
34 %3 = OpTypeFunction %2
35 %6 = OpTypeInt 32 1
36 %7 = OpTypePointer Function %6
37 %9 = OpConstant %6 0
38 %11 = OpConstant %6 1
39 %14 = OpTypeBool
40 %4 = OpFunction %2 None %3
41 %5 = OpLabel
42 %8 = OpVariable %7 Function
43 %10 = OpVariable %7 Function
44 OpStore %8 %9
45 OpStore %10 %11
46 %12 = OpLoad %6 %8
47 %13 = OpLoad %6 %10
48 %15 = OpSLessThan %14 %12 %13
49 OpSelectionMerge %17 None
50 OpBranchConditional %15 %16 %21
51 %16 = OpLabel
52 %18 = OpLoad %6 %10
53 %19 = OpLoad %6 %8
54 %20 = OpIAdd %6 %19 %18
55 OpBranch %17
56 %21 = OpLabel
57 %22 = OpLoad %6 %10
58 %23 = OpLoad %6 %8
59 %24 = OpISub %6 %23 %22
60 OpBranch %17
61 %17 = OpLabel
62 %25 = OpPhi %6 %20 %16 %24 %21
63 OpStore %8 %25
64 OpReturn
65 OpFunctionEnd
66 )";
67
68 const auto env = SPV_ENV_UNIVERSAL_1_3;
69 const auto consumer = nullptr;
70 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
71 spvtools::ValidatorOptions validator_options;
72 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
73 kConsoleMessageConsumer));
74 TransformationContext transformation_context(
75 MakeUnique<FactManager>(context.get()), validator_options);
76 // Result id is invalid.
77 ASSERT_FALSE(TransformationPermutePhiOperands(26, {}).IsApplicable(
78 context.get(), transformation_context));
79
80 // Result id is not of an OpPhi instruction.
81 ASSERT_FALSE(TransformationPermutePhiOperands(24, {}).IsApplicable(
82 context.get(), transformation_context));
83
84 // Result id is not of an OpPhi instruction.
85 ASSERT_FALSE(TransformationPermutePhiOperands(24, {}).IsApplicable(
86 context.get(), transformation_context));
87
88 // Permutation has invalid size.
89 ASSERT_FALSE(TransformationPermutePhiOperands(25, {0, 1, 2})
90 .IsApplicable(context.get(), transformation_context));
91
92 #ifndef NDEBUG
93 // Permutation has duplicates.
94 ASSERT_DEATH(TransformationPermutePhiOperands(25, {0, 0})
95 .IsApplicable(context.get(), transformation_context),
96 "Permutation has duplicates");
97 #endif
98
99 // Permutation's values are not in range.
100 ASSERT_FALSE(TransformationPermutePhiOperands(25, {1, 2})
101 .IsApplicable(context.get(), transformation_context));
102
103 TransformationPermutePhiOperands transformation(25, {1, 0});
104 ASSERT_TRUE(
105 transformation.IsApplicable(context.get(), transformation_context));
106 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
107
108 // Check that the def-use manager knows that the phi instruction's ids have
109 // been permuted.
110 std::vector<std::pair<uint32_t, uint32_t>> phi_operand_to_new_operand_index =
111 {{20, 4}, {16, 5}, {24, 2}, {21, 3}};
112 for (std::pair<uint32_t, uint32_t>& entry :
113 phi_operand_to_new_operand_index) {
114 context->get_def_use_mgr()->WhileEachUse(
115 entry.first,
116 [&entry](opt::Instruction* inst, uint32_t operand_index) -> bool {
117 if (inst->result_id() == 25) {
118 EXPECT_EQ(entry.second, operand_index);
119 return false;
120 }
121 return true;
122 });
123 }
124
125 std::string after_transformation = R"(
126 OpCapability Shader
127 %1 = OpExtInstImport "GLSL.std.450"
128 OpMemoryModel Logical GLSL450
129 OpEntryPoint Fragment %4 "main"
130 OpExecutionMode %4 OriginUpperLeft
131 OpSource ESSL 310
132 %2 = OpTypeVoid
133 %3 = OpTypeFunction %2
134 %6 = OpTypeInt 32 1
135 %7 = OpTypePointer Function %6
136 %9 = OpConstant %6 0
137 %11 = OpConstant %6 1
138 %14 = OpTypeBool
139 %4 = OpFunction %2 None %3
140 %5 = OpLabel
141 %8 = OpVariable %7 Function
142 %10 = OpVariable %7 Function
143 OpStore %8 %9
144 OpStore %10 %11
145 %12 = OpLoad %6 %8
146 %13 = OpLoad %6 %10
147 %15 = OpSLessThan %14 %12 %13
148 OpSelectionMerge %17 None
149 OpBranchConditional %15 %16 %21
150 %16 = OpLabel
151 %18 = OpLoad %6 %10
152 %19 = OpLoad %6 %8
153 %20 = OpIAdd %6 %19 %18
154 OpBranch %17
155 %21 = OpLabel
156 %22 = OpLoad %6 %10
157 %23 = OpLoad %6 %8
158 %24 = OpISub %6 %23 %22
159 OpBranch %17
160 %17 = OpLabel
161 %25 = OpPhi %6 %24 %21 %20 %16
162 OpStore %8 %25
163 OpReturn
164 OpFunctionEnd
165 )";
166
167 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
168 }
169
170 } // namespace
171 } // namespace fuzz
172 } // namespace spvtools
173