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, spv::Op::OpPhi, 0), 26)
80 .IsApplicable(context.get(), transformation_context));
81
82 // Descriptor for a wrong instruction.
83 ASSERT_FALSE(TransformationSwapConditionalBranchOperands(
84 MakeInstructionDescriptor(25, spv::Op::OpPhi, 0), 26)
85 .IsApplicable(context.get(), transformation_context));
86
87 // Fresh id is not fresh.
88 ASSERT_FALSE(
89 TransformationSwapConditionalBranchOperands(
90 MakeInstructionDescriptor(15, spv::Op::OpBranchConditional, 0), 25)
91 .IsApplicable(context.get(), transformation_context));
92
93 TransformationSwapConditionalBranchOperands transformation(
94 MakeInstructionDescriptor(15, spv::Op::OpBranchConditional, 0), 26);
95 ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(26));
96 ASSERT_EQ(nullptr, context->get_instr_block(26));
97 ASSERT_TRUE(
98 transformation.IsApplicable(context.get(), transformation_context));
99 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
100 ASSERT_EQ(spv::Op::OpLogicalNot,
101 context->get_def_use_mgr()->GetDef(26)->opcode());
102 ASSERT_EQ(5, context->get_instr_block(26)->id());
103 ASSERT_EQ(1, context->get_def_use_mgr()->NumUses(26));
104
105 // Check that the def-use manager knows that the conditional branch operands
106 // have been swapped.
107 std::vector<std::pair<uint32_t, uint32_t>> phi_operand_to_new_operand_index =
108 {{16, 2}, {21, 1}};
109 for (std::pair<uint32_t, uint32_t>& entry :
110 phi_operand_to_new_operand_index) {
111 context->get_def_use_mgr()->WhileEachUse(
112 entry.first,
113 [&entry](opt::Instruction* inst, uint32_t operand_index) -> bool {
114 if (inst->opcode() == spv::Op::OpBranchConditional) {
115 EXPECT_EQ(entry.second, operand_index);
116 return false;
117 }
118 return true;
119 });
120 }
121
122 std::string after_transformation = R"(
123 OpCapability Shader
124 %1 = OpExtInstImport "GLSL.std.450"
125 OpMemoryModel Logical GLSL450
126 OpEntryPoint Fragment %4 "main"
127 OpExecutionMode %4 OriginUpperLeft
128 OpSource ESSL 310
129 %2 = OpTypeVoid
130 %3 = OpTypeFunction %2
131 %6 = OpTypeInt 32 1
132 %7 = OpTypePointer Function %6
133 %9 = OpConstant %6 0
134 %11 = OpConstant %6 1
135 %14 = OpTypeBool
136 %4 = OpFunction %2 None %3
137 %5 = OpLabel
138 %8 = OpVariable %7 Function
139 %10 = OpVariable %7 Function
140 OpStore %8 %9
141 OpStore %10 %11
142 %12 = OpLoad %6 %8
143 %13 = OpLoad %6 %10
144 %15 = OpSLessThan %14 %12 %13
145 %26 = OpLogicalNot %14 %15
146 OpSelectionMerge %17 None
147 OpBranchConditional %26 %21 %16 20 10
148 %16 = OpLabel
149 %18 = OpLoad %6 %10
150 %19 = OpLoad %6 %8
151 %20 = OpIAdd %6 %19 %18
152 OpBranch %17
153 %21 = OpLabel
154 %22 = OpLoad %6 %10
155 %23 = OpLoad %6 %8
156 %24 = OpISub %6 %23 %22
157 OpBranch %17
158 %17 = OpLabel
159 %25 = OpPhi %6 %20 %16 %24 %21
160 OpStore %8 %25
161 OpReturn
162 OpFunctionEnd
163 )";
164
165 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
166 }
167
168 } // namespace
169 } // namespace fuzz
170 } // namespace spvtools
171