1 // Copyright (c) 2017 Google Inc.
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 <string>
16
17 #include "gmock/gmock.h"
18 #include "source/opt/build_module.h"
19 #include "source/opt/value_number_table.h"
20 #include "test/opt/assembly_builder.h"
21 #include "test/opt/pass_fixture.h"
22 #include "test/opt/pass_utils.h"
23
24 namespace spvtools {
25 namespace opt {
26 namespace {
27
28 using ::testing::HasSubstr;
29 using ::testing::MatchesRegex;
30 using LocalRedundancyEliminationTest = PassTest<::testing::Test>;
31
32 // Remove an instruction when it was already computed.
TEST_F(LocalRedundancyEliminationTest,RemoveRedundantAdd)33 TEST_F(LocalRedundancyEliminationTest, RemoveRedundantAdd) {
34 const std::string text = R"(
35 OpCapability Shader
36 %1 = OpExtInstImport "GLSL.std.450"
37 OpMemoryModel Logical GLSL450
38 OpEntryPoint Fragment %2 "main"
39 OpExecutionMode %2 OriginUpperLeft
40 OpSource GLSL 430
41 %3 = OpTypeVoid
42 %4 = OpTypeFunction %3
43 %5 = OpTypeFloat 32
44 %6 = OpTypePointer Function %5
45 %2 = OpFunction %3 None %4
46 %7 = OpLabel
47 %8 = OpVariable %6 Function
48 %9 = OpLoad %5 %8
49 %10 = OpFAdd %5 %9 %9
50 ; CHECK: OpFAdd
51 ; CHECK-NOT: OpFAdd
52 %11 = OpFAdd %5 %9 %9
53 OpReturn
54 OpFunctionEnd
55 )";
56 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
57 }
58
59 // Make sure we keep instruction that are different, but look similar.
TEST_F(LocalRedundancyEliminationTest,KeepDifferentAdd)60 TEST_F(LocalRedundancyEliminationTest, KeepDifferentAdd) {
61 const std::string text = R"(
62 OpCapability Shader
63 %1 = OpExtInstImport "GLSL.std.450"
64 OpMemoryModel Logical GLSL450
65 OpEntryPoint Fragment %2 "main"
66 OpExecutionMode %2 OriginUpperLeft
67 OpSource GLSL 430
68 %3 = OpTypeVoid
69 %4 = OpTypeFunction %3
70 %5 = OpTypeFloat 32
71 %6 = OpTypePointer Function %5
72 %2 = OpFunction %3 None %4
73 %7 = OpLabel
74 %8 = OpVariable %6 Function
75 %9 = OpLoad %5 %8
76 %10 = OpFAdd %5 %9 %9
77 ; CHECK: OpFAdd
78 OpStore %8 %10
79 %11 = OpLoad %5 %8
80 ; CHECK: %11 = OpLoad
81 %12 = OpFAdd %5 %11 %11
82 ; CHECK: OpFAdd [[:%\w+]] %11 %11
83 OpReturn
84 OpFunctionEnd
85 )";
86 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
87 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
88 }
89
90 // This test is check that the values are being propagated properly, and that
91 // we are able to identify sequences of instruction that are not needed.
TEST_F(LocalRedundancyEliminationTest,RemoveMultipleInstructions)92 TEST_F(LocalRedundancyEliminationTest, RemoveMultipleInstructions) {
93 const std::string text = R"(
94 OpCapability Shader
95 %1 = OpExtInstImport "GLSL.std.450"
96 OpMemoryModel Logical GLSL450
97 OpEntryPoint Fragment %2 "main"
98 OpExecutionMode %2 OriginUpperLeft
99 OpSource GLSL 430
100 %3 = OpTypeVoid
101 %4 = OpTypeFunction %3
102 %5 = OpTypeFloat 32
103 %6 = OpTypePointer Uniform %5
104 %8 = OpVariable %6 Uniform
105 %2 = OpFunction %3 None %4
106 %7 = OpLabel
107 ; CHECK: [[r1:%\w+]] = OpLoad
108 %9 = OpLoad %5 %8
109 ; CHECK-NEXT: [[r2:%\w+]] = OpFAdd [[:%\w+]] [[r1]] [[r1]]
110 %10 = OpFAdd %5 %9 %9
111 ; CHECK-NEXT: [[r3:%\w+]] = OpFMul [[:%\w+]] [[r2]] [[r1]]
112 %11 = OpFMul %5 %10 %9
113 ; CHECK-NOT: OpLoad
114 %12 = OpLoad %5 %8
115 ; CHECK-NOT: OpFAdd [[:\w+]] %12 %12
116 %13 = OpFAdd %5 %12 %12
117 ; CHECK-NOT: OpFMul
118 %14 = OpFMul %5 %13 %12
119 ; CHECK-NEXT: [[:%\w+]] = OpFAdd [[:%\w+]] [[r3]] [[r3]]
120 %15 = OpFAdd %5 %14 %11
121 OpReturn
122 OpFunctionEnd
123 )";
124 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
125 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
126 }
127
128 // Redundant instructions in different blocks should be kept.
TEST_F(LocalRedundancyEliminationTest,KeepInstructionsInDifferentBlocks)129 TEST_F(LocalRedundancyEliminationTest, KeepInstructionsInDifferentBlocks) {
130 const std::string text = R"(
131 OpCapability Shader
132 %1 = OpExtInstImport "GLSL.std.450"
133 OpMemoryModel Logical GLSL450
134 OpEntryPoint Fragment %2 "main"
135 OpExecutionMode %2 OriginUpperLeft
136 OpSource GLSL 430
137 %3 = OpTypeVoid
138 %4 = OpTypeFunction %3
139 %5 = OpTypeFloat 32
140 %6 = OpTypePointer Function %5
141 %2 = OpFunction %3 None %4
142 %bb1 = OpLabel
143 %8 = OpVariable %6 Function
144 %9 = OpLoad %5 %8
145 %10 = OpFAdd %5 %9 %9
146 ; CHECK: OpFAdd
147 OpBranch %bb2
148 %bb2 = OpLabel
149 ; CHECK: OpFAdd
150 %11 = OpFAdd %5 %9 %9
151 OpReturn
152 OpFunctionEnd
153 )";
154 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
155 }
156
TEST_F(LocalRedundancyEliminationTest,StorageBufferIdentification)157 TEST_F(LocalRedundancyEliminationTest, StorageBufferIdentification) {
158 const std::string text = R"(
159 ; CHECK: [[gep:%\w+]] = OpAccessChain
160 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[gep]]
161 ; CHECK: [[add:%\w+]] = OpIAdd {{%\w+}} [[ld]]
162 ; CHECK: OpStore [[gep]] [[add]]
163 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[gep]]
164 ; CHECK: [[add:%\w+]] = OpIAdd {{%\w+}} [[ld]]
165 ; CHECK: OpStore [[gep]] [[add]]
166
167 OpCapability Shader
168 OpCapability Linkage
169 OpMemoryModel Logical GLSL450
170 OpDecorate %block BufferBlock
171 OpMemberDecorate %block 0 Offset 0
172 %void = OpTypeVoid
173 %int = OpTypeInt 32 0
174 %int_0 = OpConstant %int 0
175 %int_1 = OpConstant %int 1
176 %block = OpTypeStruct %int
177 %array = OpTypeArray %block %int_1
178 %ptr_ssbo_array = OpTypePointer Uniform %array
179 %ptr_ssbo_int = OpTypePointer Uniform %int
180 %var = OpVariable %ptr_ssbo_array Uniform
181 %void_fn = OpTypeFunction %void
182 %fn = OpFunction %void None %void_fn
183 %entry = OpLabel
184 %gep1 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
185 %ld1 = OpLoad %int %gep1
186 %add1 = OpIAdd %int %ld1 %int_1
187 %gep2 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
188 OpStore %gep2 %add1
189 %gep3 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
190 %ld3 = OpLoad %int %gep3
191 %add3 = OpIAdd %int %ld3 %int_1
192 %gep4 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
193 OpStore %gep4 %add3
194 OpReturn
195 OpFunctionEnd
196 )";
197
198 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, true);
199 }
200
201 } // namespace
202 } // namespace opt
203 } // namespace spvtools
204