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