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